Source code for aeat.adapters.persistence.storage.sql._secure_object_crypto
"""Cryptographic hash helpers for SQL secure object revision metadata."""from__future__importannotationsfromdatetimeimportUTC,datetimefrom.....core.external_constantsimportUTF_8_ENCODINGfrom.....core.hashingimportsha256_hexdef_canonical_instant(value:datetime)->str:"""Return a round-trip-stable canonical form of an instant. The secure-object ``written_at`` column persists through SQLite as a timezone-naive value: a ``datetime.now(UTC)`` written as ``...+00:00`` reads back as the same wall instant with ``tzinfo`` dropped. Mixing the raw ``isoformat()`` into the revision id would therefore make the *recomputed* revision id (from the read-back, naive column) diverge from the *stored* one (derived at write from the aware value) — fail-closing valid rows on the read-time self-consistency gate. Canonicalising every instant to naive-UTC isoformat makes the write-time and read-time derivations identical. """aware=valueifvalue.tzinfoisnotNoneelsevalue.replace(tzinfo=UTC)returnaware.astimezone(UTC).replace(tzinfo=None).isoformat()
[docs]defderive_revision_id(*,namespace:str,object_key:bytes,schema_version:int,written_at:datetime,payload_hash:str,ciphertext_hash:str,previous_revision_id:str|None,previous_payload_hash:str|None,)->str:"""Derive a deterministic secure-object revision id from row metadata."""parts=(namespace,object_key.hex(),str(schema_version),_canonical_instant(written_at),payload_hash,ciphertext_hash,previous_revision_idor"",previous_payload_hashor"",)returnsha256_hex("\x1f".join(parts).encode(UTF_8_ENCODING))
[docs]defverify_revision_self_consistency(*,namespace:str,object_key:bytes,schema_version:int,written_at:datetime,revision_id:str|None,previous_revision_id:str|None,payload_hash:str|None,ciphertext_hash:str|None,previous_payload_hash:str|None,)->bool:"""Return whether a stored ``revision_id`` recomputes from its lineage columns. The revision id is a content address over the whole revision-lineage metadata tuple (namespace, object-key digest, schema version, ``written_at``, ``payload_hash``, ``ciphertext_hash``, and the previous revision/payload-hash links). Recomputing it from the stored columns and comparing to the stored ``revision_id`` is a read-time integrity gate: a tamper of any single lineage column — including ``payload_hash`` — that does not also recompute ``revision_id`` is detected and can be failed closed. The check is purely metadata-internal (it never touches the encrypted payload bytes), so it does not interfere with the AEAD payload authentication or with corruption probes that re-encrypt a mutated payload without restamping the metadata. A row written without revision metadata (``revision_id is None``) carries nothing to verify and is reported consistent. A row whose ``revision_id`` is present but whose required hash inputs are absent is inconsistent. """ifrevision_idisNone:returnTrueifpayload_hashisNoneorciphertext_hashisNone:returnFalserecomputed=derive_revision_id(namespace=namespace,object_key=object_key,schema_version=schema_version,written_at=written_at,payload_hash=payload_hash,ciphertext_hash=ciphertext_hash,previous_revision_id=previous_revision_id,previous_payload_hash=previous_payload_hash,)returnrecomputed==revision_id