git_simple_encrypt/crypt/mod.rs
1//! The core of this program. Encrypt/decrypt, compress/decompress files.
2//!
3//! # Module Structure
4//!
5//! | Module | Contents |
6//! |---|---|
7//! | [`header`] | Constants (`MAGIC`, `VERSION`, `SALT_LEN`, …) and [`FileHeader`] |
8//! | [`key`] | Key derivation (Argon2, key splitting, nonce derivation) + key cache |
9//! | [`stream`] | Streaming `Read → Write` encrypt/decrypt primitives |
10//! | [`file`] | File-to-file encrypt/decrypt with atomic writes & metadata preservation |
11//! | [`batch`] | Parallel batch operations with shared key cache |
12//! | [`repo`] | Repository-level encrypt/decrypt with salt cache integration |
13//!
14//! See the module-level docs of each submodule for details.
15//!
16//! # Nonce Derivation (Content-Based with File ID)
17//!
18//! Per-chunk nonces are derived from the file's random `File_ID` and the
19//! chunk's own plaintext content using keyed Blake3:
20//!
21//! 1. A random 16-byte `File_ID` is generated once per file and stored in the
22//! header. This ensures that even if two different files have identical
23//! plaintext at chunk 0, they produce different nonces and ciphertexts.
24//! 2. The Argon2-derived master key is split via `blake3::derive_key` into
25//! `Key_ENC` (for XChaCha20-Poly1305 encryption) and `Key_MAC` (for nonce
26//! generation).
27//! 3. For each chunk `i`: `Nonce_i = Blake3_keyed(Key_MAC, File_ID || M_i ||
28//! chunk_idx_le)[0..24]`
29//! 4. The 24-byte nonce is stored in plaintext at the head of each encrypted
30//! chunk.
31//!
32//! Different plaintext always produces a different nonce (within the same
33//! file). The `File_ID` ensures cross-file uniqueness. The chunk index prevents
34//! reordering attacks on identical 64 KB blocks.
35//!
36//! # Authenticated Additional Data (AAD)
37//!
38//! Each chunk's AAD binds the ciphertext to the full file header so that any
39//! tampering with header fields (version, compression flag, salt, `file_id`,
40//! reserved) is detected via Poly1305 authentication failure:
41//!
42//! ```text
43//! AAD = HEADER (64B) || chunk_idx (8B LE) || is_last_chunk (1B) // 73 bytes
44//! ```
45//!
46//! Each encrypted chunk layout: `[NONCE (24B)] [CIPHERTEXT] [TAG (16B)]`
47
48mod batch;
49mod file;
50mod header;
51mod key;
52mod repo;
53mod stream;
54
55pub use batch::BatchSummary;
56pub use file::{
57 decrypt_file, decrypt_file_to, decrypt_file_with_cache, encrypt_file, encrypt_file_to,
58};
59pub use header::{
60 FILE_ID_LEN, FileHeader, HEADER_LEN, MAGIC, NONCE_LEN, SALT_LEN, VERSION, is_encrypted_version,
61};
62pub use key::derive_key;
63pub use repo::{cache_key, decrypt_repo, encrypt_repo};
64pub use stream::{decrypt_into, encrypt_into};
65
66#[cfg(test)]
67mod tests;