Skip to content

LockHTML v2.0.0

Choose a tag to compare

@drsamonline drsamonline released this 20 Oct 16:06
· 19 commits to main since this release

LockHTML v2.0.0

A hidden volume, a KDF that tunes itself to the machine, and launcher scripts that just run.

Highlights

  • 🕳️ Hidden volume — a locked file can carry a second (or third…) payload behind its own PIN. The cover PIN opens the cover document; the hidden PIN opens entirely different bytes. The same idea as the duress PIN, generalised.
  • 🎛️ Auto-calibrated KDF — lockhtml calibrate times one Argon2id pass on this machine and picks the strongest time cost that still unlocks in about half a second. --auto-kdf stores those parameters in the file, so it always opens at the cost it was made with.
  • 🎭 Streaming decoy — the duress PIN now works on streaming containers: it renders a small embedded page instead of ever decrypting the sidecar (whose MAC covers that page, so swapping it is detected).
  • 🐢 Constant-memory save — the viewer can decrypt a streaming container straight to disk, chunk by chunk, via the File System Access API (Chromium). Other browsers keep the Blob download.
  • 📁 Folders — lock --recursive DIR on the CLI, and a folder picker plus directory drag-and-drop in the GUI.
  • 🚀 Launcher scripts — lockhtml.sh / lockhtml.bat and gui.sh / gui.bat run the CLI straight from a checkout, find Python 3.9+, prefer a local .venv, and tell you exactly what is missing.
  • 📦 PyPI-ready — a trusted-publishing publish.yml workflow is included.

Usage

./lockhtml.sh calibrate                                  # what can this machine afford?
./lockhtml.sh lock cover.html --pin 4821 --hidden-pin 0000 --hidden-file real.html --auto-kdf
./lockhtml.sh unlock cover.locked.html --pin 0000         # the hidden content
./lockhtml.sh lock ./contracts --recursive --pin 4821 --outdir ./locked

Live GUI

👉 https://drsamonline.github.io/lockhtml/

Verification

86 unit tests, a 35-check headless-Chrome run covering embedded, streaming, recipient, shares, hidden-volume and streaming-decoy paths, and 9 cross-implementation checks where the browser locks files the Python core then opens. All of it runs in CI.

What is not in this release, and why

  • age interop is deferred. It is a separate file format with its own chunked-ChaCha20-Poly1305 STREAM construction; cryptography's ChaCha20-Poly1305 has no Web Crypto equivalent, so it would be CLI-only, and it needs validating against the official age test vectors before it can be trusted. Shipping unverified crypto interop would be worse than not shipping it — it stays the top roadmap item.
  • PyPI publication needs one thing on your side: a trusted publisher configured for this repo. The workflow is ready; the account access is not something CI has.

Security note

A hidden volume is plausible deniability, not proof of absence — the extra slots are visible in the file's JSON to anyone who looks, they simply cannot be read without their PIN. See SECURITY.md and the self-audit in docs/AUDIT.md.