Files
tai/taicpp/docs/seal.md
T

3.3 KiB

seal parity (tai.py -> taicpp)

Namespace detz::seal, sources in src/seal/, one class per .h/.cpp pair, headers prefixed seal_. No dependency beyond the standard library: every primitive tai.py takes from hashlib/hmac/base64/os.urandom is written here.

Algorithm (must match byte for byte)

  • master key: PBKDF2-HMAC-SHA256(passphrase utf-8, salt, 200000 rounds, 32 bytes).
  • enc_key = HMAC(master, "tai-enc-1"), mac_key = HMAC(master, "tai-mac-1"), check = hex(HMAC(master, "tai-check-1")).
  • <home>/.seal: json.dumps({"salt": b64(16 random bytes), "check": check}) (mode 0600), created on first use; later opens compare check, mismatch is SealError("wrong TAI_PASSPHRASE"), unreadable JSON or salt is SealError("seal file is corrupt"). An empty file counts as absent (python if raw).
  • keystream: concatenated HMAC(enc_key, nonce || be32(counter)), counter from 0.
  • envelope: tai1$ + b64(nonce16)$b64(cipher)$b64(HMAC(mac_key, nonce||cipher)). lock of an already sealed text or with a disabled seal returns the text unchanged.
  • unlock errors: not sealed, sealed value is corrupt (not 4 $ pieces or bad base64), seal check failed (MAC mismatch, constant time compare).
  • Empty passphrase: seal disabled, no .seal is read or written.

Parity table

tai.py taicpp status
SealError store::SealError (store/errors.h, shared) same messages
Seal (lock, unlock, safe_unlock, stream, enabled, default_key, load_master) seal::Seal : store::SealPort ported, safe_unlock inherited from SealPort
DEFAULT_PASSPHRASE Seal::kDefaultPassphrase
resolve_passphrase repl::Boot::resolve_passphrase (foundation) not duplicated
rotate_seal(config, old_seal, new) SealRotation::rotate(Paths, old, new) events, secrets value+meta (with or without profile column), schedules, settings, mcp_servers, *.sys.md, *.session.json, *.bots.json; logs vault/seal_rotated
default-key upgrade in boot() SealFactory::make(home, passphrase, default_key) prints seal upgraded from default key to TAI_PASSPHRASE
hashlib sha256 / hmac / pbkdf2_hmac / base64 SealSha256, SealHmac, SealPbkdf2, SealBase64 RFC vectors in seal_test

Gaps (listed, not hidden): SealBase64::decode is strict about data after = where python silently discards it (never produced by either implementation). Invalid UTF-8 inside a sealed value is returned as bytes where python raises UnicodeDecodeError. Rotation paths are derived from the home (memory.db, profiles/) because the factory signature carries only the home. NULL values in events, secrets and schedules are not guarded in python either (python crashes, C++ re-seals an empty string).

Tests

make -f tests/seal.mk test from taicpp/:

  • tests/seal_test.cpp: test_seal.py ported 1:1 (all 16 cases) against detz::store::Store, plus RFC 4231/7914/FIPS vectors, factory upgrade and corrupt .seal cases.
  • tests/seal_diff.py with tests/seal_probe.cpp: master key and keystream equality, python seals / C++ opens and the reverse, .seal file written by C++ and opened by python, wrong passphrase, tamper, whole vaults written by one side and decrypted by the other, rotation in both directions, boot upgrade.