Skip to main content

Module crypto

Module crypto 

Source
Expand description

Envelope encryption for tenant LLM provider keys (BYOK).

§Why this lives in the edge

A tenant’s OpenAI/Anthropic key is the most sensitive value the platform handles: it bills to their account and it is useful to an attacker on its own. The design goal is that plaintext exists only in this process.

  • Brain never sees it. The engine holds a namespace-scoped grant and calls the edge, which swaps the grant for the real key on the way upstream. A Brain compromise — WAL, snapshots, backups — yields no provider keys, because none were ever written there.
  • The store never sees it. SealedSecret is the only shape that crosses the crate::port::LlmCredentialStore boundary. Whatever persists it — Postgres in the hosted gateway, a file in self-host — holds ciphertext and nothing else, so a database compromise yields nothing usable without the key-encryption key, which lives in this process’s configuration and never in its data.

§The construction

AEAD (ChaCha20-Poly1305) under a key-encryption key, with a fresh random 96-bit nonce per seal and the binding context as additional authenticated data.

The AAD is load-bearing, not decoration. It binds the ciphertext to the namespace and provider it was sealed for, so a stolen row cannot be replayed under a different tenant: moving acme’s ciphertext into globex’s row makes the tag fail and the open returns an error rather than another tenant’s key. Without it, a store with row-level write access would be a cross-tenant key-swap primitive.

kek_id is carried in the clear beside the ciphertext so several KEKs can coexist. That is what makes rotation possible without a flag day: a new KEK is added, new seals use it, and old rows stay readable until re-sealed.

§Why ring

ring is already in this binary’s dependency tree (via rustls), so using it adds no new cryptographic implementation to audit. The alternative — pulling a second AEAD crate — would widen the trusted surface to save nothing.

Structs§

KeyRing
A set of key-encryption keys, one of them current.
SealedSecret
An encrypted secret, exactly as it is persisted.
SecretBinding
The context a ciphertext is bound to.

Enums§

CryptoError
What can go wrong sealing or opening a secret.

Constants§

KEK_CURRENT_ENV
Env var naming which KEK id new seals use.
KEK_LEN
Length of a raw key-encryption key, in bytes.
KEK_SPEC_ENV
Env var holding the key-encryption keys, as id:hex,id:hex,….

Functions§

keyring_from_env
Build the key ring from the environment, or None when BYOK is not configured.