A vault is encrypted with a random data key, and that key is wrapped by your passphrase. This is the one thing you must not lose carelessly — and the one thing no one (not even the project) can recover for you.
The hard truth, stated plainly: if you lose your passphrase and have no recovery backup and no synced peer who still has the case, the data is gone. That is by design — it is the same property that means a landlord, a breach, or a subpoena can't get it either. So make a recovery backup now.
Re-wraps the same data key under a new passphrase; your evidence is not re-encrypted, so it's instant.
$ uv run habitable key rotate --vault ./case-4B
# (enter the current passphrase, then choose a new one)After rotating, update any recovery backups — an old backup still opens with its own recovery passphrase, which you may want to refresh too.
Exports the data key wrapped under an independent recovery passphrase. Keep the file and its passphrase safe and separate (different place, different passphrase from the everyday one).
$ uv run habitable key backup --vault ./case-4B --out ./case-4B-recovery.txtA good practice for a union: each case has a recovery file held by a second trusted organizer, with a recovery passphrase only they know.
If the keyfile is lost or the passphrase is forgotten, rebuild access from the recovery backup under a new passphrase. (This needs the rest of the vault directory — the encrypted case data — to still be present.)
$ uv run habitable key restore ./case-4B \
--recovery-file ./case-4B-recovery.txt
# (enter the recovery passphrase, then choose a new vault passphrase)
$ uv run habitable status --vault ./case-4B # opens with the new passphraseEvery unlock re-derives a key-encryption key from your passphrase with scrypt,
at a cost (memory + time) that trades off unlock speed against resistance to
offline brute force if the keyfile is ever stolen. The default (standard)
targets an interactive unlock on a low-end phone. If your device can spare the
extra time and memory — or you simply want more headroom as hardware gets
faster — bump the cost with key harden:
$ uv run habitable key harden --vault ./case-4B
# (enter the current passphrase; the keyfile is re-wrapped at the "hardened" profile)Like rotation, this only rewrites the small keyfile — the bulk evidence is never
touched — but every future unlock pays the new cost, so expect habitable status/app/etc. to take noticeably longer to open the vault afterward. Three
profiles are available (--profile standard|hardened|paranoid); see
crypto-spec.md for the concrete scrypt
parameters and a bump procedure. Hardening does not change the data key or the
passphrase — it is orthogonal to both rotation (above) and DEK rotation (below).
Passphrase rotation (above) re-wraps the same data key — it does nothing for a suspected leak of the key itself (e.g. a device believed compromised, or a bug that may have exposed decrypted blobs). For that, rotate the data key:
$ uv run habitable key rotate-dek --vault ./case-4B
# (enter the current passphrase; a NEW data key replaces the old one)This is the expensive operation the others deliberately avoid: every encrypted vault blob and every sealed original is decrypted, its fixity re-verified, and re-encrypted under the fresh key. It is bounded by the size of the case (not instant like rotation/hardening) but is meant to be rare — a deliberate incident response, not routine hygiene. The passphrase does not change; only the key it wraps does. Update recovery backups afterward, same as after a passphrase rotation — an old recovery blob still wraps the old data key.
A plain recovery backup is one blob held by one person. Threshold custody
splits recovery across several stewards so that any M of N can recover,
but no single steward can — so no single steward is the honeypot:
$ uv run habitable key share --vault ./case-4B \
--threshold 2 --steward Ana --steward Bo --steward Cy \
--out-dir ./case-4B-custody
# writes recovery-bundle.json + one share file per steward (a 2-of-3 split)Give each share-*.json to its named steward and keep them apart; the
recovery-bundle.json is not secret on its own but is useless without a quorum
of shares. When recovery is needed, bring any M shares together:
$ uv run habitable key recover ./case-4B \
--bundle ./case-4B-custody/recovery-bundle.json \
--share ./from-ana.json --share ./from-cy.json
# (any 2 of the 3 shares, then choose a new vault passphrase)See the key-custody-playbook.md for when to use this
and crypto-spec.md §3a for the construction.
A second organizer's device is itself a kind of backup: sync the case
peer-to-peer (see setup-guide.md), and the evidence survives
the loss of any one device. Each device has its own passphrase and its own
recovery backup.
- The data key is 256-bit; the passphrase wraps it via scrypt + ChaCha20-Poly1305.
- Rotation, hardening, and backup all operate on the small wrapped key, never the bulk data; DEK rotation is the one operation that touches every encrypted file.
- The recovery backup is the same wrapped-key format as the keyfile, protected by
a separate passphrase. Implementation:
crypto.export_recovery_blob/import_recovery_blob, exercised bytests/test_cli_key.py. key harden:crypto.harden_keyfile/Vault.harden_key,crypto.KDF_PROFILES.key rotate-dek:Vault.rotate_dek, exercised bytests/test_vault_capture.pyandtests/test_cli_key.py.