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