9-Layer Defense Architecture
The complete defense stack:
| Layer | Defense | Defends Against |
|---|---|---|
| 1 | Secure Acquisition (TPM, Keychain, etc.) | Untrusted key sources |
| 2 | Memory Page Locking (mlock / VirtualLock) | Swap files, hibernation |
| 3 | Fragment Strategy (variable chunks, shuffle) | Pattern recognition, memory scraping |
| 4 | Decoy Bytes (self-referential filler) | Entropy/frequency analysis |
| 5 | Codex Transformation (byte swap) | Memory dump analysis |
| 6 | Constant-Time Operations | Timing side-channels |
| 7 | Zero-On-Drop | Use-after-free leakage |
| 8 | Security Monitor (failure detection) | Brute-force, anomalous access |
| 9 | Audit Logging | Forensic trail, compliance |
| 10 | (Bonus) Page Protection Toggling | Snapshot attacks |
Full details: see docs/SECURITY.md for the comprehensive security architecture.
Visual walkthrough: see docs/TRANSFORMATION.md for a step-by-step trace of what happens to a key as it passes through all the layers.
Current status
key-vault is pre-1.0; the public API is not yet stable. The 9-layer
architecture above is the 1.0 design target. Each release lights up more
of it. The "Features" section below documents the 1.0 surface; the table here
records what is actually built today so you can match the README against the
shipped code.
| Component | Status as of 0.6.0 |
|---|---|
Public type system (Error, Result, KeyHandle, KeyMetadata, RawKey, FetchContext, Fragments) |
shipped |
Trait surfaces (KeyFetch, FragmentStrategy, DecoyStrategy, Codex, SecurityMonitor) |
shipped |
Layer 2 — mlock / VirtualLock (via internal LockedBytes wrapper) |
shipped |
Layer 3 — All four fragment strategies: StandardFragmenter, RandomFragmenter, InterleavedFragmenter, LayeredFragmenter |
shipped |
Layer 4 — Decoy strategies (RandomDecoy, SelfReferenceDecoy, KeyDerivedDecoy) |
shipped |
Layer 5 — Full codex stack: IdentityCodex, FnCodex, StaticCodex, DynamicCodex (table in LockedBytes) |
shipped |
Layer 6 — Constant-time KeyHandle equality (via subtle::ConstantTimeEq) |
shipped |
| Layer 7 — Zero-on-drop (every fragment + layout buffer + intermediate plaintext + decoy buffer + codex table) | shipped |
BLAKE3 key normalization (wired through KeyVaultBuilder::normalize_with_blake3) |
shipped |
TEE detection (detect_tee_capabilities) |
shipped (real x86_64 + Apple SE + AWS Nitro probes) |
KeyVault::fragment / KeyVault::defragment convenience methods |
shipped (uses StandardFragmenter internally) |
KeyVaultBuilder::with_chunk_range / with_decoy / with_codex |
shipped |
| Layer 1 — built-in fetchers (Keychain, File, Env, TPM) | planned for 0.7.0 |
| Layer 8 — Monitor implementations | planned for 0.8.0 |
| Layer 9 — Audit logging | planned for 0.8.0 |
| Multi-key vaults, rotation, master recovery | planned for 0.9.0 |
| Criterion benchmark suite | planned for 0.10.0 |
Each phase's exit criteria, scope, and timeline are tracked in .dev/ROADMAP.md.
Features (the 1.0 design)
Defense-in-depth memory protection (1.0 design)
- Memory page locking (mlock / VirtualLock) prevents key material from being swapped to disk
- Fragment storage splits keys into variable-sized chunks at non-contiguous addresses
- Self-referential decoy bytes statistically indistinguishable from real key material
- Codex transformation (opt-in) adds byte-level obfuscation
- Zero-on-drop via zeroize overwrites memory when keys leave scope
- Constant-time comparisons via subtle prevent timing attacks
- No debug exposure —
KeyHandle'sDebugimpl always printsKeyHandle(<redacted>)(shipped today)
Pluggable key fetchers (1.0 design, KeyFetch trait shipped)
The KeyFetch trait is in place today. Built-in implementations arrive in 0.7.0:
- TPM 2.0 hardware fetcher — detection-only in 1.0, full integration deferred to 1.x
- OS Keychain — macOS Keychain, Windows Credential Manager, Linux Secret Service
- Encrypted file with permission checks
- Environment variables for container deployments
- Custom fetchers via the trait — bring your own HSM, KMS client, or proprietary source
Fragment strategies (all four shipped in 0.5.0)
- Standard — variable chunks + Fisher-Yates shuffle, each chunk in its own mlock'd allocation
- Random — chunks of variable size whose bytes come from non-contiguous positions in the key (no chunk holds a contiguous key substring longer than 1)
- Interleaved — single large pool, key bytes scattered at random positions, gaps filled with CSPRNG padding
- Layered — routes each fragmentation to a uniformly-picked sub-strategy; strategy index encoded in the layout header so defragment dispatches correctly
- Custom — implement the
FragmentStrategytrait
See docs/SECURITY.md for the per-strategy threat-model comparison.
Decoy strategies (1.0 design, DecoyStrategy trait shipped)
- Random — raw RNG bytes (fastest, weakest) — shipped in 0.4.0
- Self-Reference — real key bytes used as filler (strongest, recommended default) — shipped in 0.4.0
- Key-Derived — BLAKE3-XOF bytes seeded by key + per-call nonce — shipped in 0.4.0
Codex layer (Layer 5, all four shipped in 0.6.0)
IdentityCodex— no transformation (default, max performance) — shipped in 0.2.0FnCodex— user-provided closure (involution-only) — shipped in 0.2.0StaticCodex— declarative swap table (from_swaps(&[(u8, u8)])) or fresh random involution (random_involution()) — shipped in 0.6.0DynamicCodex— per-vault randomized involution with no fixed points — shipped in 0.6.0
All codex tables live in LockedBytes (mlock'd, zeroed on drop).
Encoding/decoding is one memory load per byte (constant-time, branch-free).
Security monitoring (Layer 8, trait shipped)
- Failed decryption detection — N failures in M seconds triggers configurable response — 0.8.0
- Anomalous access patterns — detect sustained data exfiltration — 0.8.0
- Threshold lockout — lock vault after threshold breach — 0.8.0
- Pluggable sinks — log, metrics, webhook, custom — 0.8.0
Operational features
- Master key recovery — fallback path for hardware failure — 0.9.0
- Key rotation — atomic swap to new key without dropping access — 0.9.0
- Multiple keys per vault — named keys with independent lifecycles — 0.9.0
- TEE detection — check for Intel SGX, Intel TDX, AMD SEV, AMD SEV-SNP, ARM TrustZone, Apple Secure Enclave, AWS Nitro — shipped
- Key normalization — BLAKE3 hash input to neutralize format-based pattern leaks — shipped in 0.3.0
Performance targets (1.0 design — not yet measured)
- Key acquisition — sub-second from hardware, sub-millisecond from keychain
- Key access (defrag into temporary buffer) — sub-microsecond (~500ns including audit + monitor)
- Concurrent access — lock-free reads after vault initialization
- Memory overhead — < 16 KiB per key (including fragment + decoy overhead)
- Zero allocations on the hot path (after vault initialization)
Note on benchmark numbers: detailed criterion-backed benchmark numbers will land with v1.0.0 (Phase 0.10.0 in the roadmap). Until then, performance numbers are targets, not measurements.
Quick start
[]
= "0.6"
use ;
use detect_tee_capabilities;
// Build a vault with the full default stack: Layer 2 (mlock/VirtualLock)
// + Layer 3 (StandardFragmenter) + Layer 4 (SelfReferenceDecoy — the
// strongest decoy) + Layer 5 (per-vault DynamicCodex involution)
// + Layer 6 (ConstantTimeEq) + Layer 7 (zero-on-drop).
let vault = new
.normalize_with_blake3 // default
.with_codex
.with_decoy
.build;
// Hand the vault some key material and get back an opaque, scattered,
// mlock'd, zeroed-on-drop representation with decoy chunks mixed in.
let raw = new;
let frags = vault.fragment.expect;
// Reassemble when you need to use it. With BLAKE3 normalization on,
// the recovered bytes are the 32-byte hash of the input.
let recovered = vault.defragment.expect;
assert_eq!;
// Snapshot the host's TEE capabilities at startup:
let caps = detect_tee_capabilities;
println!;
Threat model
key-vault is designed to defend against:
- Memory scraping by attackers with read access — malware, forensic tools
- Forensic memory analysis — swap files, hibernation files, crash dumps
- Statistical pattern recognition — entropy analysis, frequency analysis
- Use-after-free leakage — keys persisting after they should have been wiped
- Brute-force decryption attempts — failed attempts trigger alerts
- Timing side-channels — constant-time operations
- Insider threats / forensic compliance — full audit trail
It does NOT defend against:
- Code execution within your process — an attacker who can call your reassembly logic
- Hardware-level memory access (DMA attacks) — use IOMMU + hardware mitigations
- Cold-boot attacks — use full disk encryption + power-down protocol
- Side-channel attacks on cryptographic operations — that's crypt-io's job
- Quantum computer attacks on asymmetric crypto — use post-quantum algorithms (symmetric defaults are PQ-safe)
See docs/SECURITY.md for the full threat model.
Documentation
- docs/SECURITY.md — Comprehensive 9-layer security architecture
- docs/TRANSFORMATION.md — Visual walkthrough of key transformation
- .dev/ROADMAP.md — Production roadmap to 1.0
- .dev/DIRECTIVES.md — Engineering directives
Standards
- REPS (Rust Efficiency & Performance Standards) governs every decision. See REPS.md.
- MSRV: Rust 1.85.
- Edition: 2024.
- Cross-platform: Linux, macOS, Windows.
License
Dual-licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.