aeat.adapters.persistence.storage.master_key._recovery_facade module

Typed BIP-39 recovery facade for the per-bucket unlock pipeline.

The substrate’s BIP-39 mnemonic encoding, HKDF-derived recovery KEK, and AES-256-GCM wrap of the master DEK live in _recovery.py. This module exposes a typed boundary over those primitives so callers consume and produce the strict pydantic v2 records (RecoveryRecord for the on-disk envelope, BucketSession for the live in-memory state) without reaching into the substrate. The internals never leave _recovery.py.

mint_recovery_envelope is called at enrollment: it generates a fresh 24-word BIP-39 mnemonic, derives the recovery KEK from the entropy, wraps the supplied DEK under that KEK, and returns the RecoveryRecord + the plaintext mnemonic (the only in-memory copy; the caller arranges for the operator to copy it down).

unwrap_recovery_envelope is called at recovery: it accepts the mnemonic the operator typed, decodes the entropy, derives the recovery KEK, and decrypts the wrapped DEK from the RecoveryRecord. The plaintext mnemonic is never persisted.

open_session_from_recovery composes unwrap_recovery_envelope with BucketSession.open so the recovery-flow CLI verb yields a live session the wizard can re-wrap under a fresh passphrase-derived KEK.

class MintedRecovery(**data)[source]

Bases: BaseModel

In-memory result of a recovery enrollment.

The mnemonic is the only handle on the recovery KEK; the caller arranges for the operator to copy it before this record falls out of scope.

Parameters:
envelope: RecoveryRecord
mnemonic: str
mint_recovery_envelope(*, dek, created_at)[source]

Mint a fresh MintedRecovery envelope wrapping dek.

Returns a MintedRecovery carrying the typed RecoveryRecord and the 24-word mnemonic the operator must record. The mnemonic is the only handle on the recovery KEK; this function does NOT persist it.

Return type:

MintedRecovery

Parameters:
unwrap_recovery_envelope(*, envelope, mnemonic, decoder=None)[source]

Decode mnemonic and unwrap envelope to recover the 32-byte DEK.

Parameters:
  • envelope (RecoveryRecord) – The persisted RecoveryRecord to unwrap.

  • mnemonic (str) – The 24-word BIP-39 mnemonic supplied by the operator.

  • decoder (Callable[[str], bytes] | None) – Optional override for mnemonic decoding; production callers omit it.

Return type:

bytes

Returns:

The recovered 32-byte data-encryption key.

Raises:

RecoveryVerificationError – When the mnemonic does not decode or the AEAD tag check fails.

verify_recovery_mnemonic(*, envelope, mnemonic)[source]

Return True iff the mnemonic correctly unwraps the envelope.

Used by the aeat config verify-recovery periodic-custody-test verb. Catches RecoveryVerificationError and surfaces a boolean so the CLI renders the outcome without leaking detail.

Return type:

bool

Parameters:
save_recovery_envelope(envelope, path)[source]

Atomically persist a typed recovery envelope.

Return type:

None

Parameters:
load_recovery_envelope(path)[source]

Read, validate, and return a RecoveryRecord from path.

Return type:

RecoveryRecord

Parameters:

path (Path)

open_session_from_recovery(*, bucket_id, envelope, mnemonic, kek, idle_minutes, opened_at)[source]

Compose mnemonic-unwrap with BucketSession.open and return a BucketSession.

The caller supplies the freshly-derived passphrase KEK (the operator’s new passphrase, run through Argon2id under a fresh salt); the function unwraps the DEK from the recovery envelope and yields a live session bound to bucket_id.

Return type:

BucketSession

Parameters: