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.

Return type:

str

Parameters:

value (str)

class ProfileCustodyRecoveryAad(**data)[source]

Bases: BaseModel

Closed 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'])

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, CustodyDigestModel

One 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_version to the current constant, computes self_digest from the assembled payload, then re-validates the whole record through pydantic.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:

ProfileCustodyRecoveryEnvelope

Parameters:
create_profile_custody_recovery_envelope(*, profile_id, recovery_secret, dek, dek_epoch, kdf, recovery_generation=1, previous_recovery_digest=None, settings=None)[source]

Wrap dek under recovery_secret through the supervised KDF owner.

Return type:

ProfileCustodyRecoveryEnvelope

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.

Return type:

bytes

Parameters:
class ProfileCustodyRecoveryUnlock(profile_id, dek_epoch, recovery_digest, dek)[source]

Bases: object

A DEK accepted through the explicit recovery-only door.

Parameters:
profile_id: UUID
dek_epoch: str
recovery_digest: str
dek: bytes
parse_profile_custody_recovery_envelope(value)[source]

Parse one canonical strict UTF-8 current-format recovery envelope.

Return type:

ProfileCustodyRecoveryEnvelope

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:

ProfileCustodyRecoveryUnlock

Parameters: