Crypto whitepaper
How your journal is encrypted.
This page describes the scheme Graphophone actually ships — not a marketing summary. Every primitive is standard, peer-reviewed, and implemented with audited RustCrypto crates, the open-source libraries most Rust cryptography is built on.
Last updated: 2026-10-14.
Building blocks
Primitives
-
Passphrase hardening
Argon2id (64 MiB memory, 3 iterations, 4 lanes), 16-byte CSPRNG salt. The parameters are stored beside the salt, so future versions can raise them without breaking existing vaults. -
Authenticated encryption
XChaCha20-Poly1305 with random 24-byte nonces — large enough that random nonces carry no reuse risk — and 16-byte authentication tags. Tampered ciphertext is rejected, never silently decrypted. -
Subkey derivation
HKDF-SHA256 with domain-separated labels (aj/v1/entry-key,aj/v1/blob-key,aj/v1/sync-key, …), so a compromise of one purpose-key never exposes another. -
Randomness
The operating system CSPRNG (OsRngviagetrandom). -
Secret hygiene
Every secret type zeroizes its memory on drop (zeroize) and implements neitherDebugnorDisplay, so keys can't leak into logs by accident.
From passphrase to purpose keys
The key hierarchy
Your passphrase never encrypts anything directly. It derives a key-encryption key that wraps a random per-vault master key; purpose keys are derived from the master key:
-
passphrase - Argon2id + salt
-
KEK (32 B) - XChaCha20-Poly1305 unwrap
-
master_key (32 B, random per vault) - HKDF
-
-
HKDF "aj/v1/entry-key"entry titles, bodies, tags
-
HKDF "aj/v1/blob-key"attachments
-
HKDF "aj/v1/sync-key"seals folder-sync files
-
Because the passphrase only wraps the master key, changing your passphrase re-wraps one 32-byte key — it never re-encrypts your entries. The recovery code (256 bits, shown once as dashed hexadecimal) is a second, independent wrap of the same master key: either credential opens the vault, and rotating the recovery code invalidates the old one without touching your data.
Sealed one by one
Per-entry encryption
Every entry's title, body, and tags are sealed individually with XChaCha20-Poly1305 before they touch the database. The associated data binds each ciphertext to its entry id and schema version, so a ciphertext can't be silently swapped between entries. Attachments are encrypted the same way under their own subkey and addressed by the BLAKE3 hash of the ciphertext, which de-duplicates identical files without revealing their content.
When things go wrong
Backups, decoy, panic wipe
-
Encrypted backups
Encrypted backups (.ajbackup) are sealed under their own passphrase with the same AEAD, with a versioned header and tamper detection — portable to a new device without weakening the vault's own credentials. -
Decoy vault
A separate passphrase (with its own recovery code) opens a separate, benign vault through the same unlock field, with no observable difference in behavior — plausible deniability of content under coercion. -
Panic wipe
Panic wipe destroys the vault headers first — a crypto-erase that renders all ciphertext permanently undecryptable even if file deletion is interrupted — then removes data best-effort and clears in-memory secrets.
The trade-offs
What 1.0 does not encrypt
Honesty over gloss: the database file is now whole-encrypted with SQLCipher, layered over the per-entry sealing — so timestamps, ciphertext sizes and entry counts are no longer readable from it. What someone holding the app's folder can still observe is size, because encryption hides contents and not lengths. The database file's own size tells them roughly how much you have written, and each attachment is a separate encrypted file, so their number and individual sizes can be counted from a directory listing. And anything you have explicitly exported is written in the clear on purpose — an export you cannot read is not an export. The full accounting of what an attacker with the file can and cannot learn is part of our internal threat model, summarised on the security page.
Review status
The scheme has been through repeated internal adversarial review, but it has not yet had an independent external audit — commissioning one and publishing the report is on the roadmap before cloud features ship. If you find a weakness, see our security page for the disclosure process.
See also: security overview · privacy policy · third-party licenses.