Source code for cadrumo.adapters.persistence.storage.crypto.aes_gcm
"""AES-256-GCM sealing with a fresh random nonce, on plain bytes.The one AES-GCM implementation. :mod:`.aead` wraps it in the typed:class:`~.aead.EncryptedBlob` record and the storage error hierarchy; thesupervised key-derivation child calls it directly. That child is started forevery wrap and unwrap, so this module imports only :mod:`cryptography` and thestandard library -- no pydantic, no error hierarchy -- and reports failures asthe builtin and :mod:`cryptography` exceptions its callers translate."""from__future__importannotationsimportsecretsfromtypingimportFinalfromcryptography.hazmat.primitives.ciphers.aeadimportAESGCMNONCE_SIZE:Final=12"""AES-256-GCM nonce size in bytes (per NIST SP 800-38D)."""GCM_TAG_SIZE:Final=16"""AES-256-GCM authentication-tag size in bytes."""KEY_SIZE:Final=32"""AES-256 key size in bytes."""def_cipher(key:bytes)->AESGCM:# ``AESGCM`` itself also accepts 128- and 192-bit keys, so the AES-256# requirement is enforced here rather than left to the library.iflen(key)!=KEY_SIZE:raiseValueError(f"AES-256-GCM key must be exactly {KEY_SIZE} bytes; got {len(key)}")returnAESGCM(key)
[docs]defseal(plaintext:bytes,*,key:bytes,associated_data:bytes|None=None)->tuple[bytes,bytes]:"""Encrypt ``plaintext`` under a fresh random nonce. Returns: ``(nonce, ciphertext_with_tag)``; the tag is the trailing :data:`GCM_TAG_SIZE` bytes. Raises: ValueError: If ``key`` is not exactly :data:`KEY_SIZE` bytes, or the underlying AEAD operation refuses its input. TypeError: If the underlying AEAD operation refuses its input type. """cipher=_cipher(key)nonce=secrets.token_bytes(NONCE_SIZE)returnnonce,cipher.encrypt(nonce,plaintext,associated_data)
[docs]defopen_sealed(nonce:bytes,ciphertext:bytes,*,key:bytes,associated_data:bytes|None=None)->bytes:"""Decrypt ``ciphertext`` (with its trailing tag) and verify it. Raises: cryptography.exceptions.InvalidTag: If authentication fails. ValueError: If ``key`` is not exactly :data:`KEY_SIZE` bytes, or the underlying AEAD operation refuses its input. TypeError: If the underlying AEAD operation refuses its input type. """return_cipher(key).decrypt(nonce,ciphertext,associated_data)