Repository navigation
Conversation
The same visible password can arrive as different code points: "é" is U+00E9 (NFC) on most keyboards but "e"+U+0301 (NFD) from some macOS inputs, IMEs and pasted text. TextEncoder turns those into different UTF-8 bytes, so PBKDF2 derived a different key and a file encrypted on one machine failed on another with a misleading "wrong password". Encryption now NFC-normalizes the password in all three implementations (src/lib/crypto.ts, the app's crypto core, the recovery tool). Decryption tries NFC first and, only when the typed string was not already NFC, retries with the exact typed bytes — which is how every pre-existing ciphertext was keyed. Nothing that decrypted before stops decrypting; the only cost is one extra PBKDF2 run for a wrong non-NFC password. Regression suite: - new fixture "nfd-password": produced by the unmodified v3.0.11 crypto.ts with an NFD password, kept as a JSON \u0301 escape so no editor can recompose it; proves the exact-bytes fallback. - fixtures may now carry their own "password". - NFC<->NFD cross checks for crypto.ts, the app core and the recovery file (6 checks that fail against the previous code, pass now). site/index.html, site/ittybitz-recovery.html and SHA256SUMS.txt are the rebuilt artifacts with re-pinned CSP hashes (npm run build).
|
Also available merged with every other review PR, in dependency order and verified together, as #57 — merge that or the individual PRs, not both. |
|
Thank you, Dean, for all the work and support you've put into IttyBitz. This review was thorough and genuinely useful. I'm closing this one without merging. I'm deeply committed to password security, and I'm keeping the core cryptography exactly as it is. I'm also determined to keep the file as small and tight as possible. I love the changes you've contributed, and several of them are already live in v3.0.12: several files at once, the key-file fingerprint, the printable emergency card, refusing empty key files, keyboard tabs and the accessibility fixes, and the CI reproducibility check. They're credited in the release notes. Please keep the suggestions coming! |
Problem
The same visible password can arrive as different Unicode code points.
éis U+00E9 (NFC) on most keyboards, bute+ U+0301 (NFD) from some macOS inputs, IMEs and pasted text.TextEncoderturns those into different UTF-8 bytes:PBKDF2 therefore derives a different key, and a file encrypted on one machine fails on another with the generic "wrong password" message — the user has no way to tell what went wrong. Any password containing an accented or composed character is affected.
Fix
src/lib/crypto.ts,scripts/build/crypto-core.js, and the hand-maintained decrypt core insite/ittybitz-recovery.html).Backward compatibility
I know
crypto.tsis frozen for long-horizon ciphertexts, so this was designed so that nothing that decrypted before stops decrypting:DOMExceptionas before, soapp.js's message mapping is unchanged.Regression suite
nfd-password: a ciphertext produced by the unmodified v3.0.11crypto.tswith an NFD password (Cafe\u0301-…), stored as a JSON\u0301escape so no editor can silently recompose it. It proves the exact-bytes fallback keeps pre-normalization files openable — incrypto.ts, the app core, and the recovery file."password"(falls back to the suite-wide one).crypto.ts, the app core and the recovery file.Verified the checks are not vacuous: with the previous
crypto.ts/crypto-core.js/ recovery core swapped back in, the suite reports exactly those 6 asFAIL(95 passed, 6 failed); with this branch, 101 passed, 0 failed. All 33 historical fixtures (v1.0 → v3.0.11) pass in both configurations.Artifacts
site/index.html,site/ittybitz-recovery.htmlandSHA256SUMS.txtare the rebuilt output ofnpm run buildwith re-pinned CSP hashes. I left the version string and CHANGELOG to you, since I don't know what you'd want to call the release.Note: this touches the built
site/index.html, so it will conflict with #44 if that lands too — whichever merges second just needsnpm run buildre-run.