Skip to content

Repository files navigation

NakedMoleRat

NakedMoleRat is a lightweight CLI utility designed to safely bridge the gap between digital secrets and physical paper. Standard text backups are vulnerable to optical lookalike errors (O vs 0), ink bleed, and physical degradation.

NakedMoleRat solves this using a strict three-layer pipeline:

  1. Storage — data is encrypted with AES-256-GCM, the key derived from your password with PBKDF2-HMAC-SHA256 (600k iterations, random salt).
  2. Resilience — ciphertext is wrapped in Reed-Solomon error-correcting codes (80 parity bytes per 255-byte codeword) to survive ~15% physical paper degradation or scanner artifacts — more where damage is flagged as erasures.
  3. Transport — the payload is encoded with a deterministically shuffled, homoglyph-free Base58 alphabet (shuffled via HKDF-SHA256 from your seed string). Each byte becomes exactly two characters, so one damaged character damages only one byte. A per-byte rotation offset, drawn from a seed-keyed SHA-256 stream, spins both characters through the dictionary so the printed page shows no repeating byte-boundary pattern.
  4. Paper layout — 12 groups of 5 characters per line (75 printed columns), each line prefixed with its line number. The decoder reassembles the stream by line label, so a line the scanner skips or tears becomes a run of erasures at a known offset — which Reed-Solomon corrects at twice the efficiency of ordinary errors. Duplicate or wrong-length lines are likewise erased rather than misaligning the stream.

Usage

pip install .

nakedmolerat encode -i secret.key -o backup.txt -p "correct horse" -s "my-seed"
# print backup.txt, store it somewhere safe

# later, after OCR-scanning the printout back to scan.txt:
nakedmolerat decode -i scan.txt -o recovered.key -p "correct horse" -s "my-seed"

# or skip the external OCR step entirely and decode straight from a photo
# (requires the tesseract binary: brew install tesseract)
nakedmolerat scan -i photo.jpg -o recovered.key -p "correct horse" -s "my-seed"

The scan command grayscales the image, applies a Gaussian adaptive threshold to erase shadows and uneven lighting, then runs Tesseract locked to our exact character set (--psm 6 plus a whitelist) so it can never hallucinate punctuation or homoglyphs. The OCR text then flows through the same label-aware reassembly as decode, so dropped lines in a bad photo are recovered as erasures.

You need both the password and the seed to recover the data. Omit -p to be prompted securely instead of putting the password in shell history.

See OPSEC.md for step-by-step deployment playbooks — estate continuity with a lawyer and safe deposit box, cold-wallet seed storage, and password-manager emergency kits — plus printing hygiene and the three-artifact distribution rule.

Printing tips

  • Use a monospaced font (Courier New, Consolas, Roboto Mono) at 12pt or larger. Proportional fonts cram characters together and ink bleed will quickly eat through the error-correction budget.
  • Disable justification and automatic line wrapping; every backup line is at most 80 columns wide on purpose.
  • Laser printers beat inkjets for archival life; plain high-quality paper beats glossy for OCR contrast.
  • Keep the # header lines: they record the exact character count, which lets the decoder recover even when the last line of the scan is lost.

Web app

web/ contains a single-page Svelte app implementing the exact same pipeline fully client-side — WebCrypto for AES-256-GCM/PBKDF2/HKDF and a byte-compatible JavaScript port of the Reed-Solomon and seeded-Base58 layers. Backups made by the CLI decode in the browser and vice versa (proven by an interop test against a Python-generated fixture). No data ever leaves the page, so it can be hosted statically; pushes to main deploy it to GitHub Pages via .github/workflows/pages.yml.

cd web
npm install
npm run dev    # local dev server
npm test       # vitest suite incl. Python-interop fixtures

Docker

Everything is wrapped in a multi-stage Dockerfile with two targets, wired together by docker-compose.yml:

# self-host the web app at http://localhost:8080
docker compose up -d web

# run the CLI against files in the current directory
# (tesseract is baked in, so `scan` works out of the box)
docker compose run --rm cli encode -i secret.txt -o paper.txt -s my-seed
docker compose run --rm cli scan -i photo.jpg -o recovered.bin -s my-seed

Omit -p to be prompted for the password inside the container instead of leaving it in shell history.

Development

pip install -e '.[dev]'
pytest

About

A resilient, OCR-friendly CLI tool for offline paper backups using AES-256-GCM, Reed-Solomon error correction, and a seeded Base58 transport layer.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages