Files
LibreLedger/vendor/README.md
T
LibrePortal 2cffc3ab07 Start LibreLedger: an encrypted money ledger that stores only ciphertext
LibreLedger is a single-person money ledger. The browser encrypts
everything (PBKDF2-HMAC-SHA256 with 250k iterations, then AES-256-GCM),
and a small standard-library Python server stores only the resulting
{v, salt, iv, ct} blob. Ledger files from the earlier Money Ledger version
open unchanged.

- On plain http to a LAN or VPN address, where browsers hide Web Crypto,
  the app switches to vendored @noble/hashes and @noble/ciphers 2.2.0 and
  says so on the lock screen. tests/crypto-interop.test.mjs shows both
  paths read each other's files.
- The server hands out only the app's own files, sends a self-only CSP,
  nosniff, frame denial and no-referrer, checks the shape of each blob,
  refuses cross-site writes and writes atomically. It keeps the last 10
  backups plus one per day for 30 days.
- The container runs that server from a digest-pinned python alpine
  image, as an unprivileged user, with its data in /data and a health
  check on /api/health.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 01:17:16 +01:00

78 lines
4.5 KiB
Markdown

# Vendored crypto
LibreLedger encrypts in the browser. Where the page is a secure context
(HTTPS, `http://localhost`) it uses the browser's Web Crypto API. Where it is
not (plain `http://` to a LAN or VPN address), browsers hide `crypto.subtle`,
and `crypto-fallback.js` runs the same PBKDF2-HMAC-SHA256 and AES-256-GCM from
these files instead. They are loaded only in that case, and the server serves
only the files listed in `server.py` (`VENDOR_FILES`).
| Package | Version | Released | Licence | npm tarball integrity |
| --- | --- | --- | --- | --- |
| [@noble/hashes](https://github.com/paulmillr/noble-hashes) | 2.2.0 | 2026-04-11 | MIT | `sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==` |
| [@noble/ciphers](https://github.com/paulmillr/noble-ciphers) | 2.2.0 | 2026-04-11 | MIT | `sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==` |
Both are zero-dependency libraries by Paul Miller. Audit history, from their
READMEs: independent Cure53 audits of @noble/hashes 1.0.0 (Jan 2022) and
@noble/ciphers 1.0.0 (Sep 2024), and a self-audit of exactly 2.2.0 for both
(Apr 2026), which is why 2.2.0 is the version pinned here. The files below are **unmodified**
copies of the compiled ES modules from those tarballs, with each package's
`LICENSE`. Only the modules needed for PBKDF2-SHA256 and AES-GCM are kept.
The tarballs were checked against the integrity values above before
extracting.
## File hashes
`sha256sum`:
```
d079978bb7dac51e88586dd881ea3d7be010624b876d332f395f4a2b934f5fbc noble-ciphers-2.2.0/aes.js
f36671a5487c9c5050efacb58011c37c24c55a889803cb036cf9d9a6347c1e2d noble-ciphers-2.2.0/LICENSE
87a6cdf9cad2cec61229404cc7f8da1214952a76114b8a6342a3e771f1127cd1 noble-ciphers-2.2.0/_polyval.js
cfb9806b3339c79544a48a7026ee3c868cd1f0a1555c5eef4854b7eec43ccb63 noble-ciphers-2.2.0/utils.js
137ed94227806b351a55b09801287a4dba72d2a35d3838730becf641271bc3dd noble-hashes-2.2.0/hmac.js
4f221aee6e072336700c408c68ab3b96a3fc09f6aebe6f48f1bd99e5ef13faec noble-hashes-2.2.0/LICENSE
8227b9b5cabf078a9d7f7317f7a1ace6e46627539aa9364667aec724e1636f14 noble-hashes-2.2.0/_md.js
d61f870b99cf8e67b6df0ae5f582c74177445844d6a92ea51e8060032d05b555 noble-hashes-2.2.0/pbkdf2.js
0fb8e3c3f2c73a890be2524ac5d2542aaed4decff69e561231a86131203b3973 noble-hashes-2.2.0/sha2.js
766b91a693a798f9d3cde97b25db4a6d0cef66b2ca21153d3d42424d37878870 noble-hashes-2.2.0/_u64.js
e2adfc13c846487feff0410bd5508a1d66f5ebadc3188f3a40a6b55449981e2f noble-hashes-2.2.0/utils.js
```
Subresource-integrity form (`sha384`):
```
sha384-0YHayko0KfpRNxkCNkZTuDkZIofvvDbgY4URpQALCIVKUglJYgnGQ4qGfXFFzXe8 noble-ciphers-2.2.0/aes.js
sha384-RCB3oUufLSfqmAfe/Csz1PRWhjGYjVj48y1X4s/XpyPQk1Bcd2Pa54pZCBo+u7O1 noble-ciphers-2.2.0/LICENSE
sha384-IHfhTh3OeAiHoY7cB8F9YUBJ9rn6RieetfuNQZY75cIgd5UcjVqOCh6ssn0gIGed noble-ciphers-2.2.0/_polyval.js
sha384-VZAiMxOScRfdOr1e2+N5h6GRH5I1mBeWGL1BSjmYLB9VuR/ODNHxvqbMzPIvwwXV noble-ciphers-2.2.0/utils.js
sha384-jjTbQ/7iXpfi7CA4vLI8VW2ljCxeMnfWE6FYpgMrpYgpT+IKKDJLplkP3KlaqLXp noble-hashes-2.2.0/hmac.js
sha384-a19tauEwIs1iP+2eFZxRsChHXNFBtRprDPX8zuYyn/tuG+DeZzAzH1Fv/gHlGrk7 noble-hashes-2.2.0/LICENSE
sha384-cQrKviUiqTLrOSU3x5KyKb6vIptltNRJQbJGyyXy0+QCUUpOHRwOLM0JuIE//YJB noble-hashes-2.2.0/_md.js
sha384-z3+NFrFNV0hs4V5jqy3EAGPvJQAi902QeBkbt5se8GRLG02Vbdz12785sBD3H/mx noble-hashes-2.2.0/pbkdf2.js
sha384-lVYA2l9kQw+NU1uh5QaTLMkTJaFpmFJuIohWWtXdZ5Ri+AdJ+gG7dWCnv0VpvBYt noble-hashes-2.2.0/sha2.js
sha384-j/S9oLRxzt1W++wUX4Lid0ZXyDVraPlN3I5Olt/q+FBuApzg+Tk6GAjTioMmzu0G noble-hashes-2.2.0/_u64.js
sha384-eVOwgoKAAt0Ur0m4yWkKHg9hlMn4HGGrUW0PlHqEzo7hYCelwnnIejIRYCoUIbbf noble-hashes-2.2.0/utils.js
```
## Checking them yourself
```bash
for p in hashes ciphers; do
curl -sSfO "https://registry.npmjs.org/@noble/$p/-/$p-2.2.0.tgz"
echo "$p sha512-$(openssl dgst -sha512 -binary $p-2.2.0.tgz | base64 -w0)" # compare with the table
mkdir -p "$p" && tar xzf "$p-2.2.0.tgz" -C "$p"
done
for f in noble-hashes-2.2.0/*; do cmp "$f" "hashes/package/${f#*/}"; done
for f in noble-ciphers-2.2.0/*; do cmp "$f" "ciphers/package/${f#*/}"; done
```
## Updating
Pick a release that has been out for a while, verify its tarball integrity
against the npm registry, copy the same files into a new versioned folder,
update the imports in `crypto-fallback.js`, `VENDOR_FILES` in `server.py` and
this file, then run `tests/crypto-interop.test.mjs`. The modules still carry
their `//# sourceMappingURL` comments; the maps are not shipped, so a browser's
developer tools may note a missing map, which is harmless.