diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2014-06-06 21:05:23 -0500 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2014-06-12 09:41:18 -0500 |
commit | 6af3c6ed6955030208ecfc09e02492de47c1fa10 (patch) | |
tree | 13b1bb608a05930580adc5e8ea5c68d11c524c96 | |
parent | d19e1f04b32bf95be2302d19abf56b3d07774124 (diff) | |
download | cryptography-6af3c6ed6955030208ecfc09e02492de47c1fa10.tar.gz cryptography-6af3c6ed6955030208ecfc09e02492de47c1fa10.tar.bz2 cryptography-6af3c6ed6955030208ecfc09e02492de47c1fa10.zip |
backend specific RSA*Key implementation for OpenSSL
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 264 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/asymmetric/rsa.py | 2 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_rsa.py | 946 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_serialization.py | 56 | ||||
-rw-r--r-- | tests/hazmat/primitives/utils.py | 32 |
5 files changed, 762 insertions, 538 deletions
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index ab3f9471..770b2af4 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -41,6 +41,9 @@ from cryptography.hazmat.primitives.ciphers.algorithms import ( from cryptography.hazmat.primitives.ciphers.modes import ( CBC, CFB, CFB8, CTR, ECB, GCM, OFB ) +from cryptography.hazmat.primitives.interfaces import ( + RSAPrivateKeyWithNumbers, RSAPublicKeyWithNumbers +) _MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"]) @@ -374,27 +377,34 @@ class Backend(object): return self._rsa_cdata_to_private_key(ctx) + def _generate_rsa_private_key(self, public_exponent, key_size): + rsa._verify_rsa_parameters(public_exponent, key_size) + + rsa_cdata = self._lib.RSA_new() + assert rsa_cdata != self._ffi.NULL + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + + bn = self._int_to_bn(public_exponent) + bn = self._ffi.gc(bn, self._lib.BN_free) + + res = self._lib.RSA_generate_key_ex( + rsa_cdata, key_size, bn, self._ffi.NULL + ) + assert res == 1 + + return _RSAPrivateKey(self, rsa_cdata) + def generate_rsa_parameters_supported(self, public_exponent, key_size): return (public_exponent >= 3 and public_exponent & 1 != 0 and key_size >= 512) def load_rsa_private_numbers(self, numbers): - return rsa.RSAPrivateKey( - p=numbers.p, - q=numbers.q, - private_exponent=numbers.d, - dmp1=numbers.dmp1, - dmq1=numbers.dmq1, - iqmp=numbers.iqmp, - public_exponent=numbers.public_numbers.e, - modulus=numbers.public_numbers.n - ) + rsa_cdata = self._rsa_cdata_from_private_numbers(numbers) + return _RSAPrivateKey(self, rsa_cdata) def load_rsa_public_numbers(self, numbers): - return rsa.RSAPublicKey( - public_exponent=numbers.e, - modulus=numbers.n - ) + rsa_cdata = self._rsa_cdata_from_public_numbers(numbers) + return _RSAPublicKey(self, rsa_cdata) def _new_evp_pkey(self): evp_pkey = self._lib.EVP_PKEY_new() @@ -445,8 +455,7 @@ class Backend(object): if type == self._lib.EVP_PKEY_RSA: rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) assert rsa_cdata != self._ffi.NULL - rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) - return self._rsa_cdata_to_private_key(rsa_cdata) + return _RSAPrivateKey(self, rsa_cdata) elif type == self._lib.EVP_PKEY_DSA: dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) assert dsa_cdata != self._ffi.NULL @@ -538,12 +547,47 @@ class Backend(object): return ctx + def _rsa_cdata_from_private_numbers(self, private_numbers): + # Does not GC the RSA cdata. You *must* make sure it's freed + # correctly yourself! + ctx = self._lib.RSA_new() + assert ctx != self._ffi.NULL + ctx.p = self._int_to_bn(private_numbers.p) + ctx.q = self._int_to_bn(private_numbers.q) + ctx.d = self._int_to_bn(private_numbers.d) + ctx.dmp1 = self._int_to_bn(private_numbers.dmp1) + ctx.dmq1 = self._int_to_bn(private_numbers.dmq1) + ctx.iqmp = self._int_to_bn(private_numbers.iqmp) + ctx.e = self._int_to_bn(private_numbers.public_numbers.e) + ctx.n = self._int_to_bn(private_numbers.public_numbers.n) + res = self._lib.RSA_blinding_on(ctx, self._ffi.NULL) + assert res == 1 + + return ctx + + def _rsa_cdata_from_public_numbers(self, public_numbers): + # Does not GC the RSA cdata. You *must* make sure it's freed + # correctly yourself! + + ctx = self._lib.RSA_new() + assert ctx != self._ffi.NULL + ctx.e = self._int_to_bn(public_numbers.e) + ctx.n = self._int_to_bn(public_numbers.n) + res = self._lib.RSA_blinding_on(ctx, self._ffi.NULL) + assert res == 1 + + return ctx + def create_rsa_signature_ctx(self, private_key, padding, algorithm): - return _RSASignatureContext(self, private_key, padding, algorithm) + rsa_cdata = self._rsa_cdata_from_private_key(private_key) + key = _RSAPrivateKey(self, rsa_cdata) + return _RSASignatureContext(self, key, padding, algorithm) def create_rsa_verification_ctx(self, public_key, signature, padding, algorithm): - return _RSAVerificationContext(self, public_key, signature, padding, + rsa_cdata = self._rsa_cdata_from_public_key(public_key) + key = _RSAPublicKey(self, rsa_cdata) + return _RSAVerificationContext(self, key, signature, padding, algorithm) def mgf1_hash_supported(self, algorithm): @@ -704,13 +748,18 @@ class Backend(object): def _enc_dec_rsa_pkey_ctx(self, key, data, padding_enum): if isinstance(key, rsa.RSAPublicKey): + evp_pkey = self._rsa_public_key_to_evp_pkey(key) + elif isinstance(key, rsa.RSAPrivateKey): + evp_pkey = self._rsa_private_key_to_evp_pkey(key) + else: + evp_pkey = key._evp_pkey + + if isinstance(key, (rsa.RSAPublicKey, _RSAPublicKey)): init = self._lib.EVP_PKEY_encrypt_init crypt = self._lib.Cryptography_EVP_PKEY_encrypt - evp_pkey = self._rsa_public_key_to_evp_pkey(key) else: init = self._lib.EVP_PKEY_decrypt_init crypt = self._lib.Cryptography_EVP_PKEY_decrypt - evp_pkey = self._rsa_private_key_to_evp_pkey(key) pkey_ctx = self._lib.EVP_PKEY_CTX_new( evp_pkey, self._ffi.NULL @@ -740,13 +789,19 @@ class Backend(object): def _enc_dec_rsa_098(self, key, data, padding_enum): if isinstance(key, rsa.RSAPublicKey): - crypt = self._lib.RSA_public_encrypt rsa_cdata = self._rsa_cdata_from_public_key(key) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + elif isinstance(key, rsa.RSAPrivateKey): + rsa_cdata = self._rsa_cdata_from_private_key(key) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + else: + rsa_cdata = key._rsa_cdata + + if isinstance(key, (rsa.RSAPublicKey, _RSAPublicKey)): + crypt = self._lib.RSA_public_encrypt else: crypt = self._lib.RSA_private_decrypt - rsa_cdata = self._rsa_cdata_from_private_key(key) - rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) key_size = self._lib.RSA_size(rsa_cdata) assert key_size > 0 buf = self._ffi.new("unsigned char[]", key_size) @@ -766,7 +821,7 @@ class Backend(object): errors = self._consume_errors() assert errors assert errors[0].lib == self._lib.ERR_LIB_RSA - if isinstance(key, rsa.RSAPublicKey): + if isinstance(key, (_RSAPublicKey, rsa.RSAPublicKey)): assert (errors[0].reason == self._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE) raise ValueError( @@ -1468,6 +1523,10 @@ class _RSASignatureContext(object): raise TypeError( "Expected provider of interfaces.AsymmetricPadding.") + self.pkey_size = self._backend._lib.EVP_PKEY_size( + self._private_key._evp_pkey + ) + if isinstance(padding, PKCS1v15): if self._backend._lib.Cryptography_HAS_PKEY_CTX: self._finalize_method = self._finalize_pkey_ctx @@ -1483,8 +1542,8 @@ class _RSASignatureContext(object): # Size of key in bytes - 2 is the maximum # PSS signature length (salt length is checked later) - key_size_bytes = int(math.ceil(private_key.key_size / 8.0)) - if key_size_bytes - algorithm.digest_size - 2 < 0: + assert self.pkey_size > 0 + if self.pkey_size - algorithm.digest_size - 2 < 0: raise ValueError("Digest too large for key size. Use a larger " "key.") @@ -1514,20 +1573,15 @@ class _RSASignatureContext(object): self._hash_ctx.update(data) def finalize(self): - evp_pkey = self._backend._rsa_private_key_to_evp_pkey( - self._private_key) - evp_md = self._backend._lib.EVP_get_digestbyname( self._algorithm.name.encode("ascii")) assert evp_md != self._backend._ffi.NULL - pkey_size = self._backend._lib.EVP_PKEY_size(evp_pkey) - assert pkey_size > 0 - return self._finalize_method(evp_pkey, pkey_size, evp_md) + return self._finalize_method(evp_md) - def _finalize_pkey_ctx(self, evp_pkey, pkey_size, evp_md): + def _finalize_pkey_ctx(self, evp_md): pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new( - evp_pkey, self._backend._ffi.NULL + self._private_key._evp_pkey, self._backend._ffi.NULL ) assert pkey_ctx != self._backend._ffi.NULL pkey_ctx = self._backend._ffi.gc(pkey_ctx, @@ -1590,17 +1644,17 @@ class _RSASignatureContext(object): return self._backend._ffi.buffer(buf)[:] - def _finalize_pkcs1(self, evp_pkey, pkey_size, evp_md): + def _finalize_pkcs1(self, evp_md): if self._hash_ctx._ctx is None: raise AlreadyFinalized("Context has already been finalized.") - sig_buf = self._backend._ffi.new("char[]", pkey_size) + sig_buf = self._backend._ffi.new("char[]", self.pkey_size) sig_len = self._backend._ffi.new("unsigned int *") res = self._backend._lib.EVP_SignFinal( self._hash_ctx._ctx._ctx, sig_buf, sig_len, - evp_pkey + self._private_key._evp_pkey ) self._hash_ctx.finalize() if res == 0: @@ -1613,15 +1667,11 @@ class _RSASignatureContext(object): return self._backend._ffi.buffer(sig_buf)[:sig_len[0]] - def _finalize_pss(self, evp_pkey, pkey_size, evp_md): + def _finalize_pss(self, evp_md): data_to_sign = self._hash_ctx.finalize() - padded = self._backend._ffi.new("unsigned char[]", pkey_size) - rsa_cdata = self._backend._lib.EVP_PKEY_get1_RSA(evp_pkey) - assert rsa_cdata != self._backend._ffi.NULL - rsa_cdata = self._backend._ffi.gc(rsa_cdata, - self._backend._lib.RSA_free) + padded = self._backend._ffi.new("unsigned char[]", self.pkey_size) res = self._backend._lib.RSA_padding_add_PKCS1_PSS( - rsa_cdata, + self._private_key._rsa_cdata, padded, data_to_sign, evp_md, @@ -1639,12 +1689,12 @@ class _RSASignatureContext(object): raise ValueError("Salt length too long for key size. Try using " "MAX_LENGTH instead.") - sig_buf = self._backend._ffi.new("char[]", pkey_size) + sig_buf = self._backend._ffi.new("char[]", self.pkey_size) sig_len = self._backend._lib.RSA_private_encrypt( - pkey_size, + self.pkey_size, padded, sig_buf, - rsa_cdata, + self._private_key._rsa_cdata, self._backend._lib.RSA_NO_PADDING ) assert sig_len != -1 @@ -1662,6 +1712,10 @@ class _RSAVerificationContext(object): raise TypeError( "Expected provider of interfaces.AsymmetricPadding.") + self.pkey_size = self._backend._lib.EVP_PKEY_size( + self._public_key._evp_pkey + ) + if isinstance(padding, PKCS1v15): if self._backend._lib.Cryptography_HAS_PKEY_CTX: self._verify_method = self._verify_pkey_ctx @@ -1677,8 +1731,8 @@ class _RSAVerificationContext(object): # Size of key in bytes - 2 is the maximum # PSS signature length (salt length is checked later) - key_size_bytes = int(math.ceil(public_key.key_size / 8.0)) - if key_size_bytes - algorithm.digest_size - 2 < 0: + assert self.pkey_size > 0 + if self.pkey_size - algorithm.digest_size - 2 < 0: raise ValueError( "Digest too large for key size. Check that you have the " "correct key and digest algorithm." @@ -1710,18 +1764,15 @@ class _RSAVerificationContext(object): self._hash_ctx.update(data) def verify(self): - evp_pkey = self._backend._rsa_public_key_to_evp_pkey( - self._public_key) - evp_md = self._backend._lib.EVP_get_digestbyname( self._algorithm.name.encode("ascii")) assert evp_md != self._backend._ffi.NULL - self._verify_method(evp_pkey, evp_md) + self._verify_method(evp_md) - def _verify_pkey_ctx(self, evp_pkey, evp_md): + def _verify_pkey_ctx(self, evp_md): pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new( - evp_pkey, self._backend._ffi.NULL + self._public_key._evp_pkey, self._backend._ffi.NULL ) assert pkey_ctx != self._backend._ffi.NULL pkey_ctx = self._backend._ffi.gc(pkey_ctx, @@ -1772,7 +1823,7 @@ class _RSAVerificationContext(object): assert errors raise InvalidSignature - def _verify_pkcs1(self, evp_pkey, evp_md): + def _verify_pkcs1(self, evp_md): if self._hash_ctx._ctx is None: raise AlreadyFinalized("Context has already been finalized.") @@ -1780,7 +1831,7 @@ class _RSAVerificationContext(object): self._hash_ctx._ctx._ctx, self._signature, len(self._signature), - evp_pkey + self._public_key._evp_pkey ) self._hash_ctx.finalize() # The previous call can return negative numbers in the event of an @@ -1792,29 +1843,23 @@ class _RSAVerificationContext(object): assert errors raise InvalidSignature - def _verify_pss(self, evp_pkey, evp_md): - pkey_size = self._backend._lib.EVP_PKEY_size(evp_pkey) - assert pkey_size > 0 - rsa_cdata = self._backend._lib.EVP_PKEY_get1_RSA(evp_pkey) - assert rsa_cdata != self._backend._ffi.NULL - rsa_cdata = self._backend._ffi.gc(rsa_cdata, - self._backend._lib.RSA_free) - buf = self._backend._ffi.new("unsigned char[]", pkey_size) + def _verify_pss(self, evp_md): + buf = self._backend._ffi.new("unsigned char[]", self.pkey_size) res = self._backend._lib.RSA_public_decrypt( len(self._signature), self._signature, buf, - rsa_cdata, + self._public_key._rsa_cdata, self._backend._lib.RSA_NO_PADDING ) - if res != pkey_size: + if res != self.pkey_size: errors = self._backend._consume_errors() assert errors raise InvalidSignature data_to_verify = self._hash_ctx.finalize() res = self._backend._lib.RSA_verify_PKCS1_PSS( - rsa_cdata, + self._public_key._rsa_cdata, data_to_verify, evp_md, buf, @@ -2110,4 +2155,87 @@ class _EllipticCurvePublicKey(object): _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) +@utils.register_interface(RSAPrivateKeyWithNumbers) +class _RSAPrivateKey(object): + def __init__(self, backend, rsa_cdata): + self._backend = backend + self._rsa_cdata = self._backend._ffi.gc( + rsa_cdata, self._backend._lib.RSA_free + ) + + evp_pkey = self._backend._lib.EVP_PKEY_new() + assert evp_pkey != self._backend._ffi.NULL + evp_pkey = self._backend._ffi.gc( + evp_pkey, self._backend._lib.EVP_PKEY_free + ) + res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata) + assert res == 1 + self._evp_pkey = evp_pkey + + self.key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n) + + def signer(self, padding, algorithm): + return _RSASignatureContext(self._backend, self, padding, algorithm) + + def decrypt(self, ciphertext, padding): + return self._backend.decrypt_rsa(self, ciphertext, padding) + + def public_key(self): + ctx = self._backend._lib.RSA_new() + assert ctx != self._backend._ffi.NULL + ctx.e = self._backend._lib.BN_dup(self._rsa_cdata.e) + ctx.n = self._backend._lib.BN_dup(self._rsa_cdata.n) + res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL) + assert res == 1 + return _RSAPublicKey(self._backend, ctx) + + def private_numbers(self): + return rsa.RSAPrivateNumbers( + p=self._backend._bn_to_int(self._rsa_cdata.p), + q=self._backend._bn_to_int(self._rsa_cdata.q), + d=self._backend._bn_to_int(self._rsa_cdata.d), + dmp1=self._backend._bn_to_int(self._rsa_cdata.dmp1), + dmq1=self._backend._bn_to_int(self._rsa_cdata.dmq1), + iqmp=self._backend._bn_to_int(self._rsa_cdata.iqmp), + public_numbers=rsa.RSAPublicNumbers( + e=self._backend._bn_to_int(self._rsa_cdata.e), + n=self._backend._bn_to_int(self._rsa_cdata.n), + ) + ) + + +@utils.register_interface(RSAPublicKeyWithNumbers) +class _RSAPublicKey(object): + def __init__(self, backend, rsa_cdata): + self._backend = backend + self._rsa_cdata = self._backend._ffi.gc( + rsa_cdata, self._backend._lib.RSA_free + ) + + evp_pkey = self._backend._lib.EVP_PKEY_new() + assert evp_pkey != self._backend._ffi.NULL + evp_pkey = self._backend._ffi.gc( + evp_pkey, self._backend._lib.EVP_PKEY_free + ) + res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata) + assert res == 1 + self._evp_pkey = evp_pkey + + self.key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n) + + def verifier(self, signature, padding, algorithm): + return _RSAVerificationContext( + self._backend, self, signature, padding, algorithm + ) + + def encrypt(self, plaintext, padding): + return self._backend.encrypt_rsa(self, plaintext, padding) + + def public_numbers(self): + return rsa.RSAPublicNumbers( + e=self._backend._bn_to_int(self._rsa_cdata.e), + n=self._backend._bn_to_int(self._rsa_cdata.n), + ) + + backend = Backend() diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py index be7edad3..dee2d7a5 100644 --- a/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -29,7 +29,7 @@ def generate_private_key(public_exponent, key_size, backend): ) _verify_rsa_parameters(public_exponent, key_size) - return backend.generate_rsa_private_key(public_exponent, key_size) + return backend._generate_rsa_private_key(public_exponent, key_size) def _verify_rsa_parameters(public_exponent, key_size): diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 8f10fb10..4dd34c2b 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -28,7 +28,7 @@ from cryptography.exceptions import ( from cryptography.hazmat.primitives import hashes, interfaces from cryptography.hazmat.primitives.asymmetric import padding, rsa from cryptography.hazmat.primitives.serialization import ( - load_rsa_private_numbers + load_rsa_private_numbers, load_rsa_public_numbers ) from .fixtures_rsa import ( @@ -38,7 +38,7 @@ from .fixtures_rsa import ( RSA_KEY_768, ) from .utils import ( - _check_rsa_private_key, generate_rsa_verification_test + _check_rsa_private_numbers, generate_rsa_verification_test ) from ...utils import ( load_pkcs1_vectors, load_rsa_nist_vectors, load_vectors_from_file, @@ -98,13 +98,11 @@ class TestRSA(object): ) def test_generate_rsa_keys(self, backend, public_exponent, key_size): skey = rsa.generate_private_key(public_exponent, key_size, backend) - _check_rsa_private_key(skey) + assert skey assert skey.key_size == key_size - assert skey.public_exponent == public_exponent def test_generate_rsa_key_class_method(self, backend): skey = rsa.RSAPrivateKey.generate(65537, 512, backend) - _check_rsa_private_key(skey) assert skey.key_size == 512 assert skey.public_exponent == 65537 @@ -141,255 +139,31 @@ class TestRSA(object): def test_load_pss_vect_example_keys(self, pkcs1_example): secret, public = pkcs1_example - skey = rsa.RSAPrivateKey( + private_num = rsa.RSAPrivateNumbers( p=secret["p"], q=secret["q"], - private_exponent=secret["private_exponent"], + d=secret["private_exponent"], dmp1=secret["dmp1"], dmq1=secret["dmq1"], iqmp=secret["iqmp"], - public_exponent=secret["public_exponent"], - modulus=secret["modulus"] + public_numbers=rsa.RSAPublicNumbers( + e=secret["public_exponent"], + n=secret["modulus"] + ) ) - assert skey - _check_rsa_private_key(skey) + _check_rsa_private_numbers(private_num) - pkey = rsa.RSAPublicKey( - public_exponent=public["public_exponent"], - modulus=public["modulus"] + public_num = rsa.RSAPublicNumbers( + e=public["public_exponent"], + n=public["modulus"] ) - assert pkey - - pkey2 = skey.public_key() - assert pkey2 - - assert skey.modulus == pkey.modulus - assert skey.modulus == skey.n - assert skey.public_exponent == pkey.public_exponent - assert skey.public_exponent == skey.e - assert skey.private_exponent == skey.d - - assert pkey.modulus - assert pkey.modulus == pkey2.modulus - assert pkey.modulus == pkey.n - assert pkey.public_exponent == pkey2.public_exponent - assert pkey.public_exponent == pkey.e - - assert skey.key_size - assert skey.key_size == pkey.key_size - assert skey.key_size == pkey2.key_size - - def test_invalid_private_key_argument_types(self): - with pytest.raises(TypeError): - rsa.RSAPrivateKey(None, None, None, None, None, None, None, None) - - def test_invalid_public_key_argument_types(self): - with pytest.raises(TypeError): - rsa.RSAPublicKey(None, None) - - def test_invalid_private_key_argument_values(self): - # Start with p=3, q=11, private_exponent=3, public_exponent=7, - # modulus=33, dmp1=1, dmq1=3, iqmp=2. Then change one value at - # a time to test the bounds. - - # Test a modulus < 3. - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_exponent=7, - modulus=2 - ) - - # Test a modulus != p * q. - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_exponent=7, - modulus=35 - ) - - # Test a p > modulus. - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=37, - q=11, - private_exponent=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_exponent=7, - modulus=33 - ) - - # Test a q > modulus. - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=37, - private_exponent=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_exponent=7, - modulus=33 - ) - - # Test a dmp1 > modulus. - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=3, - dmp1=35, - dmq1=3, - iqmp=2, - public_exponent=7, - modulus=33 - ) - - # Test a dmq1 > modulus. - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=3, - dmp1=1, - dmq1=35, - iqmp=2, - public_exponent=7, - modulus=33 - ) - - # Test an iqmp > modulus. - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=3, - dmp1=1, - dmq1=3, - iqmp=35, - public_exponent=7, - modulus=33 - ) - - # Test a private_exponent > modulus - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=37, - dmp1=1, - dmq1=3, - iqmp=2, - public_exponent=7, - modulus=33 - ) - - # Test a public_exponent < 3 - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_exponent=1, - modulus=33 - ) - - # Test a public_exponent > modulus - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_exponent=65537, - modulus=33 - ) - - # Test a public_exponent that is not odd. - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_exponent=6, - modulus=33 - ) - - # Test a dmp1 that is not odd. - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=3, - dmp1=2, - dmq1=3, - iqmp=2, - public_exponent=7, - modulus=33 - ) - - # Test a dmq1 that is not odd. - with pytest.raises(ValueError): - rsa.RSAPrivateKey( - p=3, - q=11, - private_exponent=3, - dmp1=1, - dmq1=4, - iqmp=2, - public_exponent=7, - modulus=33 - ) - - def test_invalid_public_key_argument_values(self): - # Start with public_exponent=7, modulus=15. Then change one value at a - # time to test the bounds. - - # Test a modulus < 3. - with pytest.raises(ValueError): - rsa.RSAPublicKey(public_exponent=7, modulus=2) + assert public_num - # Test a public_exponent < 3 - with pytest.raises(ValueError): - rsa.RSAPublicKey(public_exponent=1, modulus=15) + public_num2 = private_num.public_numbers + assert public_num2 - # Test a public_exponent > modulus - with pytest.raises(ValueError): - rsa.RSAPublicKey(public_exponent=17, modulus=15) - - # Test a public_exponent that is not odd. - with pytest.raises(ValueError): - rsa.RSAPublicKey(public_exponent=6, modulus=15) - - -def test_rsa_generate_invalid_backend(): - pretend_backend = object() - - with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - rsa.generate_private_key(65537, 2048, pretend_backend) - - with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - rsa.RSAPrivateKey.generate(65537, 2048, pretend_backend) + assert public_num.n == public_num2.n + assert public_num.e == public_num2.e @pytest.mark.rsa @@ -410,17 +184,20 @@ class TestRSASignature(object): ) def test_pkcs1v15_signing(self, pkcs1_example, backend): private, public, example = pkcs1_example - private_key = rsa.RSAPrivateKey( + private_numbers = rsa.RSAPrivateNumbers( p=private["p"], q=private["q"], - private_exponent=private["private_exponent"], + d=private["private_exponent"], dmp1=private["dmp1"], dmq1=private["dmq1"], iqmp=private["iqmp"], - public_exponent=private["public_exponent"], - modulus=private["modulus"] + public_numbers=rsa.RSAPublicNumbers( + e=private["public_exponent"], + n=private["modulus"] + ) ) - signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1(), backend) + private_key = load_rsa_private_numbers(private_numbers, backend) + signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) signer.update(binascii.unhexlify(example["message"])) signature = signer.finalize() assert binascii.hexlify(signature) == example["signature"] @@ -444,27 +221,30 @@ class TestRSASignature(object): ) def test_pss_signing(self, pkcs1_example, backend): private, public, example = pkcs1_example - private_key = rsa.RSAPrivateKey( + private_numbers = rsa.RSAPrivateNumbers( p=private["p"], q=private["q"], - private_exponent=private["private_exponent"], + d=private["private_exponent"], dmp1=private["dmp1"], dmq1=private["dmq1"], iqmp=private["iqmp"], - public_exponent=private["public_exponent"], - modulus=private["modulus"] + public_numbers=rsa.RSAPublicNumbers( + e=private["public_exponent"], + n=private["modulus"] + ) ) - public_key = rsa.RSAPublicKey( - public_exponent=public["public_exponent"], - modulus=public["modulus"] + public_numbers = rsa.RSAPublicNumbers( + e=public["public_exponent"], + n=public["modulus"] ) + private_key = load_rsa_private_numbers(private_numbers, backend) + public_key = load_rsa_public_numbers(public_numbers, backend) signer = private_key.signer( padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), - hashes.SHA1(), - backend + hashes.SHA1() ) signer.update(binascii.unhexlify(example["message"])) signature = signer.finalize() @@ -478,8 +258,7 @@ class TestRSASignature(object): mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(binascii.unhexlify(example["message"])) verifier.verify() @@ -504,8 +283,7 @@ class TestRSASignature(object): salt_length=padding.MGF1.MAX_LENGTH ) ), - hashes.SHA1(), - backend + hashes.SHA1() ) signer.update(b"so deprecated") signature = signer.finalize() @@ -520,8 +298,7 @@ class TestRSASignature(object): salt_length=padding.MGF1.MAX_LENGTH ) ), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(b"so deprecated") verifier.verify() @@ -546,19 +323,10 @@ class TestRSASignature(object): mgf=padding.MGF1(hash_alg), salt_length=padding.PSS.MAX_LENGTH ) - signer = private_key.signer( - pss, - hash_alg, - backend - ) + signer = private_key.signer(pss, hash_alg) signer.update(b"testing signature") signature = signer.finalize() - verifier = public_key.verifier( - signature, - pss, - hash_alg, - backend - ) + verifier = public_key.verifier(signature, pss, hash_alg) verifier.update(b"testing signature") verifier.verify() @@ -581,8 +349,7 @@ class TestRSASignature(object): mgf=padding.MGF1(hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), - hashes.SHA512(), - backend + hashes.SHA512() ) signer.update(b"no failure") signer.finalize() @@ -608,8 +375,7 @@ class TestRSASignature(object): mgf=padding.MGF1(hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), - hashes.SHA512(), - backend + hashes.SHA512() ) @pytest.mark.supported( @@ -628,8 +394,7 @@ class TestRSASignature(object): mgf=padding.MGF1(hashes.SHA1()), salt_length=1000000 ), - hashes.SHA1(), - backend + hashes.SHA1() ) signer.update(b"failure coming") with pytest.raises(ValueError): @@ -643,7 +408,7 @@ class TestRSASignature(object): ) def test_use_after_finalize(self, backend): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) - signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1(), backend) + signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) signer.update(b"sign me") signer.finalize() with pytest.raises(AlreadyFinalized): @@ -654,20 +419,12 @@ class TestRSASignature(object): def test_unsupported_padding(self, backend): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): - private_key.signer(DummyPadding(), hashes.SHA1(), backend) + private_key.signer(DummyPadding(), hashes.SHA1()) def test_padding_incorrect_type(self, backend): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) with pytest.raises(TypeError): - private_key.signer("notpadding", hashes.SHA1(), backend) - - def test_rsa_signer_invalid_backend(self, backend): - pretend_backend = object() - private_key = load_rsa_private_numbers(RSA_KEY_2048, backend) - - with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - private_key.signer( - padding.PKCS1v15(), hashes.SHA256, pretend_backend) + private_key.signer("notpadding", hashes.SHA1()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -678,8 +435,7 @@ class TestRSASignature(object): def test_unsupported_pss_mgf(self, backend): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF): - private_key.signer(padding.PSS(mgf=DummyMGF()), hashes.SHA1(), - backend) + private_key.signer(padding.PSS(mgf=DummyMGF()), hashes.SHA1()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -691,8 +447,7 @@ class TestRSASignature(object): private_key = load_rsa_private_numbers(RSA_KEY_599, backend) signer = private_key.signer( padding.PKCS1v15(), - hashes.SHA512(), - backend + hashes.SHA512() ) signer.update(b"failure coming") with pytest.raises(ValueError): @@ -706,11 +461,7 @@ class TestRSASignature(object): ) def test_pkcs1_minimum_key_size(self, backend): private_key = load_rsa_private_numbers(RSA_KEY_745, backend) - signer = private_key.signer( - padding.PKCS1v15(), - hashes.SHA512(), - backend - ) + signer = private_key.signer(padding.PKCS1v15(), hashes.SHA512()) signer.update(b"no failure") signer.finalize() @@ -733,15 +484,15 @@ class TestRSAVerification(object): ) def test_pkcs1v15_verification(self, pkcs1_example, backend): private, public, example = pkcs1_example - public_key = rsa.RSAPublicKey( - public_exponent=public["public_exponent"], - modulus=public["modulus"] + public_numbers = rsa.RSAPublicNumbers( + e=public["public_exponent"], + n=public["modulus"] ) + public_key = load_rsa_public_numbers(public_numbers, backend) verifier = public_key.verifier( binascii.unhexlify(example["signature"]), padding.PKCS1v15(), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(binascii.unhexlify(example["message"])) verifier.verify() @@ -755,14 +506,13 @@ class TestRSAVerification(object): def test_invalid_pkcs1v15_signature_wrong_data(self, backend): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) public_key = private_key.public_key() - signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1(), backend) + signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) signer.update(b"sign me") signature = signer.finalize() verifier = public_key.verifier( signature, padding.PKCS1v15(), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(b"incorrect data") with pytest.raises(InvalidSignature): @@ -778,14 +528,13 @@ class TestRSAVerification(object): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) private_key2 = load_rsa_private_numbers(RSA_KEY_512_ALT, backend) public_key = private_key2.public_key() - signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1(), backend) + signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) signer.update(b"sign me") signature = signer.finalize() verifier = public_key.verifier( signature, padding.PKCS1v15(), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(b"sign me") with pytest.raises(InvalidSignature): @@ -810,18 +559,18 @@ class TestRSAVerification(object): ) def test_pss_verification(self, pkcs1_example, backend): private, public, example = pkcs1_example - public_key = rsa.RSAPublicKey( - public_exponent=public["public_exponent"], - modulus=public["modulus"] + public_numbers = rsa.RSAPublicNumbers( + e=public["public_exponent"], + n=public["modulus"] ) + public_key = load_rsa_public_numbers(public_numbers, backend) verifier = public_key.verifier( binascii.unhexlify(example["signature"]), padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=20 ), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(binascii.unhexlify(example["message"])) verifier.verify() @@ -836,26 +585,26 @@ class TestRSAVerification(object): skip_message="Does not support PSS." ) def test_invalid_pss_signature_wrong_data(self, backend): - public_key = rsa.RSAPublicKey( - modulus=int( + public_numbers = rsa.RSAPublicNumbers( + n=int( b"dffc2137d5e810cde9e4b4612f5796447218bab913b3fa98bdf7982e4fa6" b"ec4d6653ef2b29fb1642b095befcbea6decc178fb4bed243d3c3592c6854" b"6af2d3f3", 16 ), - public_exponent=65537 + e=65537 ) signature = binascii.unhexlify( b"0e68c3649df91c5bc3665f96e157efa75b71934aaa514d91e94ca8418d100f45" b"6f05288e58525f99666bab052adcffdf7186eb40f583bd38d98c97d3d524808b" ) + public_key = load_rsa_public_numbers(public_numbers, backend) verifier = public_key.verifier( signature, padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(b"incorrect data") with pytest.raises(InvalidSignature): @@ -875,24 +624,24 @@ class TestRSAVerification(object): b"3a1880165014ba6eb53cc1449d13e5132ebcc0cfd9ade6d7a2494a0503bd0826" b"f8a46c431e0d7be0ca3e453f8b2b009e2733764da7927cc6dbe7a021437a242e" ) - public_key = rsa.RSAPublicKey( - modulus=int( + public_numbers = rsa.RSAPublicNumbers( + n=int( b"381201f4905d67dfeb3dec131a0fbea773489227ec7a1448c3109189ac68" b"5a95441be90866a14c4d2e139cd16db540ec6c7abab13ffff91443fd46a8" b"960cbb7658ded26a5c95c86f6e40384e1c1239c63e541ba221191c4dd303" b"231b42e33c6dbddf5ec9a746f09bf0c25d0f8d27f93ee0ae5c0d723348f4" b"030d3581e13522e1", 16 ), - public_exponent=65537 + e=65537 ) + public_key = load_rsa_public_numbers(public_numbers, backend) verifier = public_key.verifier( signature, padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(b"sign me") with pytest.raises(InvalidSignature): @@ -912,24 +661,24 @@ class TestRSAVerification(object): b"cb43bde4f7ab89eb4a79c6e8dd67e0d1af60715da64429d90c716a490b799c29" b"194cf8046509c6ed851052367a74e2e92d9b38947ed74332acb115a03fcc0222" ) - public_key = rsa.RSAPublicKey( - modulus=int( + public_numbers = rsa.RSAPublicNumbers( + n=int( b"381201f4905d67dfeb3dec131a0fbea773489227ec7a1448c3109189ac68" b"5a95441be90866a14c4d2e139cd16db540ec6c7abab13ffff91443fd46a8" b"960cbb7658ded26a5c95c86f6e40384e1c1239c63e541ba221191c4dd303" b"231b42e33c6dbddf5ec9a746f09bf0c25d0f8d27f93ee0ae5c0d723348f4" b"030d3581e13522", 16 ), - public_exponent=65537 + e=65537 ) + public_key = load_rsa_public_numbers(public_numbers, backend) verifier = public_key.verifier( signature, padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(b"sign me") with pytest.raises(InvalidSignature): @@ -944,15 +693,14 @@ class TestRSAVerification(object): def test_use_after_finalize(self, backend): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) public_key = private_key.public_key() - signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1(), backend) + signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) signer.update(b"sign me") signature = signer.finalize() verifier = public_key.verifier( signature, padding.PKCS1v15(), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(b"sign me") verifier.verify() @@ -965,22 +713,13 @@ class TestRSAVerification(object): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) public_key = private_key.public_key() with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): - public_key.verifier(b"sig", DummyPadding(), hashes.SHA1(), backend) + public_key.verifier(b"sig", DummyPadding(), hashes.SHA1()) def test_padding_incorrect_type(self, backend): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) public_key = private_key.public_key() with pytest.raises(TypeError): - public_key.verifier(b"sig", "notpadding", hashes.SHA1(), backend) - - def test_rsa_verifier_invalid_backend(self, backend): - pretend_backend = object() - private_key = rsa.generate_private_key(65537, 2048, backend) - public_key = private_key.public_key() - - with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - public_key.verifier( - b"foo", padding.PKCS1v15(), hashes.SHA256(), pretend_backend) + public_key.verifier(b"sig", "notpadding", hashes.SHA1()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -993,7 +732,7 @@ class TestRSAVerification(object): public_key = private_key.public_key() with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF): public_key.verifier(b"sig", padding.PSS(mgf=DummyMGF()), - hashes.SHA1(), backend) + hashes.SHA1()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -1022,8 +761,7 @@ class TestRSAVerification(object): mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), - hashes.SHA512(), - backend + hashes.SHA512() ) @pytest.mark.supported( @@ -1040,14 +778,15 @@ class TestRSAVerification(object): b"8b9a3ae9fb3b64158f3476dd8d8a1f1425444e98940e0926378baa9944d219d8" b"534c050ef6b19b1bdc6eb4da422e89161106a6f5b5cc16135b11eb6439b646bd" ) - public_key = rsa.RSAPublicKey( - modulus=int( + public_numbers = rsa.RSAPublicNumbers( + n=int( b"d309e4612809437548b747d7f9eb9cd3340f54fe42bb3f84a36933b0839c" b"11b0c8b7f67e11f7252370161e31159c49c784d4bc41c42a78ce0f0b40a3" b"ca8ffb91", 16 ), - public_exponent=65537 + e=65537 ) + public_key = load_rsa_public_numbers(public_numbers, backend) verifier = public_key.verifier( signature, padding.PSS( @@ -1056,8 +795,7 @@ class TestRSAVerification(object): ), salt_length=1000000 ), - hashes.SHA1(), - backend + hashes.SHA1() ) verifier.update(b"sign me") with pytest.raises(InvalidSignature): @@ -1391,29 +1129,28 @@ class TestRSADecryption(object): ) def test_decrypt_pkcs1v15_vectors(self, vector, backend): private, public, example = vector - skey = rsa.RSAPrivateKey( + private_numbers = rsa.RSAPrivateNumbers( p=private["p"], q=private["q"], - private_exponent=private["private_exponent"], + d=private["private_exponent"], dmp1=private["dmp1"], dmq1=private["dmq1"], iqmp=private["iqmp"], - public_exponent=private["public_exponent"], - modulus=private["modulus"] + public_numbers=rsa.RSAPublicNumbers( + e=private["public_exponent"], + n=private["modulus"] + ) ) + private = load_rsa_private_numbers(private_numbers, backend) ciphertext = binascii.unhexlify(example["encryption"]) - assert len(ciphertext) == math.ceil(skey.key_size / 8.0) - message = skey.decrypt( - ciphertext, - padding.PKCS1v15(), - backend - ) + assert len(ciphertext) == math.ceil(private.key_size / 8.0) + message = private.decrypt(ciphertext, padding.PKCS1v15()) assert message == binascii.unhexlify(example["message"]) def test_unsupported_padding(self, backend): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): - private_key.decrypt(b"0" * 64, DummyPadding(), backend) + private_key.decrypt(b"0" * 64, DummyPadding()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -1426,8 +1163,7 @@ class TestRSADecryption(object): with pytest.raises(ValueError): private_key.decrypt( b"\x00" * 64, - padding.PKCS1v15(), - backend + padding.PKCS1v15() ) @pytest.mark.supported( @@ -1441,8 +1177,7 @@ class TestRSADecryption(object): with pytest.raises(ValueError): private_key.decrypt( b"\x00" * 65, - padding.PKCS1v15(), - backend + padding.PKCS1v15() ) @pytest.mark.supported( @@ -1460,19 +1195,7 @@ class TestRSADecryption(object): with pytest.raises(ValueError): private_key.decrypt( ct, - padding.PKCS1v15(), - backend - ) - - def test_rsa_decrypt_invalid_backend(self, backend): - pretend_backend = object() - private_key = rsa.RSAPrivateKey.generate(65537, 2048, backend) - - with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - private_key.decrypt( - b"irrelevant", - padding.PKCS1v15(), - pretend_backend + padding.PKCS1v15() ) @pytest.mark.supported( @@ -1495,24 +1218,26 @@ class TestRSADecryption(object): ) def test_decrypt_oaep_vectors(self, vector, backend): private, public, example = vector - skey = rsa.RSAPrivateKey( + private_numbers = rsa.RSAPrivateNumbers( p=private["p"], q=private["q"], - private_exponent=private["private_exponent"], + d=private["private_exponent"], dmp1=private["dmp1"], dmq1=private["dmq1"], iqmp=private["iqmp"], - public_exponent=private["public_exponent"], - modulus=private["modulus"] + public_numbers=rsa.RSAPublicNumbers( + e=private["public_exponent"], + n=private["modulus"] + ) ) + skey = load_rsa_private_numbers(private_numbers, backend) message = skey.decrypt( binascii.unhexlify(example["encryption"]), padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), label=None - ), - backend + ) ) assert message == binascii.unhexlify(example["message"]) @@ -1525,8 +1250,7 @@ class TestRSADecryption(object): mgf=DummyMGF(), algorithm=hashes.SHA1(), label=None - ), - backend + ) ) @@ -1561,18 +1285,10 @@ class TestRSAEncryption(object): private_key = load_rsa_private_numbers(key_data, backend) pt = b"encrypt me!" public_key = private_key.public_key() - ct = public_key.encrypt( - pt, - pad, - backend - ) + ct = public_key.encrypt(pt, pad) assert ct != pt assert len(ct) == math.ceil(public_key.key_size / 8.0) - recovered_pt = private_key.decrypt( - ct, - pad, - backend - ) + recovered_pt = private_key.decrypt(ct, pad) assert recovered_pt == pt @pytest.mark.supported( @@ -1594,18 +1310,10 @@ class TestRSAEncryption(object): private_key = load_rsa_private_numbers(key_data, backend) pt = b"encrypt me!" public_key = private_key.public_key() - ct = public_key.encrypt( - pt, - pad, - backend - ) + ct = public_key.encrypt(pt, pad) assert ct != pt assert len(ct) == math.ceil(public_key.key_size / 8.0) - recovered_pt = private_key.decrypt( - ct, - pad, - backend - ) + recovered_pt = private_key.decrypt(ct, pad) assert recovered_pt == pt @pytest.mark.parametrize( @@ -1631,28 +1339,14 @@ class TestRSAEncryption(object): with pytest.raises(ValueError): public_key.encrypt( b"\x00" * (private_key.key_size // 8 - 1), - pad, - backend + pad ) # Larger than the key size. with pytest.raises(ValueError): public_key.encrypt( b"\x00" * (private_key.key_size // 8 + 5), - pad, - backend - ) - - def test_rsa_encrypt_invalid_backend(self, backend): - pretend_backend = object() - private_key = rsa.RSAPrivateKey.generate(65537, 512, backend) - public_key = private_key.public_key() - - with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - public_key.encrypt( - b"irrelevant", - padding.PKCS1v15(), - pretend_backend + pad ) def test_unsupported_padding(self, backend): @@ -1660,7 +1354,7 @@ class TestRSAEncryption(object): public_key = private_key.public_key() with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): - public_key.encrypt(b"somedata", DummyPadding(), backend) + public_key.encrypt(b"somedata", DummyPadding()) def test_unsupported_oaep_mgf(self, backend): private_key = load_rsa_private_numbers(RSA_KEY_512, backend) @@ -1673,8 +1367,7 @@ class TestRSAEncryption(object): mgf=DummyMGF(), algorithm=hashes.SHA1(), label=None - ), - backend + ) ) @@ -1682,7 +1375,7 @@ class TestRSAEncryption(object): class TestRSANumbers(object): def test_rsa_public_numbers(self): public_numbers = rsa.RSAPublicNumbers(e=1, n=15) - assert public_numbers.e == 1 + assert public_numbers.e == 3 assert public_numbers.n == 15 def test_rsa_private_numbers(self): @@ -2038,3 +1731,396 @@ class TestRSANumbers(object): ) ) ) + + +@pytest.mark.rsa +class TestDeprecatedRSA(object): + def test_deprecated_invalid_private_key_argument_types(self): + with pytest.raises(TypeError): + rsa.RSAPrivateKey(None, None, None, None, None, None, None, None) + + def test_deprecated_invalid_public_key_argument_types(self): + with pytest.raises(TypeError): + rsa.RSAPublicKey(None, None) + + def test_deprecated_invalid_private_key_argument_values(self): + # This can be removed when we finish deprecation for DeprecatedIn05 + + # Start with p=3, q=11, private_exponent=3, public_exponent=7, + # modulus=33, dmp1=1, dmq1=3, iqmp=2. Then change one value at + # a time to test the bounds. + + # Test a modulus < 3. + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_exponent=7, + modulus=2 + ) + + # Test a modulus != p * q. + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_exponent=7, + modulus=35 + ) + + # Test a p > modulus. + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=37, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_exponent=7, + modulus=33 + ) + + # Test a q > modulus. + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=37, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_exponent=7, + modulus=33 + ) + + # Test a dmp1 > modulus. + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=3, + dmp1=35, + dmq1=3, + iqmp=2, + public_exponent=7, + modulus=33 + ) + + # Test a dmq1 > modulus. + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=3, + dmp1=1, + dmq1=35, + iqmp=2, + public_exponent=7, + modulus=33 + ) + + # Test an iqmp > modulus. + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=35, + public_exponent=7, + modulus=33 + ) + + # Test a private_exponent > modulus + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=37, + dmp1=1, + dmq1=3, + iqmp=2, + public_exponent=7, + modulus=33 + ) + + # Test a public_exponent < 3 + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_exponent=1, + modulus=33 + ) + + # Test a public_exponent > modulus + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_exponent=65537, + modulus=33 + ) + + # Test a public_exponent that is not odd. + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_exponent=6, + modulus=33 + ) + + # Test a dmp1 that is not odd. + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=3, + dmp1=2, + dmq1=3, + iqmp=2, + public_exponent=7, + modulus=33 + ) + + # Test a dmq1 that is not odd. + with pytest.raises(ValueError): + rsa.RSAPrivateKey( + p=3, + q=11, + private_exponent=3, + dmp1=1, + dmq1=4, + iqmp=2, + public_exponent=7, + modulus=33 + ) + + def test_deprecated_invalid_public_key_argument_values(self): + # This can be removed when we finish deprecation for DeprecatedIn05 + + # Start with public_exponent=7, modulus=15. Then change one value at a + # time to test the bounds. + + # Test a modulus < 3. + with pytest.raises(ValueError): + rsa.RSAPublicKey(public_exponent=7, modulus=2) + + # Test a public_exponent < 3 + with pytest.raises(ValueError): + rsa.RSAPublicKey(public_exponent=1, modulus=15) + + # Test a public_exponent > modulus + with pytest.raises(ValueError): + rsa.RSAPublicKey(public_exponent=17, modulus=15) + + # Test a public_exponent that is not odd. + with pytest.raises(ValueError): + rsa.RSAPublicKey(public_exponent=6, modulus=15) + + def test_rsa_deprecated_generate_invalid_backend(self): + # This can be removed when we finish deprecation for DeprecatedIn05 + pretend_backend = object() + + with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): + rsa.generate_private_key(65537, 2048, pretend_backend) + + with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): + rsa.RSAPrivateKey.generate(65537, 2048, pretend_backend) + + @pytest.mark.supported( + only_if=lambda backend: backend.rsa_padding_supported( + padding.PKCS1v15() + ), + skip_message="Does not support PKCS1v1.5." + ) + @pytest.mark.parametrize( + "pkcs1_example", + _flatten_pkcs1_examples(load_vectors_from_file( + os.path.join( + "asymmetric", "RSA", "pkcs1v15sign-vectors.txt"), + load_pkcs1_vectors + )) + ) + def test_deprecated_pkcs1v15_signing(self, pkcs1_example, backend): + # This can be removed when we finish deprecation for DeprecatedIn05 + + private, public, example = pkcs1_example + private_key = rsa.RSAPrivateKey( + p=private["p"], + q=private["q"], + private_exponent=private["private_exponent"], + dmp1=private["dmp1"], + dmq1=private["dmq1"], + iqmp=private["iqmp"], + public_exponent=private["public_exponent"], + modulus=private["modulus"] + ) + signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1(), backend) + signer.update(binascii.unhexlify(example["message"])) + signature = signer.finalize() + assert binascii.hexlify(signature) == example["signature"] + + def test_rsa_deprecated_signer_invalid_backend(self, backend): + # This can be removed when we finish deprecation for DeprecatedIn05 + pretend_backend = object() + private_key = rsa.RSAPrivateKey( + p=RSA_KEY_2048.p, + q=RSA_KEY_2048.q, + private_exponent=RSA_KEY_2048.d, + dmp1=RSA_KEY_2048.dmp1, + dmq1=RSA_KEY_2048.dmq1, + iqmp=RSA_KEY_2048.iqmp, + public_exponent=RSA_KEY_2048.public_numbers.e, + modulus=RSA_KEY_2048.public_numbers.n + ) + + with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): + private_key.signer( + padding.PKCS1v15(), hashes.SHA256, pretend_backend) + + def test_rsa_deprecated_verifier_invalid_backend(self, backend): + # This can be removed when we finish deprecation for DeprecatedIn05 + pretend_backend = object() + private_key = rsa.RSAPrivateKey( + p=RSA_KEY_2048.p, + q=RSA_KEY_2048.q, + private_exponent=RSA_KEY_2048.d, + dmp1=RSA_KEY_2048.dmp1, + dmq1=RSA_KEY_2048.dmq1, + iqmp=RSA_KEY_2048.iqmp, + public_exponent=RSA_KEY_2048.public_numbers.e, + modulus=RSA_KEY_2048.public_numbers.n + ) + public_key = private_key.public_key() + + with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): + public_key.verifier( + b"foo", padding.PKCS1v15(), hashes.SHA256(), pretend_backend) + + def test_rsa_decrypt_invalid_backend(self, backend): + # This can be removed when we finish deprecation for DeprecatedIn05 + pretend_backend = object() + private_key = rsa.RSAPrivateKey( + p=RSA_KEY_2048.p, + q=RSA_KEY_2048.q, + private_exponent=RSA_KEY_2048.d, + dmp1=RSA_KEY_2048.dmp1, + dmq1=RSA_KEY_2048.dmq1, + iqmp=RSA_KEY_2048.iqmp, + public_exponent=RSA_KEY_2048.public_numbers.e, + modulus=RSA_KEY_2048.public_numbers.n + ) + + with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): + private_key.decrypt( + b"irrelevant", + padding.PKCS1v15(), + pretend_backend + ) + + @pytest.mark.supported( + only_if=lambda backend: backend.rsa_padding_supported( + padding.PKCS1v15() + ), + skip_message="Does not support PKCS1v1.5." + ) + def test_deprecated_rsa_encrypt_pkcs1v15(self, backend): + # This can be removed when we finish deprecation for DeprecatedIn05 + private_key = rsa.RSAPrivateKey( + p=RSA_KEY_1024.p, + q=RSA_KEY_1024.q, + private_exponent=RSA_KEY_1024.d, + dmp1=RSA_KEY_1024.dmp1, + dmq1=RSA_KEY_1024.dmq1, + iqmp=RSA_KEY_1024.iqmp, + public_exponent=RSA_KEY_1024.public_numbers.e, + modulus=RSA_KEY_1024.public_numbers.n + ) + pt = b"encrypt me!" + public_key = private_key.public_key() + pad = padding.PKCS1v15() + ct = public_key.encrypt(pt, pad, backend) + assert ct != pt + assert len(ct) == math.ceil(public_key.key_size / 8.0) + recovered_pt = private_key.decrypt(ct, pad, backend) + assert recovered_pt == pt + + def test_rsa_deprecated_encrypt_invalid_backend(self, backend): + # This can be removed when we finish deprecation for DeprecatedIn05 + pretend_backend = object() + private_key = rsa.RSAPrivateKey( + p=RSA_KEY_2048.p, + q=RSA_KEY_2048.q, + private_exponent=RSA_KEY_2048.d, + dmp1=RSA_KEY_2048.dmp1, + dmq1=RSA_KEY_2048.dmq1, + iqmp=RSA_KEY_2048.iqmp, + public_exponent=RSA_KEY_2048.public_numbers.e, + modulus=RSA_KEY_2048.public_numbers.n + ) + public_key = private_key.public_key() + + with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): + public_key.encrypt( + b"irrelevant", + padding.PKCS1v15(), + pretend_backend + ) + + @pytest.mark.supported( + only_if=lambda backend: backend.rsa_padding_supported( + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + algorithm=hashes.SHA1(), + label=None + ) + ), + skip_message="Does not support OAEP." + ) + def test_rsa_deprecated_decrypt_oaep(self, backend): + private_key = rsa.RSAPrivateKey( + p=RSA_KEY_2048.p, + q=RSA_KEY_2048.q, + private_exponent=RSA_KEY_2048.d, + dmp1=RSA_KEY_2048.dmp1, + dmq1=RSA_KEY_2048.dmq1, + iqmp=RSA_KEY_2048.iqmp, + public_exponent=RSA_KEY_2048.public_numbers.e, + modulus=RSA_KEY_2048.public_numbers.n + ) + pt = b"encrypt me!" + public_key = private_key.public_key() + pad = padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + algorithm=hashes.SHA1(), + label=None + ) + ct = public_key.encrypt(pt, pad, backend) + assert ct != pt + assert len(ct) == math.ceil(public_key.key_size / 8.0) + recovered_pt = private_key.decrypt(ct, pad, backend) + assert recovered_pt == pt diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 4aa9707f..625f5dc2 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -20,7 +20,8 @@ import textwrap import pytest from cryptography.exceptions import _Reasons -from cryptography.hazmat.primitives.asymmetric import dsa, rsa +from cryptography.hazmat.primitives import interfaces +from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives.serialization import ( load_pem_pkcs8_private_key, load_pem_traditional_openssl_private_key, @@ -29,7 +30,7 @@ from cryptography.hazmat.primitives.serialization import ( ) from .fixtures_rsa import RSA_KEY_1024 -from .utils import _check_rsa_private_key, load_vectors_from_file +from .utils import _check_rsa_private_numbers, load_vectors_from_file from ...utils import raises_unsupported_algorithm @@ -54,8 +55,9 @@ class TestTraditionalOpenSSLSerialisation(object): ) assert key - assert isinstance(key, rsa.RSAPrivateKey) - _check_rsa_private_key(key) + assert isinstance(key, interfaces.RSAPrivateKey) + if isinstance(key, interfaces.RSAPrivateKeyWithNumbers): + _check_rsa_private_numbers(key.private_numbers()) @pytest.mark.parametrize( ("key_file", "password"), @@ -87,33 +89,37 @@ class TestTraditionalOpenSSLSerialisation(object): ) assert pkey - assert pkey.p == int( + if not isinstance(pkey, interfaces.RSAPrivateKeyWithNumbers): + pytest.skip("Does not support numbers") + + numbers = pkey.private_numbers() + assert numbers.p == int( "fb7d316fc51531b36d93adaefaf52db6ad5beb793d37c4cf9dfc1ddd17cfbafb", 16 ) - assert pkey.q == int( + assert numbers.q == int( "df98264e646de9a0fbeab094e31caad5bc7adceaaae3c800ca0275dd4bb307f5", 16 ) - assert pkey.private_exponent == int( + assert numbers.d == int( "db4848c36f478dd5d38f35ae519643b6b810d404bcb76c00e44015e56ca1cab0" "7bb7ae91f6b4b43fcfc82a47d7ed55b8c575152116994c2ce5325ec24313b911", 16 ) - assert pkey.dmp1 == int( + assert numbers.dmp1 == int( "ce997f967192c2bcc3853186f1559fd355c190c58ddc15cbf5de9b6df954c727", 16 ) - assert pkey.dmq1 == int( + assert numbers.dmq1 == int( "b018a57ab20ffaa3862435445d863369b852cf70a67c55058213e3fe10e3848d", 16 ) - assert pkey.iqmp == int( + assert numbers.iqmp == int( "6a8d830616924f5cf2d1bc1973f97fde6b63e052222ac7be06aa2532d10bac76", 16 ) - assert pkey.public_exponent == 65537 - assert pkey.modulus == int( + assert numbers.public_numbers.e == 65537 + assert numbers.public_numbers.n == int( "dba786074f2f0350ce1d99f5aed5b520cfe0deb5429ec8f2a88563763f566e77" "9814b7c310e5326edae31198eed439b845dd2db99eaa60f5c16a43f4be6bcf37", 16 @@ -283,8 +289,9 @@ class TestPKCS8Serialisation(object): ) assert key - assert isinstance(key, rsa.RSAPrivateKey) - _check_rsa_private_key(key) + assert isinstance(key, interfaces.RSAPrivateKey) + if isinstance(key, interfaces.RSAPrivateKeyWithNumbers): + _check_rsa_private_numbers(key.private_numbers()) def test_unused_password(self, backend): key_file = os.path.join( @@ -415,7 +422,12 @@ class TestPKCS8Serialisation(object): ) assert pkey - assert pkey.modulus == int( + if not isinstance(pkey, interfaces.RSAPrivateKeyWithNumbers): + pytest.skip("Does not support numbers") + + numbers = pkey.private_numbers() + + assert numbers.public_numbers.n == int( "00beec64d6db5760ac2fd4c971145641b9bd7f5c56558ece608795c79807" "376a7fe5b19f95b35ca358ea5c8abd7ae051d49cd2f1e45969a1ae945460" "3c14b278664a0e414ebc8913acb6203626985525e17a600611b028542dd0" @@ -423,9 +435,9 @@ class TestPKCS8Serialisation(object): "dd68480567c99b1a57", 16 ) - assert pkey.public_exponent == 65537 + assert numbers.public_numbers.e == 65537 - assert pkey.private_exponent == int( + assert numbers.d == int( "0cfe316e9dc6b8817f4fcfd5ae38a0886f68f773b8a6db4c9e6d8703c599" "f3d9785c3a2c09e4c8090909fb3721e19a3009ec21221523a729265707a5" "8f13063671c42a4096cad378ef2510cb59e23071489d8893ac4934dd149f" @@ -433,31 +445,31 @@ class TestPKCS8Serialisation(object): "cf7d995688c86c81", 16 ) - assert pkey.p == int( + assert numbers.p == int( "00db122ac857b2c0437d7616daa98e597bb75ca9ad3a47a70bec10c10036" "03328794b225c8e3eee6ffd3fd6d2253d28e071fe27d629ab072faa14377" "ce6118cb67", 16 ) - assert pkey.q == int( + assert numbers.q == int( "00df1b8aa8506fcbbbb9d00257f2975e38b33d2698fd0f37e82d7ef38c56" "f21b6ced63c825383782a7115cfcc093300987dbd2853b518d1c8f26382a" "2d2586d391", 16 ) - assert pkey.dmp1 == int( + assert numbers.dmp1 == int( "00be18aca13e60712fdf5daa85421eb10d86d654b269e1255656194fb0c4" "2dd01a1070ea12c19f5c39e09587af02f7b1a1030d016a9ffabf3b36d699" "ceaf38d9bf", 16 ) - assert pkey.dmq1 == int( + assert numbers.dmq1 == int( "71aa8978f90a0c050744b77cf1263725b203ac9f730606d8ae1d289dce4a" "28b8d534e9ea347aeb808c73107e583eb80c546d2bddadcdb3c82693a4c1" "3d863451", 16 ) - assert pkey.iqmp == int( + assert numbers.iqmp == int( "136b7b1afac6e6279f71b24217b7083485a5e827d156024609dae39d48a6" "bdb55af2f062cc4a3b077434e6fffad5faa29a2b5dba2bed3e4621e478c0" "97ccfe7f", 16 diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index a496459b..54659aa9 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -28,6 +28,9 @@ from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.kdf.hkdf import HKDF, HKDFExpand from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC +from cryptography.hazmat.primitives.serialization import ( + load_rsa_public_numbers +) from ...utils import load_vectors_from_file @@ -388,16 +391,16 @@ def generate_rsa_verification_test(param_loader, path, file_names, hash_alg, def rsa_verification_test(backend, params, hash_alg, pad_factory): - public_key = rsa.RSAPublicKey( - public_exponent=params["public_exponent"], - modulus=params["modulus"] + public_numbers = rsa.RSAPublicNumbers( + e=params["public_exponent"], + n=params["modulus"] ) + public_key = load_rsa_public_numbers(public_numbers, backend) pad = pad_factory(params, hash_alg) verifier = public_key.verifier( binascii.unhexlify(params["s"]), pad, - hash_alg, - backend + hash_alg ) verifier.update(binascii.unhexlify(params["msg"])) if params["fail"]: @@ -407,19 +410,14 @@ def rsa_verification_test(backend, params, hash_alg, pad_factory): verifier.verify() -def _check_rsa_private_key(skey): +def _check_rsa_private_numbers(skey): assert skey - assert skey.modulus - assert skey.public_exponent - assert skey.private_exponent - assert skey.p * skey.q == skey.modulus - assert skey.key_size + pkey = skey.public_numbers + assert pkey + assert pkey.e + assert pkey.n + assert skey.d + assert skey.p * skey.q == pkey.n assert skey.dmp1 == rsa.rsa_crt_dmp1(skey.d, skey.p) assert skey.dmq1 == rsa.rsa_crt_dmq1(skey.d, skey.q) assert skey.iqmp == rsa.rsa_crt_iqmp(skey.p, skey.q) - - pkey = skey.public_key() - assert pkey - assert skey.modulus == pkey.modulus - assert skey.public_exponent == pkey.public_exponent - assert skey.key_size == pkey.key_size |