From d0c3bcd7c8e850105021333aec3499d0468b25aa Mon Sep 17 00:00:00 2001 From: disqualifier Date: Fri, 3 Jul 2026 16:46:20 -0400 Subject: [PATCH] refactor: hoist shared RSA-OAEP padding to a constant; restore encrypt_aes_key_with_rsa docstring hoists the byte-identical OAEP(MGF1(SHA256), SHA256, label=None) construction out of encrypt_aes_key_with_rsa and decrypt_aes_key_with_rsa into a module-level _OAEP_PADDING constant so a future scheme change lands in one place instead of two in lockstep. also restores encrypt_aes_key_with_rsa's Args/Returns/Raises docstring block, matching its four siblings, after Wave-1 over-stripped it to bare prose. Signed-off-by: disqualifier --- pyproject.toml | 2 +- src/envelope_crypto/envelope_crypto.py | 42 ++++++++++++++------------ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1b3018b..4ec1b15 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "envelope_crypto" -version = "0.1.8" +version = "0.1.9" description = "Envelope encryption (RSA-OAEP wrapped AES-256-GCM) for dict records — config-free, storage-agnostic, installable." requires-python = ">=3.10" dependencies = [ diff --git a/src/envelope_crypto/envelope_crypto.py b/src/envelope_crypto/envelope_crypto.py index 770472d..a189afd 100644 --- a/src/envelope_crypto/envelope_crypto.py +++ b/src/envelope_crypto/envelope_crypto.py @@ -36,6 +36,12 @@ from cryptography.hazmat.primitives.serialization import load_ssh_public_key _log = logging.getLogger(__name__) +_OAEP_PADDING = padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None, +) + def _password_mismatch_message(pw: Optional[bytes]) -> str: """clear ValueError text for a TypeError raised by a password/encryption mismatch""" @@ -263,10 +269,22 @@ class EnvelopeCrypto: def encrypt_aes_key_with_rsa( self, aes_key: bytes, rsa_key: str, is_file: bool = True ) -> Tuple[str, str]: - """wrap an AES key with an RSA public key; returns (fingerprint, wrapped_b64) + """wrap an AES key with an RSA public key - raises ValueError if rsa_key is not an RSA key (this lib is RSA-envelope only; - e.g. an Ed25519/EC key loads and fingerprints fine but cannot wrap). + Args: + aes_key: the AES data key to wrap. + rsa_key: path to (or, if is_file=False, raw PEM/OpenSSH data of) + the RSA public key to wrap with. + is_file: True (default) treats rsa_key as a path. + + Returns: + (fingerprint, wrapped_b64): the wrapping key's fingerprint and the + RSA-OAEP wrapped key, base64-encoded. + + Raises: + ValueError: rsa_key is not an RSA key (this lib is RSA-envelope + only; e.g. an Ed25519/EC key loads and fingerprints fine but + cannot wrap), or is malformed. """ if is_file: with open(rsa_key, "rb") as key_file: @@ -277,14 +295,7 @@ class EnvelopeCrypto: public_key = _load_public_key(key_data) _require_rsa(public_key) - wrapped = public_key.encrypt( - aes_key, - padding.OAEP( - mgf=padding.MGF1(algorithm=hashes.SHA256()), - algorithm=hashes.SHA256(), - label=None, - ), - ) + wrapped = public_key.encrypt(aes_key, _OAEP_PADDING) fingerprint = _fingerprint_of(public_key) wrapped_b64 = base64.b64encode(wrapped).decode() _log.info("wrapped data key for fingerprint %s", fingerprint[:8]) @@ -321,14 +332,7 @@ class EnvelopeCrypto: _require_rsa(private_key) wrapped = base64.b64decode(encrypted_key_base64) - aes_key = private_key.decrypt( - wrapped, - padding.OAEP( - mgf=padding.MGF1(algorithm=hashes.SHA256()), - algorithm=hashes.SHA256(), - label=None, - ), - ) + aes_key = private_key.decrypt(wrapped, _OAEP_PADDING) _log.info("unwrapped data key with RSA private key") return aes_key