Architecture
Three layers, and the keys at each
Records are sealed in the member's browser, kept by the server in the company's own TessariDB vault, and stored by TessariDB. Each layer holds its own keys, and none below the browser holds a key that opens a record.
Layers
Browser, company vault, store
The browser is the only place a record is ever plaintext. The server holds each revision's sealed body in the company's TessariDB vault, which a key derived per request opens, and TessariDB stores that vault encrypted again. The store's own vault passphrase and its root account open none of it.
- the member's browserholds the unlock password, and the keys it unwrapsthe record, opened
- tessaridb-vaultholds the service key file; each company's vault key, derived per requesta sealed revision, its size, its readers
- TessariDBholds the company's vault, encrypted againa vault entry it can open only with a presented key
In the browser
The unlock password is not the sign-in password
Signing in proves who you are to the server. Unlocking happens only in the browser: Argon2id turns the unlock password into a key that unwraps your private keys for this company, and the password never leaves the page.
| 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 |
Vouching
Writing a row adds no reader
The company's first owner pins the company owner key. Owners and admins extend a chain of signed statements from it, one member key or group key at a time, after comparing its fingerprint. A browser wraps a record key only to a key the chain covers, and trusts a revision only from an author it covers, so a server that inserts a key of its own gets nothing to read.
A revision that was moved, altered or not signed is refused, and so is one older than a revision the browser has already seen.
On the server
One key file, outside the store
The server reads one service key 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 (per company, per request, never stored), the pepper applied to sign-in passwords before Argon2id, and the key that seals authenticator secrets. The file itself is 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. Without it nothing in the store can be opened by the server either.
In TessariDB
Every piece of state is a TessariDB record
Companies, members, departments and teams, key sets, records and their revisions, shares, files, sessions, throttles and the audit trail live in TessariDB: records, vaults, spaces with expiry and buckets, with no second store beside it.
A file up to 64 KiB stays in the company's vault; a larger one goes to a TessariDB bucket, encrypted in the browser in 64 KiB chunks.
- Every admin change and every read of a sealed record is written to the company's trail in the same transaction as the act.
- A chain over each company's events shows where a row was altered.
- Sessions and attempt counters are TessariDB spaces that expire on their own.
Recovery
Owners can hand keys back, and the member is told
Every member's browser escrows their private keys to the company's recovery key, which only owners hold. A member who forgot the unlock password asks with a one-time key their browser makes and reads a code to an owner; the owner's browser hands the keys over to that one-time key, and the member sets a new unlock password within 72 hours.
Every read of a member's escrowed keys is shown to that member. An admin, another company, the platform admin and the store's administrator are refused.
One binary
The web application is in the server
The pages and their script are compiled into the tessaridb-vault binary and served from it, with no third-party code. 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.
Limits
What it does not protect against
- An unlocked browser and the device it runs on. While your vault is unlocked, the keys are in that tab's memory. Malware on the device, or a browser extension allowed to read the page, can read what you can.
- The code the server delivers. Whoever controls the server you sign in to can serve a modified application that captures your unlock password. A web client cannot prove to you that it is honest.
- The server host. Someone with control of the host can read the database-side keys and session tokens in the service's memory, and the metadata below. Without your unlock password they still cannot decrypt a record.
- Your company's owners and admins. Owners hold the recovery key, so they can restore any member's access and read every record shared with members of the company. Admins hold the keys of departments and teams, so they can read every record shared with a department, a team or the whole company, but not records shared only with individual people. Every member is shown this.
- Metadata. The server sees who belongs to which company, department and team, who shares which record with whom, record types, sizes, counts and timestamps, and when records are fetched. Names of records are encrypted; their existence is not.
- Someone who already read a secret. Removing a person stops their future access and rotates the record's key. It cannot make them forget a value they saw. Change the secret at its source.
- A restored old copy. Someone who can write to the database can put back an old version of a record. Your browser refuses a version older than one it has already seen, but cannot detect an old version it has never seen newer of.
- A weak unlock password. Anyone holding the database and the server's key file can try to guess your unlock password offline. Each guess costs a memory-hard key derivation, but a short or common password still falls.
- Your sign-in provider. A compromised identity provider can sign you in, but it cannot unlock your vault: the unlock password is separate and never leaves your browser.
- Files kept in an external object store. When a deployment stores files in TessariDB S3 instead of the database, those files carry the browser's encryption but not the database's second layer.
- Timing and traffic analysis, and future quantum computers against today's ciphertext. The key exchange is classical X25519 in this version; the format names its algorithms so it can move.