FileVault Architecture & Workflow
Technical documentation for FileVault's internal architecture, data flow, and operational workflows.
Table of Contents
System Architecture
High-Level Overview
| Text Only |
|---|
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLI Layer β
β (Command Parsing, User Interaction, Progress Display) β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ
β Command Layer β
β encrypt_cmd β decrypt_cmd β keygen_cmd β benchmark_cmd β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ
β Core Engine β
β CryptoEngine (Algorithm Registry) β
ββββββββ¬βββββββββββββββ¬βββββββββββββββ¬βββββββββββββββββββββββββ
β β β
ββββββββΌβββββββ βββββββΌβββββββ βββββββΌβββββββββ
β Symmetric β β Asymmetric β β PQC β
β Algorithms β β Algorithms β β Algorithms β
ββββββββ¬βββββββ βββββββ¬βββββββ ββββββ¬ββββββββββ
β β β
ββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββ
β Botan 3.x Library β
β (Cryptographic Primitives, RNG, Key Management) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
Component Responsibilities
| Component | Responsibility |
| CLI Layer | Parse arguments, validate inputs, display progress |
| Command Layer | Implement business logic for each command |
| Core Engine | Algorithm registration, key derivation, streaming |
| Crypto Algorithms | Wrapper classes for Botan primitives |
| File I/O Utils | Memory-mapped I/O, buffered reading/writing |
| Progress Utils | Real-time progress bars, ETA calculation |
Core Components
1. CryptoEngine (core/crypto_engine.cpp)
Purpose: Central registry and factory for all cryptographic operations.
Key Methods:
| C++ |
|---|
| class CryptoEngine {
// Algorithm registration
void register_algorithm(std::unique_ptr<CryptoAlgorithm> algo);
// Algorithm lookup
CryptoAlgorithm* get_algorithm(const std::string& name);
// Key derivation
Result<std::vector<uint8_t>> derive_key(
const std::string& password,
const std::vector<uint8_t>& salt,
const KDFParams& params
);
// File operations
Result<void> encrypt_file(const EncryptParams& params);
Result<void> decrypt_file(const DecryptParams& params);
};
|
Initialization Flow:
1. Create CryptoEngine instance
2. Register all symmetric algorithms (AES, ChaCha20, etc.)
3. Register asymmetric algorithms (RSA, ECC)
4. Register PQC algorithms (Kyber, Dilithium)
5. Set default algorithm (AES-256-GCM)
2. CryptoAlgorithm Interface (core/crypto_algorithm.hpp)
Purpose: Abstract interface for all encryption algorithms.
| C++ |
|---|
| class CryptoAlgorithm {
public:
virtual ~CryptoAlgorithm() = default;
// Metadata
virtual std::string name() const = 0;
virtual std::string description() const = 0;
virtual size_t key_size() const = 0;
virtual size_t iv_size() const = 0;
virtual bool is_aead() const = 0;
// Encryption
virtual Result<std::vector<uint8_t>> encrypt(
const std::vector<uint8_t>& plaintext,
const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv
) = 0;
// Decryption
virtual Result<std::vector<uint8_t>> decrypt(
const std::vector<uint8_t>& ciphertext,
const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv
) = 0;
};
|
Implementations:
- AEAD Ciphers: AES_GCM, ChaCha20Poly1305, Serpent_GCM
- Block Modes: AES_CBC, AES_CTR, AES_XTS
- Asymmetric: RSA, ECCHybrid
- PQC: KyberHybrid, KyberKEM, Dilithium
3. Streaming Engine (core/streaming.cpp)
Purpose: Memory-efficient encryption/decryption for large files.
Key Features:
- Adaptive Chunking: Adjusts chunk size based on available RAM
- Zero-Copy I/O: Memory-mapped files when beneficial
- Progress Tracking: Real-time updates with ETA
- Error Recovery: Atomic operations with rollback
Memory Management:
| C++ |
|---|
| class StreamingEngine {
// Calculate optimal chunk size
size_t calculate_chunk_size() {
size_t available_memory = get_available_memory();
size_t file_size = get_file_size(input_path);
// Use 10% of available RAM, min 1MB, max 64MB
size_t chunk = std::clamp(
available_memory / 10,
1ULL << 20, // 1 MB
64ULL << 20 // 64 MB
);
return chunk;
}
};
|
Processing Flow:
1. Open input file (read mode)
2. Create output file (write mode)
3. Calculate optimal chunk size
4. Initialize progress bar
5. Process chunks:
- Read chunk from input
- Encrypt/decrypt chunk
- Write to output
- Update progress
6. Finalize and verify
Purpose: Standardized format for encrypted files (.fvlt).
Structure:
| Text Only |
|---|
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β File Header β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Magic Number (8 bytes): "FILEVLT\x00" β
β Version (2 bytes): 0x0100 (v1.0) β
β Algorithm ID (2 bytes): Enum value β
β KDF Type (1 byte): Argon2id/PBKDF2/Scrypt β
β Security Level (1 byte): weak/medium/strong β
β Flags (2 bytes): Compression, PQC, etc. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Salt (32 bytes): Random salt for KDF β
β Nonce/IV (12-16 bytes): Algorithm-specific β
β KDF Parameters (variable): Iterations, memory β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Original Filename Length (2 bytes) β
β Original Filename (UTF-8) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Metadata Length (4 bytes) β
β Metadata (JSON): timestamps, compression, etc. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Header MAC (32 bytes): HMAC-SHA256 of header β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Encrypted Payload β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Authentication Tag (16 bytes): For AEAD modes β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
Header Fields:
| Field | Size | Description |
| Magic Number | 8 bytes | "FILEVLT\x00" identifier |
| Version | 2 bytes | Major.Minor (0x0100 = 1.0) |
| Algorithm ID | 2 bytes | Algorithm enum value |
| KDF Type | 1 byte | 0=Argon2id, 1=PBKDF2, 2=Scrypt |
| Security Level | 1 byte | 0=weak, 1=medium, 2=strong, 3=paranoid |
| Flags | 2 bytes | Bit flags for features |
| Salt | 32 bytes | Random salt for key derivation |
| Nonce/IV | 12-16 bytes | Algorithm-specific initialization vector |
| KDF Params | Variable | Iterations, memory cost, parallelism |
| Filename | Variable | UTF-8 encoded original filename |
| Metadata | Variable | JSON encoded metadata |
| Header MAC | 32 bytes | HMAC-SHA256 for header integrity |
Flags Bitfield:
| Text Only |
|---|
| Bit 0: Compression enabled
Bit 1: PQC algorithm used
Bit 2: Asymmetric encryption
Bit 3: Steganography applied
Bit 4-15: Reserved
|
Encryption Workflow
Password-Based Encryption (Symmetric)
| Text Only |
|---|
| βββββββββββββββ
β User Input β
β - File β
β - Password β
β - Algorithm β
ββββββββ¬βββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 1. Generate Random Salt (32 bytes) β
β crypto::random_bytes(32) β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 2. Derive Key from Password β
β Argon2id(password, salt, params) β
β β 256-bit key β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 3. Generate Random Nonce (12 bytes) β
β crypto::random_bytes(12) β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 4. Create File Header β
β - Magic, version, algorithm ID β
β - Salt, nonce, KDF params β
β - Original filename, metadata β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 5. Compute Header MAC β
β HMAC-SHA256(header, key) β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 6. Write Header to Output File β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 7. Encrypt File in Chunks β
β FOR each chunk: β
β - Read plaintext chunk β
β - Encrypt with AES-GCM β
β - Write ciphertext chunk β
β - Update progress bar β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 8. Write Authentication Tag β
β (For AEAD modes like GCM) β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 9. Finalize and Close Files β
β - Sync to disk β
β - Verify output file size β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββ
β Success! β
β .fvlt file β
βββββββββββββββ
|
Public Key Encryption (Asymmetric)
RSA Encryption
| Text Only |
|---|
| 1. Load RSA public key from PEM file
2. Generate random AES-256 key (32 bytes)
3. Encrypt file with AES-256-GCM:
- Derive key and nonce
- Encrypt payload
4. Encrypt AES key with RSA public key:
- RSA-OAEP encryption
- Store encrypted key in header
5. Write header + encrypted payload
|
ECC Hybrid Encryption
| Text Only |
|---|
| 1. Load ECC public key
2. Generate ephemeral ECC keypair
3. Perform ECDH key agreement:
- shared_secret = ECDH(ephemeral_private, recipient_public)
4. Derive AES key from shared secret:
- key = KDF(shared_secret, salt)
5. Encrypt file with AES-256-GCM
6. Include ephemeral public key in header
|
Kyber-Hybrid Encryption (PQC)
| Text Only |
|---|
| 1. Load Kyber-1024 public key
2. Perform KEM encapsulation:
- (ciphertext, shared_secret) = Kyber.Encapsulate(public_key)
3. Derive AES key from shared secret:
- key = HKDF(shared_secret, salt, "FileVault")
4. Encrypt file with AES-256-GCM
5. Store KEM ciphertext in header
6. Provides quantum resistance!
|
Decryption Workflow
Password-Based Decryption
| Text Only |
|---|
| βββββββββββββββ
β User Input β
β - .fvlt β
β - Password β
ββββββββ¬βββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 1. Read and Parse File Header β
β - Verify magic number β
β - Extract algorithm ID, KDF type β
β - Read salt, nonce, params β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 2. Derive Key from Password β
β Use same KDF with stored params: β
β Argon2id(password, salt, params) β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 3. Verify Header MAC β
β Compute HMAC-SHA256(header, key) β
β Compare with stored MAC β
β β If mismatch: Wrong password! β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 4. Initialize Decryption Cipher β
β AES-GCM with derived key + nonce β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 5. Decrypt File in Chunks β
β FOR each chunk: β
β - Read ciphertext chunk β
β - Decrypt with AES-GCM β
β - Write plaintext chunk β
β - Update progress bar β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 6. Verify Authentication Tag β
β (For AEAD modes) β
β β If invalid: File tampered! β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 7. Restore Original Filename β
β Use filename from header β
ββββββββ¬βββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββ
β Success! β
β Decrypted β
β file β
βββββββββββββββ
|
Public Key Decryption
RSA Decryption
| Text Only |
|---|
| 1. Read header and extract encrypted AES key
2. Decrypt AES key with RSA private key:
- plaintext_key = RSA_Decrypt(encrypted_key, private_key)
3. Decrypt file with recovered AES key
4. Verify authentication tag
|
ECC Decryption
| Text Only |
|---|
| 1. Extract ephemeral public key from header
2. Load recipient's private key
3. Perform ECDH:
- shared_secret = ECDH(recipient_private, ephemeral_public)
4. Derive AES key from shared secret
5. Decrypt file with AES-256-GCM
|
Kyber-Hybrid Decryption
| Text Only |
|---|
| 1. Read KEM ciphertext from header
2. Perform KEM decapsulation:
- shared_secret = Kyber.Decapsulate(ciphertext, private_key)
3. Derive AES key from shared secret
4. Decrypt file with AES-256-GCM
5. Quantum-resistant decryption complete!
|
Security Design
Defense-in-Depth
Layer 1: Algorithm Security
- Use only well-vetted, NIST-approved algorithms
- AEAD ciphers for authenticated encryption
- Post-quantum algorithms for future-proofing
Layer 2: Key Management
- Strong KDF (Argon2id) with tunable parameters
- Random salt per encryption (prevents rainbow tables)
- Secure key derivation from passwords
Layer 3: Implementation Security
- Use Botan (audited crypto library)
- Constant-time operations where critical
- Secure memory wiping (zero key material)
Layer 4: File Integrity
- Header MAC prevents tampering
- AEAD authentication tag for payload
- Version field allows format migration
Layer 5: Operational Security
- Nonce uniqueness enforced
- Atomic file operations (no partial writes)
- Progress indication without leaking data
Threat Model
Protected Against:
- β
Brute-force password attacks (strong KDF)
- β
Dictionary attacks (salt + iterations)
- β
Chosen-ciphertext attacks (AEAD)
- β
Tampering (MAC + auth tag)
- β
Traffic analysis (encrypted metadata)
- β
Quantum attacks (PQC algorithms)
Not Protected Against:
- β Weak passwords (use strong passwords!)
- β Keyloggers/malware (OS-level threat)
- β Side-channel attacks (hardware-level)
- β Coercion (rubber-hose cryptanalysis)
Randomness
Sources:
- Primary: OS CSPRNG (/dev/urandom, CryptGenRandom)
- Library: Botan's AutoSeeded_RNG (entropy pooling)
Usage:
- Salt generation (32 bytes per encryption)
- Nonce/IV generation (12-16 bytes)
- Key generation (asymmetric keypairs)
- Session keys (hybrid encryption)
Quality Assurance:
- DRBG health checks
- Entropy accumulation
- Reseeding after fork (Unix)
Bottlenecks
-
I/O Operations (Usually the slowest)
- Solution: Buffered I/O, memory mapping
-
Key Derivation (Intentionally slow)
- Solution: Cache derived keys (carefully)
-
Encryption/Decryption (CPU-bound)
- Solution: Hardware acceleration (AES-NI)
Optimizations
1. Chunked Processing
| C++ |
|---|
| // Adaptive chunk size based on file size and RAM
size_t chunk_size = calculate_optimal_chunk_size(file_size);
// Process in parallel (future enhancement)
#pragma omp parallel for
for (size_t i = 0; i < num_chunks; ++i) {
process_chunk(i);
}
|
2. Hardware Acceleration
- AES-NI instructions for AES-GCM
- AVX2/AVX512 for ChaCha20
- Compiler optimizations (-O3 -march=native)
3. Memory Management
- Stack allocation for small buffers
- Arena allocators for frequent allocations
- Secure wiping on deallocation
4. Progress Feedback
- Non-blocking progress updates
- Minimal overhead (<1% CPU)
- Accurate ETA calculation
Benchmarks
Test Environment: Intel i7-11800H, 32GB RAM, NVMe SSD
| Operation | Throughput | Notes |
| AES-256-GCM Encrypt | ~700 MB/s | Hardware accelerated |
| ChaCha20-Poly1305 | ~600 MB/s | Software optimized |
| Kyber-1024-Hybrid | ~650 MB/s | Minimal overhead |
| Argon2id (medium) | ~10ms | Per key derivation |
| RSA-4096 Keygen | ~1.7s | One-time cost |
| Kyber-1024 Keygen | ~0.4ms | Fast PQC! |
Error Handling
Result Type
| C++ |
|---|
| template<typename T>
class Result {
std::variant<T, Error> value_;
public:
bool is_ok() const;
bool is_err() const;
T unwrap();
Error error();
};
|
Usage:
| C++ |
|---|
| auto result = encrypt_file(params);
if (result.is_err()) {
console::error("Encryption failed: {}", result.error().message());
return 1;
}
|
Error Categories
- I/O Errors: File not found, permission denied
- Crypto Errors: Wrong password, corrupted file
- Format Errors: Invalid header, unsupported version
- System Errors: Out of memory, disk full
Future Enhancements
Planned Features
-
Parallel Processing
- Multi-threaded chunk encryption
- SIMD optimizations
-
Cloud Integration
- S3/Azure Blob Storage support
- Streaming encryption to cloud
-
Key Management
- Hardware security module (HSM) support
- TPM integration for key protection
-
Advanced Compression
- Context-aware compression
- Encryption + compression pipeline
-
Metadata Encryption
- Hide file size (padding)
- Encrypted filenames
References