// LibreLedger — pure-JS crypto for pages without Web Crypto. // // Browsers only expose crypto.subtle in a secure context (HTTPS or localhost). // Opened as plain http://:, the app loads this module // instead. It does exactly what the Web Crypto path does, so the two read and // write the same ledger files: // key = PBKDF2-HMAC-SHA256(UTF-8 passphrase, 16-byte salt, iterations) -> 32 bytes // ct = AES-256-GCM(key, 12-byte iv, plaintext) -> ciphertext || 16-byte tag // The primitives are unmodified copies of @noble/hashes and @noble/ciphers // (audited, zero-dependency); versions and hashes are in vendor/README.md. // // The one real difference: Web Crypto keys are non-extractable, while here the // 32 key bytes live in page memory until the ledger is locked. Use HTTPS where // you can. import { pbkdf2Async } from "./vendor/noble-hashes-2.2.0/pbkdf2.js"; import { sha256 } from "./vendor/noble-hashes-2.2.0/sha2.js"; import { gcm } from "./vendor/noble-ciphers-2.2.0/aes.js"; export async function deriveKeyBytes(passphraseBytes, salt, iterations) { return pbkdf2Async(sha256, passphraseBytes, salt, { c: iterations, dkLen: 32, asyncTick: 25 }); } export function encrypt(keyBytes, iv, plaintext) { return gcm(keyBytes, iv).encrypt(plaintext); } // Throws on a wrong key or tampered data, like crypto.subtle.decrypt does. export function decrypt(keyBytes, iv, ciphertext) { return gcm(keyBytes, iv).decrypt(ciphertext); }