cadrumo.adapters.persistence.storage.custody.recovery module¶
Optional per-profile recovery envelopes: a second wrapper over the same DEK.
A recovery envelope wraps a profile’s data-encryption key under a minted
recovery code instead of the operator’s passphrase. It is installed into a
committed capsule only when the operator opts in, removed when they opt out,
and proved by the passphrase-reset door. It never participates in password
login, and it is bound to the exact (profile_id, dek_epoch) it was minted
against, so a passphrase rotation that preserves the epoch leaves it valid.
- validate_profile_custody_dek_epoch(value)[source]¶
Validate the immutable random 128-bit epoch’s canonical representation.
- class ProfileCustodyRecoveryAad(**data)[source]¶
Bases:
BaseModelClosed recovery wrapper AAD descriptor carried by durable records.
- Parameters:
- schema_version: Literal[1]¶
- product: Literal['cadrumo']¶
- purpose: Literal['profile-recovery-dek-wrap/v1']¶
- key_schedule: Literal['profile-recovery-dek-wrap/v1']¶
- class ProfileCustodyRecoveryEnvelope(**data)[source]¶
Bases:
_RecoveryPayload,CustodyDigestModelOne enrolled, independently current-format recovery wrapper.
- Parameters:
self_digest (str)
- self_digest: str¶
- classmethod create(*, profile_id, recovery_generation, dek_epoch, kdf, wrapped_dek, previous_recovery_digest=None)[source]¶
Build the one valid construction path for a current-format recovery envelope.
Pins
schema_versionto the current constant, computesself_digestfrom the assembled payload, then re-validates the whole record throughpydantic.BaseModel.model_validate_json()rather than constructing the model directly — so a caller can never end up holding an envelope whose digest was never actually checked against its own fields.- Return type:
- Parameters:
profile_id (UUID)
recovery_generation (int)
dek_epoch (str)
wrapped_dek (ProfileCustodyWrappedDek)
previous_recovery_digest (str | None)
- create_profile_custody_recovery_envelope(*, profile_id, recovery_secret, dek, dek_epoch, kdf, recovery_generation=1, previous_recovery_digest=None, settings=None)[source]¶
Wrap
dekunderrecovery_secretthrough the supervised KDF owner.- Return type:
- Parameters:
- profile_custody_recovery_aad_for(*, profile_id, dek_epoch, recovery_generation, kdf, aad)[source]¶
Return the canonical associated data that binds a recovery wrapper to its capsule.
- class ProfileCustodyRecoveryUnlock(profile_id, dek_epoch, recovery_digest, dek)[source]¶
Bases:
objectA DEK accepted through the explicit recovery-only door.
- parse_profile_custody_recovery_envelope(value)[source]¶
Parse one canonical strict UTF-8 current-format recovery envelope.
- Return type:
- Parameters:
value (bytes)
- unlock_profile_custody_recovery_envelope(envelope, recovery_secret, *, sentinel, expected_profile_id, expected_dek_epoch, settings=None)[source]¶
Prove a committed recovery envelope against its named identity and sentinel.
The envelope is refused before any KDF work when it does not name the exact profile and DEK epoch of the capsule it sits in, so a wrapper copied from another capsule cannot become this one’s authority.
- Return type:
- Parameters:
envelope (ProfileCustodyRecoveryEnvelope)
recovery_secret (str)
sentinel (ProfileCustodySentinelRecord)
expected_profile_id (UUID)
expected_dek_epoch (str)
settings (Settings | None)