mirror of
https://github.com/hanzoai/cek.git
synced 2026-10-09 02:37:18 +00:00
0037b6071cff91a1428d52f4c2a4003c2316e97c
"wrong master key, or a damaged store" was one sentence covering two faults with opposite remedies. The first wants the other key and the bytes are intact. The second wants a restore and the bytes are gone. Nothing on disk told them apart, so telling them apart meant forensics: reading 18MB for a SQLite header that was not there, dating a lock file to the minute of the first conversion, and finding no backup beside it — while an identity store sat unreadable and every relying party in the estate had no JWKS to fetch. So the seal now records its key. `<database>.keyid` holds SHA-256 over a domain-separating label and the DERIVED key, truncated — a commitment, not the key: it cannot be run backwards, it cannot be replayed as one, and it says nothing about any other database, because two stores under one master derive different keys and so carry different ids. On a store that will not read, diagnose() compares the recorded id with the id of the key in hand and answers which fault this is. A store sealed before ids existed cannot answer, and says that rather than inventing a verdict — a guess there aims a restore at the wrong file. convert() now finishes through settle() instead of repeating it. Its own check opened a handle and closed it, which proves nothing: database/sql connects lazily, so a read has to be forced or the key never meets a page. That is the same mistake as trusting the header, wearing different clothes. One place decides a store is good, and that place reads the schema, records the key, and only then releases the plaintext. Mutation-proven on three axes, each restored before staging and the file confirmed byte-identical after: not recording the id fails the test; never detecting a different key falls back to blaming damage, which is the ambiguity this removes; and writing the raw key instead of a commitment fails on the assertion that the id must not contain the key. Co-authored-by: Hanzo Dev <[email protected]>
cek
Opens a namespace's SQLite database encrypted at rest.
cek.SetMaster(k) // once, at boot, from KMS
db, err := cek.Open(ns, "treasury", dataDir) // everywhere else
The key is derived from the master and the namespace. It is not generated, not wrapped, not stored, and not rotated in place — so there is no unwrap step, no rewrap step, no per-file key material to lose, and no migration path to maintain. A database is born encrypted or it does not exist.
Losing the master loses the data. That is the property you want from encryption at rest, and the reason the master lives in KMS.
Where it sits
hanzoai/namespace |
names the entity, and where its file lives |
hanzoai/cek |
turns the master + that name into the file's key, and opens it |
hanzoai/sqlite |
opens a file under a raw key; knows nothing about who owns it |
hanzoai/kms |
holds the master |
Nothing here knows about orgs, users, billing or plugins. It knows a namespace, a subsystem, and a master key.
Languages
Go
100%