Data & Storage

The client vault

Because the server is blind, the real data — your keys and your plaintext history — lives on your device, inside an encrypted local database. This is the actual vault.

Your device keeps a private notebook (IndexedDB). Every sensitive line in it is written in a locked script, and the key to that script is itself kept in a locker that only your fingerprint or passphrase opens. Lock the app and the locker snaps shut — a reload, or even someone copying the whole notebook, can’t read a word.

The web app stores state in IndexedDB (Dexie). The rule: every sensitive field is AES-256-GCM encrypted (fields suffixed _enc) under a master “data” key. Public keys, random tokens, and local timestamps stay plaintext. Heavy crypto runs in a SharedWorker so key material and the WASM heap stay off the UI thread.

Who holds the master key

  • No app lock (default): the key sits in a special browser vault that even Privex’s own code can’t read out; it’s ready on start-up.
  • No app lock (default): a non-extractable WebCrypto AES-GCM key in idb-keyval — its raw bytes never exist in JS; auto-available on boot.
  • App lock on: the key only exists in memory while unlocked. At rest it’s sealed behind your passphrase and/or your fingerprint. Nothing on disk can be unlocked without you.
  • App lock on: the data key lives in memory only while unlocked; at rest it exists solely as wrap blobs under an Argon2id passphrase key (m=32 MiB, t=3) and/or a WebAuthn-PRF biometric key. Enabling/disabling re-keys every _enc field.
Key custody → encrypted stores
any one factor yields the master key; the master key encrypts everything
unlock factor master key encrypted store
Figure. Local history persists until you explicitly “erase this device.” The only automatic client TTL is per-message: an expired parked outbox blob is dropped, never sent late.

Every local store