Encryption
MemDb supports AES-256-CBC encryption at the record level. Encrypted and unencrypted records can coexist in the same dataset — configuring a key enables per-record opt-in encryption at insert time, not whole-database encryption. A fresh 128-bit initialization vector is generated for every encrypted record.
MemDbConfigurationException at configuration time. Calling Insert(..., encrypt: true) on a database whose configuration has no encryption key throws NotEncryptionReadyException.What encryption protects
Record-level encryption protects record contents at rest on disk. It does not protect:
- Records held in the in-memory cache (any code in the same process can read decrypted records via the normal API)
- Pointer metadata in the
.mapfile (id, timestamps, encryption flag, length, position) - Index data (indexes are RAM-only and are built from decrypted record values)
If an attacker can read the raw .db file but cannot run code in the application’s process, the encrypted record bytes remain protected by AES-256-CBC.
Configuration
Configure encryption with either a password (hashed into a 256-bit AES key via SHA-256) or a raw 256-bit (32-byte) key:
// Configure with a password — minimum 10 characters
MemDb.ConfigureFor<Person>("people", _dbDirectory)
.EncryptWithPassword(() => "SuperSecureEncryptionPasswordGoesHere.")
.Register();
// Configure with a raw 256-bit key — must be exactly 32 bytes
MemDb.ConfigureFor<Person>("people", _dbDirectory)
.EncryptWithKey(() => myAes256BitKey)
.Register();Constraints enforced at configuration or open time:
- Passwords must be at least 10 characters long (
MemDbConfiguration.MinPasswordLength) - Raw keys must be exactly 32 bytes (256 bits)
- The provider delegate is invoked when the database is opened; supplying
nullor an empty password throws
Usage
Encrypt individual records at insert by passing encrypt: true:
db.Insert(eric, (id) => eric.Id = id, encrypt: true); // encrypted at rest
db.Insert(kyle, (id) => kyle.Id = id); // stored unencryptedReads are transparent — encrypted records are decrypted once at cache load time, and all subsequent reads serve plaintext objects directly from the cache.
Encryption cannot be applied on Update. To encrypt an existing unencrypted record, delete and re-insert it.
Opening a database without the key
If a database is opened without the encryption key configured, encrypted records are silently skipped during the initial load. The cache holds only the unencrypted records; the encrypted bytes remain untouched on disk.
This enables a deferred-key workflow: open and operate on non-sensitive records without the key; when the user supplies the password, dispose the instance and re-open with the key configured to access the full dataset.
Counts and queries against a partially-loaded dataset reflect only the unencrypted subset; avoid totals or aggregates in this state.