|
| 1 | +# Architecture |
| 2 | + |
| 3 | +## Cryptographic Pipeline |
| 4 | + |
| 5 | +EntityCrypt implements a six-layer cryptographic pipeline that operates within the EF Core model finalization lifecycle. Each layer is independent and can be configured or disabled without affecting the others. |
| 6 | + |
| 7 | +``` |
| 8 | +┌──────────────────────────────────────────────────────────────┐ |
| 9 | +│ Layer 1 — Application Interface │ |
| 10 | +│ EF Core DbContext · DbSet<T> · LINQ Queries │ |
| 11 | +│ No application code changes required │ |
| 12 | +├──────────────────────────────────────────────────────────────┤ |
| 13 | +│ Layer 2 — Convention Engine │ |
| 14 | +│ IModelFinalizingConvention │ |
| 15 | +│ Applies ValueConverters and schema transforms per-entity │ |
| 16 | +│ Respects [Encrypted], [NoEncrypt], [EncryptedTable] attrs │ |
| 17 | +├──────────────────────────────────────────────────────────────┤ |
| 18 | +│ Layer 3 — Value Encryption │ |
| 19 | +│ AES-256-GCM per column · Authenticated encryption │ |
| 20 | +│ Random IV via RandomNumberGenerator.Fill (no reuse) │ |
| 21 | +│ HKDF-SHA256 key derivation with domain separation │ |
| 22 | +├──────────────────────────────────────────────────────────────┤ |
| 23 | +│ Layer 4 — Post-Quantum Layer │ |
| 24 | +│ ML-KEM-768 Key Encapsulation (FIPS 203) │ |
| 25 | +│ Hybrid mode: AES-256 ⊕ ML-KEM shared secret via HKDF │ |
| 26 | +│ Native .NET 10 System.Security.Cryptography.MLKem │ |
| 27 | +├──────────────────────────────────────────────────────────────┤ |
| 28 | +│ Layer 5 — Schema Obfuscation │ |
| 29 | +│ HMAC-SHA256 deterministic hashing │ |
| 30 | +│ Table names: HMAC(key, "table:" + name) → mc_<hex> │ |
| 31 | +│ Column names: HMAC(key, "column:" + table + ":" + col) │ |
| 32 | +│ Prevents schema inference attacks │ |
| 33 | +├──────────────────────────────────────────────────────────────┤ |
| 34 | +│ Layer 6 — Key Management & Integrity │ |
| 35 | +│ Merkle Tree · CSPRNG · IDisposable memory zeroing │ |
| 36 | +│ Fingerprint-based vault derivation │ |
| 37 | +│ Proof generation, verification, and consensus │ |
| 38 | +└──────────────────────────────────────────────────────────────┘ |
| 39 | +``` |
| 40 | + |
| 41 | +## Design Invariants |
| 42 | + |
| 43 | +These invariants hold across all configurations and are enforced by the implementation: |
| 44 | + |
| 45 | +### 1. No IV Reuse |
| 46 | +Every encryption operation generates a fresh nonce via `RandomNumberGenerator.Fill`. The deterministic mode (for searchable fields) uses HMAC-derived nonces — never timestamp or counter-based. |
| 47 | + |
| 48 | +### 2. No Plaintext Key Material at Rest |
| 49 | +All derived keys pass through HKDF-SHA256 with domain-separation context strings. Master keys are never used directly for data encryption. |
| 50 | + |
| 51 | +### 3. Zero Trust on the Database |
| 52 | +When fully configured (schema obfuscation enabled), the database engine never processes: |
| 53 | +- Plaintext column names |
| 54 | +- Plaintext table names |
| 55 | +- Plaintext data values (except preserved PK/FK values for JOIN semantics) |
| 56 | + |
| 57 | +### 4. Authenticated Encryption |
| 58 | +AES-256-GCM provides both confidentiality and integrity. Tampering with ciphertext is detected before any plaintext is returned. |
| 59 | + |
| 60 | +### 5. Deterministic Memory Cleanup |
| 61 | +All cryptographic types implement `IDisposable` with explicit memory zeroing of sensitive buffers. Seven classes enforce this pattern. |
| 62 | + |
| 63 | +## Value Encryption Flow |
| 64 | + |
| 65 | +``` |
| 66 | + ┌─────────────────┐ |
| 67 | + │ Plaintext Value │ |
| 68 | + └────────┬────────┘ |
| 69 | + │ |
| 70 | + ┌────────▼────────┐ |
| 71 | + │ Type Detection │ |
| 72 | + │ (13+ CLR types) │ |
| 73 | + └────────┬────────┘ |
| 74 | + │ |
| 75 | + ┌──────────────┼──────────────┐ |
| 76 | + │ │ │ |
| 77 | + ┌────────▼───┐ ┌──────▼─────┐ ┌────▼────────┐ |
| 78 | + │ Classical │ │ Hybrid │ │ PostQuantum │ |
| 79 | + │ AES-256 │ │ AES + MLKEM│ │ ML-KEM-768 │ |
| 80 | + └────────┬───┘ └──────┬─────┘ └────┬────────┘ |
| 81 | + │ │ │ |
| 82 | + └──────────────┼──────────────┘ |
| 83 | + │ |
| 84 | + ┌────────▼────────┐ |
| 85 | + │ Prefix Tag + │ |
| 86 | + │ IV + Cipher │ |
| 87 | + │ + Auth Tag │ |
| 88 | + └────────┬────────┘ |
| 89 | + │ |
| 90 | + ┌────────▼────────┐ |
| 91 | + │ Database Column │ |
| 92 | + │ (obfuscated) │ |
| 93 | + └─────────────────┘ |
| 94 | +``` |
| 95 | + |
| 96 | +## Hybrid Encryption Detail |
| 97 | + |
| 98 | +The Hybrid tier provides quantum-resistance while maintaining classical-grade performance: |
| 99 | + |
| 100 | +1. **First pass:** Encrypt plaintext with AES-256-GCM using a random key |
| 101 | +2. **ML-KEM Encapsulation:** Generate shared secret via ML-KEM-768 `Encapsulate` |
| 102 | +3. **Key Derivation:** Derive a second AES key from ML-KEM shared secret via HKDF-SHA256 |
| 103 | +4. **Second pass:** Encrypt the first-pass ciphertext with the ML-KEM-derived key |
| 104 | +5. **Output:** ML-KEM capsule + double-encrypted ciphertext |
| 105 | + |
| 106 | +Decryption reverses the process using ML-KEM `Decapsulate` to recover the shared secret. |
| 107 | + |
| 108 | +## Key Management Model |
| 109 | + |
| 110 | +``` |
| 111 | + Master Key (environment/vault) |
| 112 | + │ |
| 113 | + ├── HKDF("entity:" + EntityType) ──► Entity-specific key |
| 114 | + │ │ |
| 115 | + │ ├── HKDF("column:" + name) ──► Column-specific key |
| 116 | + │ │ |
| 117 | + │ └── HKDF("schema:" + name) ──► Schema obfuscation key |
| 118 | + │ |
| 119 | + ├── CSPRNG ──► Per-operation IV (12 bytes for GCM) |
| 120 | + │ |
| 121 | + └── Merkle Tree |
| 122 | + ├── Genesis key derivation |
| 123 | + ├── Per-database registration |
| 124 | + ├── Proof generation |
| 125 | + └── Consensus verification |
| 126 | +``` |
| 127 | + |
| 128 | +## Schema Obfuscation |
| 129 | + |
| 130 | +Schema obfuscation transforms all database identifiers using HMAC-SHA256: |
| 131 | + |
| 132 | +- **Table names:** `HMAC-SHA256(key, "table:" + originalName)` → `mc_<truncated-hex>` |
| 133 | +- **Column names:** `HMAC-SHA256(key, "column:" + tableName + ":" + columnName)` → `mc_<truncated-hex>` |
| 134 | + |
| 135 | +This is **deterministic** — the same input always produces the same output — enabling EF Core's model metadata to map between application names and database names. But it is **irreversible** without the key, preventing schema inference attacks. |
| 136 | + |
| 137 | +### PK/FK Handling |
| 138 | + |
| 139 | +- **Column names** of PK/FK are always obfuscated (when schema obfuscation is enabled) |
| 140 | +- **Column values** of PK/FK can be preserved (`PreserveRelationships = true`) for JOIN semantics |
| 141 | +- An attacker with database access cannot identify which obfuscated columns are primary/foreign keys |
| 142 | + |
| 143 | +## ValueConverter Architecture |
| 144 | + |
| 145 | +EntityCrypt uses EF Core's `ValueConverter<TModel, TProvider>` pipeline to intercept all read/write operations: |
| 146 | + |
| 147 | +``` |
| 148 | + Application (C# types) Database (encrypted strings) |
| 149 | + ═══════════════════════ ═══════════════════════════ |
| 150 | + string "Jane Doe" ──► "ENC:AES256:iv:cipher:tag" |
| 151 | + int 42 ──► "ENC:AES256:iv:cipher:tag" |
| 152 | + decimal 99.95 ──► "ENC:AES256:iv:cipher:tag" |
| 153 | + DateTime 2025-01-01 ──► "ENC:AES256:iv:cipher:tag" |
| 154 | + Guid {abc-123} ──► "ENC:AES256:iv:cipher:tag" |
| 155 | + bool true ──► "ENC:AES256:iv:cipher:tag" |
| 156 | +``` |
| 157 | + |
| 158 | +The `ValueConverterFactory` supports 13+ CLR types with both randomized and deterministic encryption modes. |
| 159 | + |
| 160 | +## Searchable Encryption |
| 161 | + |
| 162 | +For fields marked `[Encrypted(Searchable = true)]`: |
| 163 | + |
| 164 | +1. A deterministic nonce is derived: `HMAC-SHA256(key, plaintext)` → truncated to nonce size |
| 165 | +2. AES-256-GCM encrypts with this deterministic nonce |
| 166 | +3. **Result:** Identical plaintexts produce identical ciphertexts |
| 167 | +4. **Trade-off:** Reveals equality (two equal values → equal ciphertexts) |
| 168 | +5. **Use case:** Exact-match lookups (`WHERE Email = @param`) |
| 169 | + |
| 170 | +> Searchable encryption should be used sparingly on low-sensitivity equality-lookup fields only. |
| 171 | +
|
| 172 | +## Merkle Integrity Layer |
| 173 | + |
| 174 | +The Merkle Key Tree provides: |
| 175 | + |
| 176 | +- **Genesis Key Derivation** — deterministic root key from master key |
| 177 | +- **Database Registration** — per-database key isolation |
| 178 | +- **Tree Rebuilding** — reconstruct integrity state from persisted data |
| 179 | +- **Proof Generation** — cryptographic proof that a specific key exists in the tree |
| 180 | +- **Proof Verification** — validate proofs without accessing the full tree |
| 181 | +- **Consensus Checking** — multi-party agreement on tree state |
| 182 | + |
| 183 | +This enables integrity verification of the key hierarchy independent of the database. |
0 commit comments