Fordan .sec File Format
Version: 1 | Status: Normative
Overview
A .sec file is a streaming, authenticated-encryption container for a single plaintext file. Files are split into fixed-size chunks; each chunk is independently encrypted and authenticated. The design allows both encryption and decryption to proceed with O(chunk) RAM regardless of the total file size, and makes truncation, chunk reordering, and bit-flips detectable rather than silently tolerated.
Magic Bytes and File Identity
Every .sec file begins with an 8-byte MAGIC sequence:
46 4F 52 44 41 4E 01 00 (ASCII "FORDAN" + 0x01 0x00)
A reader that does not see this exact MAGIC at offset 0 must reject the file immediately with an error.
Header Layout
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 8 | MAGIC | FORDAN\x01\x00 — format identity guard |
| 8 | 2 | VERSION | u16 little-endian; current value is 1 |
| 10 | 1 | AEAD_ID | 0x01 = XChaCha20-Poly1305 (default), 0x02 = AES-256-GCM |
| 11 | 1 | KDF_ID | 0x01 = Argon2id |
| 12 | 4 | CHUNK_SIZE | u32 little-endian; plaintext bytes per chunk (default 65536) |
| 16 | 4 | TOTAL_CHUNKS | u32 little-endian; total number of chunks |
| 20 | 8 | PLAINTEXT_LEN | u64 little-endian; exact original file size |
| 28 | 4 | ARGON2_T | u32 little-endian; Argon2 time cost |
| 32 | 4 | ARGON2_M | u32 little-endian; Argon2 memory cost (KiB) |
| 36 | 4 | ARGON2_P | u32 little-endian; Argon2 parallelism |
| 40 | 32 | SALT | Random 32-byte KDF salt (generated with getrandom) |
| 72 | 32 | HEADER_BLAKE3 | BLAKE3 hash of bytes 0..72 (integrity self-check) |
Total header size: 104 bytes.
AEAD Algorithms
0x01 — XChaCha20-Poly1305 (default)
- Implemented via the
chacha20poly1305RustCrypto crate. - 24-byte nonce (192 bits).
- 16-byte Poly1305 auth tag appended to each ciphertext chunk.
- Preferred for all new vaults; hardware acceleration not required.
0x02 — AES-256-GCM
- Implemented via the
aes-gcmRustCrypto crate. - 12-byte nonce (96 bits).
- 16-byte GCM auth tag appended to each ciphertext chunk.
- Available for interoperability with hardware AES-NI environments.
Key Derivation
The vault key is derived with Argon2id (argon2 crate) from:
- A user-supplied passphrase (UTF-8, not stored in the file).
- The 32-byte SALT from the header.
- KDF parameters from the header (ARGON2_T, ARGON2_M, ARGON2_P).
Recommended defaults: t=3, m=65536, p=4.
Chunk Body
[ nonce (N bytes) | ciphertext (CHUNK_SIZE or less) | auth tag (16 bytes) ]
Where N = 24 for XChaCha20-Poly1305, N = 12 for AES-256-GCM.
Nonce Construction
nonce[i] = first_N_bytes( BLAKE3( key || chunk_index_as_u64_le ) )
Associated Data
AD[i] = MAGIC || VERSION_u16_le || chunk_index_u32_le || TOTAL_CHUNKS_u32_le
Binding to TOTAL_CHUNKS means a truncated file (missing trailing chunks) will cause the last surviving chunk's AD to fail authentication.
Threat Model and Error Detection
Truncation
A truncated file produces fewer chunks than TOTAL_CHUNKS. The reader counts successfully decrypted chunks and compares to TOTAL_CHUNKS; a shortfall is reported as truncation, not as a valid partial file.
Chunk Reordering
Because each chunk's nonce and AD embed the chunk index and TOTAL_CHUNKS, a reordered chunk will fail AEAD authentication at the position where it is presented.
Bit-Flips and Corruption
Any single-bit change to a chunk's ciphertext or auth tag causes the AEAD decryption to return an authentication failure for that chunk. Fordan treats any auth tag mismatch as a fatal error.
Streaming Decrypt
A compliant decoder:
- Reads exactly 104 header bytes; validates MAGIC, VERSION, and HEADER_BLAKE3.
- Derives the key from the passphrase and SALT.
- For
iin0..TOTAL_CHUNKS:- Reads
nonce_len + chunk_ciphertext_len + 16bytes from the stream. - Reconstructs the nonce from the key and chunk index.
- Decrypts and authenticates the chunk; aborts on auth tag failure.
- Writes the plaintext bytes to the output stream.
- Reads
- Asserts that the total plaintext bytes written equals PLAINTEXT_LEN.
No seek is required. The decoder allocates one chunk buffer and reuses it for every chunk. Files of arbitrary size are processed with bounded RAM.
Partial Recovery
Fordan does not support partial recovery by design: a vault that cannot be fully verified is treated as corrupt. There is no --skip-bad-chunks flag.
Format Version History
| VERSION | Change |
|---|---|
| 1 | Initial format. XChaCha20-Poly1305 default; AES-256-GCM alternative. |