diff --git a/docs/CRYPTO.md b/docs/CRYPTO.md index 6f44769..42f7020 100644 --- a/docs/CRYPTO.md +++ b/docs/CRYPTO.md @@ -72,7 +72,7 @@ vault creation and is interchangeable: | Container | How the 32 bytes are stored | Extract step | |---|---|---| | Reference image (default) | Embedded in JPEG DCT coefficients via QIM steganography | `imgsecret::extract()` | -| Key file (`.relkey`) | base64-encoded in a plain armored text file | `keyfile_decode()` (`crates/relicario-core/src/keyfile.rs` — ) | +| Key file (`.relkey`) | base64-encoded in a plain armored text file | `keyfile_decode()` (`crates/relicario-core/src/keyfile.rs:36`) | | Recovery QR | XChaCha20-Poly1305 envelope keyed by a separate recovery passphrase | Unwrap then read the raw 32 bytes | The Argon2id KDF input — `u64_be(len(passphrase)) || passphrase || u64_be(32) || secret_32_bytes` — is **identical regardless of container**. Master-key derivation is unaffected by the container choice. The diagrams below show the reference-image path; substitute the appropriate extract step for other containers. diff --git a/docs/FORMATS.md b/docs/FORMATS.md index 06525a6..61ff6e4 100644 --- a/docs/FORMATS.md +++ b/docs/FORMATS.md @@ -39,8 +39,7 @@ Every encrypted file — `manifest.enc`, `settings.enc`, `items/.enc`, `atta Parsed via `ParamsFile { kdf: KdfParams }` in `crates/relicario-cli/src/session.rs:117` (`KdfParams` is defined in `crates/relicario-core/src/crypto.rs:157`). `second_factor` is a -top-level sibling of `kdf` on `ParamsFile`, added by Dev-D's key-file work. - +top-level sibling of `kdf` on `ParamsFile` (`ParamsFile.second_factor`, `crates/relicario-cli/src/session.rs:125`; the `SecondFactor` enum is `crates/relicario-core/src/crypto.rs:69`). The `kdf` nesting is intentional — `format_version`, `aead`, and `salt_path` co-exist for forward-compat probing. Do not flatten. Production defaults: `m=65536` (64 MiB), `t=3`, `p=4`. Tests use `m=256, t=1, p=1`. ### `second_factor` field @@ -60,8 +59,7 @@ Exactly two lines, each terminated by a newline (`\n`). The first line is the li - Suggested file extension: `.relkey` - The 32 bytes are the second-factor secret **in the clear** — this file is the "something you have". It is not itself encrypted. See [SECURITY.md](SECURITY.md) for the threat-model implications. -- Source: `crates/relicario-core/src/keyfile.rs` — `keyfile_encode` / `keyfile_decode` - +- Source: `crates/relicario-core/src/keyfile.rs` — `keyfile_encode` (`:28`) / `keyfile_decode` (`:36`) ## `.relicario/salt` diff --git a/docs/SECURITY.md b/docs/SECURITY.md index f4e50f9..714bd7c 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -22,6 +22,8 @@ Both containers hold the second-factor secret **in the clear** — they are the - **Reference image** (`reference.jpg`): the 32-byte secret is embedded in the JPEG DCT coefficients. The file itself is not encrypted. In the browser extension the image bytes are stored as `imageBase64` in `chrome.storage.local` — also in the clear. - **Key file** (`.relkey`): the 32-byte secret is base64-encoded in a plain text file. The file itself is not encrypted. In the browser extension the key-file bytes are stored as `keyfileBase64` in `chrome.storage.local` — also in the clear. +Neither container is ever committed to the vault repository or pushed to the git remote: the reference JPEG / `.relkey` lives only on your devices (a local file you safeguard for the CLI, `chrome.storage.local` for the extension). The server's repository holds only the `.enc` ciphertext, the non-secret salt, and KDF params — never the second factor. + The key file is **not weaker** than the reference image. Both containers are protected by the same invariant: the passphrase is also required, and the server holds only opaque ciphertext sealed under a key derived from both. A stolen second factor without the passphrase yields nothing actionable (256 bits of Argon2id to brute-force). A stolen passphrase without the second factor is equally unactionable. ## Manifest Integrity