Skip to main content

Module sanctuary_vault

Module sanctuary_vault 

Source
Expand description

Encrypted-at-rest Sanctuary store with an independent decoy lane (master plan §6).

Unlike the projection filter in super::sanctuary (which merely hides journal rows on read), this is a real boundary: sensitive notes live only inside AEAD-encrypted lanes, keyed by material derived from the owner’s PIN with Argon2id (memory-hard; ADR D1) — or PBKDF2-HMAC-SHA256 for a PBKDF2-configured vault — over a per-lane random salt. When the vault is not unlocked there is nothing readable on disk — not a filtered view, actual ciphertext.

The on-disk format is the CBOR-native, n-layer VaultContainerV2 (vault v2, ADR §2/§9). There is no JSON path anywhere in this module: the container and the per-lane records are both ciborium-encoded. The container carries a constant number of layer slots (padded with reserved layers) so the on-disk layer count reveals nothing about how many lanes are real / decoy / empty.

Two independent lanes are in use:

  • Real — the true Sanctuary, opened by the real PIN.
  • Decoy — a separate encrypted lane with its own salt/key, opened by the duress PIN. It never aliases real data (different key, different ciphertext) and a duress unlock only ever touches the decoy lane.

The PIN is never stored, not even hashed. A per-lane verifier (a fixed magic string encrypted under the lane key) is used to recognise which lane a PIN belongs to. There is no destructive “nuke PIN” (plan §6).

Native-only: qualia_core_db::crypto::sanctuary_crypto is not(wasm32); the desktop is the authoritative node that owns keys and the vault.

Structs§

DecoyActionView
One decrypted decoy action surfaced to the real lane.
DecoyActivityReport
The result of reviewing the decoy audit log from the real lane.
SanctuaryVaultNote
A sensitive note held only inside the encrypted vault.

Enums§

AuditIntegrity
The integrity verdict of the decoy audit log at review time.
SanctuaryLane
Which lane a PIN opened.

Constants§

SANCTUARY_VAULT_FILE
On-disk vault file. CBOR, not JSON (vault v2).

Functions§

add_note
Append a note to the lane the PIN opens (real PIN → real lane; duress PIN → decoy only).
add_note_in_session
As add_note, but a decoy write is attributed to session_ref — a fresh ref per duress unlock yields the git-like per-session branch (ADR §10). Ignored for real-lane writes (real activity is never audited).
get_retention_mode
Read the decoy-audit retention policy (real-lane setting). Requires the real PIN; defaults to RetentionMode::AutoArchive when never set.
is_configured
Is the encrypted vault configured on disk?
is_keychain_wrapped
Is the on-disk vault keychain-wrapped (T1.2)?
list_notes
Read the notes held in the lane the PIN opens. Nothing is readable without a valid PIN.
real_curate_decoy_add_note
Real-session decoy curation (ADR §3.2). From a real unlock, write a note into the decoy lane without the decoy PIN — the real lane unwraps the decoy key from its one-way hierarchy. This is how the victim keeps the decoy lived-in and plausible so a coercer’s re-unlock shows believable content. Requires the real PIN; supplying the decoy PIN is rejected (the decoy cannot curate itself, and must not be able to detect that curation exists).
resolve_lane
Resolve which lane a PIN opens (or an error if it opens neither).
review_decoy_activity
Review decoy activity from the real lane (ADR §3.1 / §10). Opens the real lane, unwraps the audit secret, decrypts every sealed decoy-session record, verifies chain integrity, and checks each previously-witnessed prefix against its head anchor (detecting forensic truncation/replace). Then advances the anchors for clean branches and persists them inside the real lane’s encrypted records. Requires the real PIN; the decoy PIN is rejected.
set_retention_mode
Set the decoy-audit retention policy (ADR §8). Real-session only — the setting is stored in the real lane’s encrypted records so it is invisible and unreachable from a decoy session (which must never learn that auditing exists). Requires the real PIN.
setup
Create the two encrypted lanes with the production Argon2id KDF (memory-hard; ADR D1). Fails if a PIN is too weak, the PINs are equal, or the vault already exists.
setup_wrapped
Opt-in (off by default). Create the two encrypted lanes with an OS-keychain-held pepper mixed into the KDF, so disk + PIN alone cannot open the vault. Returns the pepper as a hex recovery code: the caller MUST have the user record it out-of-band — if the keychain entry is later lost (reinstall / new machine), this code is the only way back in (see unlock_with_recovery).
unlock_with_recovery
Recover access to a keychain-wrapped vault whose keychain entry is missing (new device, OS reinstall) by supplying the hex recovery code from setup_wrapped. On success the pepper is re-stored into this device’s keychain so subsequent unlocks are seamless again.