phase 9 chat save 3 — client crypto + Chat island (v1.56.82): lib/crypto.ts E2E construction (Web Crypto, no new deps) — per-device ECDH P-256 keypair, private key NON-extractable in IndexedDB; key agreement ECDH→deriveBits(256)→HKDF-SHA256→AES-GCM-256 (HKDF hardens the raw shared secret beyond the spec's bare-ECDH draft); AES-256-GCM with fresh 96-bit IV per blob; one ciphertext blob per recipient; fingerprint=base64(SHA-256(pubkey)) matching the server. Chat.tsx island: global room + DMs (server-resolved canonical rooms), SSE live stream, history decrypt, encrypt-per-recipient send, self-fingerprint shown for out-of-band verification, no-key members disabled. ACCEPTED TRADEOFFS (flagged for dual crypto review, no answer to my stop-and-ask → recommended defaults): no forward secrecy (static keys; key loss = clean start) and server-mediated key distribution (MITM mitigated only by out-of-band fingerprint compare). VERIFIED in real headless browser against the real crypto.ts: A→B encrypt/decrypt round-trip, ciphertext≠plaintext, sender/non-recipient/tampered all fail, self round-trip, fingerprint stable (8/8); Chat island mounts, registers key, send POST body is ciphertext (plaintext absent). DB-layer privacy boundary verified against real Postgres in save 2

dev · 16 hours ago · 2026-06-16 · 14.4 MB

session: admin rebuild · agent: claude-code

$ koh steal kepr.uk/kepr@ca0d030d820f
·
← c75890f0a9b3 ee3342b00267 →
⇓ download .face