TessariDBDocs
  • 0.35.3latest
  • 0.35.2
  • 0.35.1
  • 0.35.0
  • 0.34.4
  • 0.34.3-beta
  • 0.34.2-beta
  • 0.34.1-beta
  • 0.34.0-beta
  • 0.33.4-beta
  • 0.33.3-beta
  • 0.33.2-beta
  • 0.33.1-beta
  • 0.33.0-beta
  • 0.32.0-beta

Encryption at rest

Every file encrypted and authenticated under a key of its own, derived from a root key your KeyProvider supplies; AES-256-GCM or ChaCha20-Poly1305; wrong keys refused before anything is read; key rotation.

With encryption on, every file holding data or metadata — table files, log segments, manifests and the options record — is encrypted and authenticated. The database stores no key.

How keys are arranged

  • You supply root keys through a KeyProvider: given a key id, it returns the 32-byte root key with that id, or None.
  • Each file gets a key of its own, derived from a root key. Each table file, each manifest and each open's log are sealed under different keys.
  • Each file names the id of the root key its key comes from, and the cipher it uses. The database asks the provider for that root key when it opens the file.

Turning it on

use std::sync::Arc;
use tessarikv::{Db, DbOptions, KeyProvider, RootKey};

struct Keys {
    current: [u8; 32],
}

impl KeyProvider for Keys {
    fn root_key(&self, key_id: u32) -> Option<RootKey> {
        (key_id == 1).then(|| RootKey::new(self.current))
    }
}

async fn open_sealed(root: [u8; 32]) -> tessarikv::Result<Db> {
    let options = DbOptions::builder()
        .encryption(Arc::new(Keys { current: root }), 1) // new files use key id 1
        .build()?;
    Db::open("data/sealed", options).await
}

Load the root key from your own secret store. The provider is called on a blocking thread when the database opens and whenever it opens a file, so it may read a key store. Answer from memory where you can: every table file opened waits for it.

Ciphers

By default new files use AES-256-GCM where the processor has AES instructions, and ChaCha20-Poly1305 where it does not. DbOptionsBuilder::encryption_cipher(Cipher::Aes256Gcm) pins one. Each file names its cipher, so files written under another cipher still open.

A wrong or missing key

A database encrypted once opens only with its key. Opening with a wrong key, or with a provider that has no key for an id a file names, is refused before any file is read.

Rotating the root key

  1. Add the new root key to your provider under a new id, keeping the old one.
  2. Open with the new id in encryption(provider, new_id). New files take it.
  3. Keep the old key while any file still names it. Compaction rewrites table files over time, and every file it writes takes the current key id.

What stays visible

File names, file sizes, the sizes of the blocks, frames and edits inside them, and the sequence number of each logged batch are not hidden. Everything else — keys, values, options — is.