aeat.adapters.persistence.storage.crypto._crypto module¶
AEAD primitives and HKDF derivation for at-rest persistence.
Wraps cryptography.hazmat.primitives.ciphers.aead.AESGCM and
cryptography.hazmat.primitives.kdf.hkdf.HKDF behind a small,
typed surface. The at-rest crypto stack pivots on this module:
column-level TypeDecorator instances, the encrypted blob
store, the secret store, and the schema-version envelope all consume
encrypt_record(), decrypt_record(), and derive_key().
The on-wire shape of EncryptedBlob is deliberately minimal —
nonce || ciphertext_with_tag. The AEAD identifier and any version
metadata live in the envelope record (see adapters.persistence.storage’s
EncryptionMetadata), so a future swap to e.g. ChaCha20-Poly1305
or an Argon2id-derived KEK can define a new current envelope contract
without changing this primitive blob shape.
- class EncryptedBlob(**data)[source]¶
Bases:
BaseModelOne frozen unit of AEAD ciphertext.
The on-wire form is
nonce || ciphertext_with_tag. Callers that persist the blob choose the wire encoding (raw BLOB column, base64-in-JSON, etc.). The pydantic record is the in-memory canonical form.- Variables:
nonce – 12 random bytes used exactly once with the wrapping key. Sourced from
secrets.token_bytes(); the GCM birthday bound permits roughly 2**32 random nonces per key.ciphertext – AES-256-GCM ciphertext concatenated with its 16-byte authentication tag. The
min_length=GCM_TAG_SIZEpermits a bare 16-byte authentication tag, which is the legitimate shape for an empty-plaintext encryption (encrypt_record(b"")); shorter values are rejected because the GCM tag would be truncated.
- Parameters:
- nonce: bytes¶
- ciphertext: bytes¶
- classmethod from_wire(payload)[source]¶
Parse the canonical wire form back into an
EncryptedBlob.- Parameters:
payload (
bytes) –nonce || ciphertext_with_tag. Must be at leastNONCE_SIZE + GCM_TAG_SIZEbytes.- Return type:
- Returns:
The reconstructed
EncryptedBlob.- Raises:
DecryptionError – If
payloadis shorter than the minimum envelope.
- encrypt_record(plaintext, *, key, associated_data=None)[source]¶
Encrypt
plaintextwith AES-256-GCM and return anEncryptedBlob.A 12-byte random nonce is generated for every call. The substrate’s expected throughput is far below the GCM birthday bound, so random nonces are safe.
- Parameters:
plaintext (
bytes) – Bytes to encrypt. Empty plaintext is permitted; the tag still authenticates the empty payload.key (
bytes) – 32-byte AES-256 key. Smaller keys are rejected.associated_data (
bytes|None) – Optional additional authenticated data. The same value MUST be supplied at decrypt time; mismatch raisesDecryptionError.
- Return type:
- Returns:
A frozen
EncryptedBlobcarrying the nonce and ciphertext-with-tag.- Raises:
EncryptionError – If
keyis not exactlyKEY_SIZEbytes, or if the underlying AEAD operation fails for any other reason.
- decrypt_record(blob, *, key, associated_data=None)[source]¶
Decrypt an
EncryptedBloband verify its authentication tag.- Parameters:
blob (
EncryptedBlob) – The encrypted record produced byencrypt_record().key (
bytes) – The same 32-byte key used to encrypt the blob.associated_data (
bytes|None) – The same associated data passed at encrypt time. Must match exactly (includingNonevsb"").
- Return type:
- Returns:
The original plaintext bytes.
- Raises:
DecryptionError – If the authentication tag does not verify, the ciphertext has been tampered with, the key does not match, or the associated-data binding is wrong.
EncryptionError – If
keyis not exactlyKEY_SIZEbytes.
- derive_key(*, key_material, salt, context, length=32)[source]¶
Derive a per-purpose key via HKDF-SHA256.
The substrate uses HKDF to produce per-row, per-blob, and per-store keys from a single master key.
contextis the HKDFinfoparameter and binds the derived key to a specific purpose; reusing the same master key with differentcontextvalues yields cryptographically independent keys.- Parameters:
key_material (
bytes) – The IKM (input keying material). For the substrate this is the master key.salt (
bytes) – HKDF salt. SHOULD be a random per-store value persisted alongside the secret-store master key file. May be empty for callers that only ever derive one key from the IKM, but a per-purpose salt is preferred.context (
bytes) – HKDFinfoparameter. SHOULD be a stable descriptive bytestring such asb"aeat.lookup.v1"orb"aeat.envelope.payload.v1".length (
int) – Number of bytes to derive. Defaults toKEY_SIZE.
- Return type:
- Returns:
lengthderived key bytes.- Raises:
KeyDerivationError – If the HKDF operation fails.