Keys and layers
The three layers a record passes through, the keys at each, the chain of vouching that decides who can be a reader, and the one key file the server holds.
A record is plaintext in one place only: the browser of a member it is shared with. Below the browser are two layers, and each holds keys of its own; none of them holds a key that opens a record.
Status. Release
0.0.1, the first.
The layers
- The browser seals each revision and wraps the record's key to its readers.
- The server keeps the sealed body in the company's own TessariDB vault, which opens only for a request presenting that company's key. The key is derived per request from the service key and never stored.
- TessariDB stores the vault encrypted again. The store's own vault passphrase and its root account open none of it, and a scan of a backup or the store directory finds no record body.
The browser's keys
| Key | What it does | Algorithm |
|---|---|---|
| unlock key | wraps your private keys for one company | Argon2id, then HKDF-SHA256 and AES-256-GCM |
| agreement key | receives record keys and group keys wrapped to you | X25519, HPKE (RFC 9180) |
| signing key | signs the revisions you write and the statements you vouch | Ed25519 |
| record key | one per record, wrapped to each member or group it is shared with | random 256-bit |
| content key | seals one revision, once, bound to its company, record, revision and key | HKDF-SHA256, AES-256-GCM |
The unlock key's derivation is checked before any work is done: at least 47 104 KiB of memory, 1 to 10 passes, 1 to 8 lanes. A wrapped key set that asks for less is refused rather than derived. The browser's cryptography carries no third-party code; HPKE is checked against the standard's published vectors.
Vouching
The company's first owner pins the company owner key. Owners and admins then append signed statements to a chain that starts at it, one member key or group key at a time, after comparing the key's fingerprint with its holder. A browser:
- wraps a record key only to a key the chain covers, and
- trusts a revision only from an author the chain covers.
The server stores the chain, but a statement not signed by a key the chain already covers is refused by every browser, so writing a row adds no reader.
The service key
The server reads one file at start: 32 random bytes as 64 hexadecimal characters, readable by its own user only. From it the server derives the key that opens each company's vault, the pepper applied to sign-in passwords before Argon2id, and the key that seals authenticator secrets. The file's contents are dropped from memory once those keys exist.
The file is not in the store, so a backup of the store holds none of these keys. Back it up apart from the store: without it the server can open nothing it keeps.
The web application
The pages and their script are compiled into the tessaridb-vault binary and
served from it. Every page carries a content security policy that lets it run
only its own script and its own WebAssembly, talk only to its own origin, and
never be framed.