| Field | Encryption | Search index | Supports | Decrypt allowed for |
|---|---|---|---|---|
| subject_nid | AES-256-GCM, per-record key | Keyed hash (HMAC-SHA-256) | Exact match | Analysts with case access |
| subject_name | AES-256-GCM | Bloom-filter n-grams | Fuzzy and partial match | Analysts with case access |
| txn_amount | AES-256-GCM | Order-revealing encryption | Range and sort | Analytics service (aggregates only) |
| account_no | Format-preserving tokenisation | Token equality | Join across systems | Supervisors on request |
| str_narrative | AES-256-GCM | None | — | Case team · AI summariser in an enclave |
| wb_identity | Per-report key, two-person unseal | None | — | Two committee members together, never a named member |
DEK_r ← random 256-bit key per record C_r ← AES-256-GCM(DEK_r, plaintext, aad = table‖id‖field) W_r ← HSM.wrap(KEK_partition, DEK_r) # KEK never leaves the HSM idx_eq ← HMAC-SHA-256(K_idx, normalise(value)) # exact match idx_ng ← BloomFilter(trigrams(value), k = 3) # fuzzy match read: policy(user, purpose) → HSM.unwrap(W_r) → decrypt → audit event