Project · Lifebot V2 · ADRs

ADR 0002 — One libsodium everywhere; master-password-derived key

type adrstatus activelifebot · crypto · libsodium · cross-platform

Status

Accepted

Context

The same key must be reproducible on web, iOS, and Android (owner requirement), and the server must not be able to compute it. Device hardware keys don't travel; OAuth tokens are visible to the IdP/server. Multi-stack crypto (WebCrypto + RN modules + Python) risks byte-level divergence, and AES-GCM's 96-bit nonces are unsafe for uncoordinated multi-device writers.

Decision

Master password + per-user salt → Argon2id → master key → unwraps a random data key; payloads use XChaCha20-Poly1305 with an AAD-authenticated header. One library family — libsodium (JS sumo/WASM, PyNaCl, react-native-libsodium later) — injected per platform into a single shared TS implementation (setSodium). Identity (Clerk) and unlock (master password) remain two separate secrets.

Consequences

  • Proven byte-identical: TS-encrypted vectors decrypt in Python (spike, 8/8 checks).
  • 192-bit random nonces make multi-device nonce reuse cryptographically negligible.
  • Forgotten password = data loss unless the user keeps the recovery key; no server bypass exists.
  • Pinned KDF params travel in the vault, enabling per-user upgrades without breaking old envelopes.
Compiled from wiki/projects/lifebot-v2/adr/0002-one-libsodium-master-password-key.md · git is the source of truth