Status: Proposed (2026-07-28); design in
docs/design/encryption.md. Companion to
ADR-0018, which adds per-attribute keys
above this layer.
Every durable artifact Corium writes is currently plaintext: index blobs in the object store, transaction log records, root records, backup archives, and the peer's SSD segment cache. ADR-0003 makes those blobs immutable and content-addressed, and docs/design/protocol.md states the operating assumption plainly — "the blob store is assumed private to the deployment".
That assumption does not survive the deployments Corium already supports. An S3 bucket, a Postgres blob table, a backup file copied to a laptop, and an SSD cache directory on a shared host all have failure modes where the medium is readable by someone who was never granted database access. Authentication and authorization (ADR-0012, ADR-0014) guard the request path and do nothing for any of them.
The constraint that shapes the answer is content addressing. A blob's id is its BLAKE3 digest; publication reuses unchanged leaves by id; GC marks and sweeps by id; backups copy by id; the cache verifies by id. Encryption must not disturb any of that, and must not require a key to perform the operations that today require none.
Encrypt every durable artifact under a per-database data key, wrapped by a
key-encryption key held in a KMS or an operator file, with a new
corium-crypt crate owning the primitives and a Keyring trait owning key
resolution.
EncryptedBlobStore<S> wraps
any BlobStore, so mark_and_sweep, manifest walking, backup, and every
reader keep operating on plaintext and stay unchanged.put stays idempotent, unchanged
leaves still produce identical objects and are still shared structurally, and
the store still verifies integrity by re-hashing what it holds, with no key.
Cross-database deduplication is given up; within a database nothing changes.(log-version, t) and
an AAD binding both, so no record can be replayed at another basis or moved
between the per-lease-version files M7 fencing depends on.RootStore::compare_and_set compares bytes. A new keys:<db> root record
holds the wrapped DEKs, and DbRoot gains a manifest version (storage
format 4) so an encrypted database announces itself before a reader tries to
parse a blob.corium keys operates one database at a time.put,
structural sharing, and keyless integrity verification, which is far too much
to pay.Can you improve this documentation? These fine people already did:
Casey Marshall & ClaudeEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |