Zero-Knowledge Security & Blind Indexing โ
FLASH DB operates on an architectural zero-knowledge model: the engine and network daemons never receive unencrypted plaintext or decryption keys.
This is not a zk-SNARK circuit system. It is enforced hiding:
| Layer | What it is allowed to see |
|---|---|
FlashClient | Keys, plaintext, trapdoors (the keyholder) |
FlashDatabase / disk | Sealed envelopes (_enc), HMAC trapdoors, Merkle hashes |
FlashServer / gRPC / replication | Sealed wire records + blind query envelopes only |
FlashZKKernel rejects plaintext inserts and plaintext query fields on every network surface. FlashSQL and FlashGraphQL require FlashClient. FlashRBAC can be attached to FlashServer so operations are authorized without the server reading document contents.
The Intelligence Console is a local FlashClient (it holds the key). It is not a remote blind admin.
Fail-closed defaults (v1.2.0): daemons require authKey, the console requires token, remote URIs require authKey, and fieldPolicy: plaintext requires allowPlaintextFields. Weak secrets are rejected.
Trust boundary
Architectural blindness is not a substitute for an independent audit. Limits, leakage, and the public audit roadmap are documented in Trust Model & Audit Roadmap.
The Cryptographic Primitives โ
1. Document & Field Encryption (FlashCipher) โ
- Algorithm: Authenticated
AES-256-GCMwith 96-bit randomized Nonces (IVs) and 128-bit authentication tags. - Key Derivation: Master secret keys are derived using
PBKDF2-HMAC-SHA256with 100,000 rounds and a dynamically generated unique database-specific salt (stored securely in.flash-saltper-database). Master secret passphrases of any length are automatically hardened and derived, rather than being used directly as raw AES keys. - Envelope Layout:
[ IV (12 bytes) | AuthTag (16 bytes) | Ciphertext (N bytes) ]encoded as Base64.
2. Blind Indexing & Searchable Encryption โ
How can a database find records if it cannot decrypt the data?
FLASH DB implements Searchable Symmetric Encryption (SSE) using salted HMAC cryptographic trapdoors:
Exact Matches ($eq, $in) โ
Trapdoor = HMAC-SHA256(SecretKey, "exact:" + FieldName + ":" + Value)- The client hashes the search value into a 64-character hex token.
- The server searches its in-memory Blind Index map for this hex token.
- The server matches the record without ever knowing what value was searched for!
::: security Deterministic Encryption For situations requiring exact matching where deterministic encryption is preferred, FLASH utilizes AES-256-CBC with synthetic HMAC-based IVs rather than AES-GCM deterministic mode, eliminating any risks associated with GCM nonce-reuse (which would compromise the master key if a synthetic nonce ever collided). :::
Substring & Regex Queries ($regex) โ
For partial text search:
- The text is broken down into 3-Gram Substrings.
- Each 3-gram is hashed into an HMAC token.
- The server computes the set intersection of matching documents.
Regular Expression Sandboxing (ReDoS Prevention)
To prevent Regular Expression Denial of Service (ReDoS) resource exhaustion attacks (where a malicious pattern causes exponential backtracking), $regex evaluations on the server are executed in a secure Node.js vm sandbox with a strict 50ms execution timeout.
Honey Padding (Defense Against Frequency Leakage) โ
To prevent statistical frequency analysis attacks (where an attacker analyzes token repetition counts):
- FLASH injects randomized, pseudo-deterministic dummy noise tokens (Honey Padding).
- This masks the token distribution and document length profiles from attackers.
3. Bucketed Range Indexing ($gt, $lt) โ
Continuous numerical fields (like age, balance, or timestamps) are partitioned into discrete, salt-hashed buckets:
BucketIndex = floor(Value / BucketSize)
BucketToken = HMAC-SHA256(SecretKey, "bucket:" + FieldName + ":" + BucketIndex)When querying { balance: { $gte: 1000, $lte: 5000 } }:
- The client SDK computes the tokens covering buckets from index
100to500. - The server returns the union of matching candidate documents.
- The client SDK decrypts and performs the final sub-bucket precision filter.
4. AAD Field Binding (Anti-Swap Protection) โ
Since v2, FLASH DB binds each ciphertext to its record ID and field name using Additional Authenticated Data (AAD):
Ciphertext = AES-256-GCM(Key, Nonce, Plaintext, AAD = "recordId:fieldName")Why This Matters โ
Without AAD, an attacker could swap ciphertext between records and the database wouldn't notice:
# Without AAD (v1) โ vulnerable to ciphertext swapping
user-1.name ciphertext โ pasted into user-2.name โ decrypts successfully โ
# With AAD (v2) โ ciphertext is bound to the record
user-1.name ciphertext (AAD="user-1:name") โ pasted into user-2.name
โ AAD mismatch โ decryption FAILS โHow It Works โ
- Encrypt: Each field gets AAD =
{recordId}:{fieldName} - Payload format (v2):
[0xF44C4532] [length bytes] [12-byte nonce] [ciphertext + 16-byte auth tag] - Decrypt: The AAD is verified โ if the ciphertext was moved to a different record or field, decryption fails with an authentication error.
- Legacy support: v1 payloads (without the
0xF44C4532magic prefix) are detected and decrypted transparently without AAD verification. No migration needed.
Tenant Key Isolation โ
When using multi-tenancy (client.tenant(tenantId)), keys are derived as:
TenantKey = HMAC-SHA256(MasterKey, dbName + tenantId + version)This ensures that:
- Each tenant's data is encrypted with a unique key
- A compromised tenant key cannot decrypt other tenants' data
- Key rotation is supported per-tenant
const orgA = client.tenant("org-a");
const orgB = client.tenant("org-b");
// org-a's key cannot decrypt org-b's data, and vice versaQuantum-Resistant Hardening โ
Enable PQC-hardened key derivation for post-quantum protection:
const client = new FlashClient({
storagePath: "./flash_data",
pqcHardened: true, // Uses FlashPQC.deriveQuantumHardenedKey()
});