From 09328bbfb3306d3c7b02a44f12ecd22ce3ec700e Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 12 Feb 2014 23:57:27 -0600 Subject: add crt coefficients to RSAPrivateKey constructor and update tests --- cryptography/hazmat/backends/openssl/backend.py | 3 + cryptography/hazmat/primitives/asymmetric/rsa.py | 24 +++- tests/hazmat/primitives/test_rsa.py | 163 +++++++++++++++++++---- tests/test_utils.py | 31 ++++- tests/utils.py | 6 + 5 files changed, 196 insertions(+), 31 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index fc3c3bda..ce37e5c8 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -296,6 +296,9 @@ class Backend(object): return rsa.RSAPrivateKey( p=self._bn_to_int(ctx.p), q=self._bn_to_int(ctx.q), + dmp1=self._bn_to_int(ctx.dmp1), + dmq1=self._bn_to_int(ctx.dmq1), + iqmp=self._bn_to_int(ctx.iqmp), private_exponent=self._bn_to_int(ctx.d), public_exponent=self._bn_to_int(ctx.e), modulus=self._bn_to_int(ctx.n), diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py index 60c5c807..dbe56b47 100644 --- a/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -72,10 +72,14 @@ class RSAPublicKey(object): @utils.register_interface(interfaces.RSAPrivateKey) class RSAPrivateKey(object): - def __init__(self, p, q, private_exponent, public_exponent, modulus): + def __init__(self, p, q, private_exponent, dmp1, dmq1, iqmp, + public_exponent, modulus): if ( not isinstance(p, six.integer_types) or not isinstance(q, six.integer_types) or + not isinstance(dmp1, six.integer_types) or + not isinstance(dmq1, six.integer_types) or + not isinstance(iqmp, six.integer_types) or not isinstance(private_exponent, six.integer_types) or not isinstance(public_exponent, six.integer_types) or not isinstance(modulus, six.integer_types) @@ -91,6 +95,15 @@ class RSAPrivateKey(object): if q >= modulus: raise ValueError("q must be < modulus") + if dmp1 >= modulus: + raise ValueError("dmp1 must be < modulus") + + if dmq1 >= modulus: + raise ValueError("dmq1 must be < modulus") + + if iqmp >= modulus: + raise ValueError("iqmp must be < modulus") + if private_exponent >= modulus: raise ValueError("private_exponent must be < modulus") @@ -100,11 +113,20 @@ class RSAPrivateKey(object): if public_exponent & 1 == 0: raise ValueError("public_exponent must be odd") + if dmp1 & 1 == 0: + raise ValueError("dmp1 must be odd") + + if dmq1 & 1 == 0: + raise ValueError("dmq1 must be odd") + if p * q != modulus: raise ValueError("p*q must equal modulus") self._p = p self._q = q + self._dmp1 = dmp1 + self._dmq1 = dmq1 + self._iqmp = iqmp self._private_exponent = private_exponent self._public_exponent = public_exponent self._modulus = modulus diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 0e930e44..9dc1a9e4 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -24,6 +24,20 @@ from cryptography.hazmat.primitives.asymmetric import rsa from ...utils import load_pkcs1_vectors, load_vectors_from_file +def _egcd(a, b): + if a == 0: + return (b, 0, 1) + else: + g, y, x = _egcd(b % a, a) + return (g, x - (b // a) * y, y) + + +def _modinv(a, m): + g, x, y = _egcd(a, m) + assert g == 1 + return x % m + + def _check_rsa_private_key(skey): assert skey assert skey.modulus @@ -31,6 +45,9 @@ def _check_rsa_private_key(skey): assert skey.private_exponent assert skey.p * skey.q == skey.modulus assert skey.key_size + assert skey._dmp1 == skey.d % (skey.p - 1) + assert skey._dmq1 == skey.d % (skey.q - 1) + assert skey._iqmp == _modinv(skey.q, skey.p) pkey = skey.public_key() assert pkey @@ -115,22 +132,26 @@ class TestRSA(object): def test_invalid_private_key_argument_types(self): with pytest.raises(TypeError): - rsa.RSAPrivateKey(None, None, None, None, None) + 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=5, private_exponent=14, public_exponent=7, - # modulus=15. Then change one value at a time to test the bounds. + # 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=5, - private_exponent=14, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, public_exponent=7, modulus=2 ) @@ -139,70 +160,156 @@ class TestRSA(object): with pytest.raises(ValueError): rsa.RSAPrivateKey( p=3, - q=5, - private_exponent=14, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, public_exponent=7, - modulus=16 + modulus=35 ) # Test a p > modulus. with pytest.raises(ValueError): rsa.RSAPrivateKey( - p=16, - q=5, - private_exponent=14, + p=37, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, public_exponent=7, - modulus=15 + modulus=33 ) # Test a q > modulus. with pytest.raises(ValueError): rsa.RSAPrivateKey( p=3, - q=16, - private_exponent=14, + 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=15 + modulus=33 ) # Test a private_exponent > modulus with pytest.raises(ValueError): rsa.RSAPrivateKey( p=3, - q=5, - private_exponent=16, + q=11, + private_exponent=37, + dmp1=1, + dmq1=3, + iqmp=2, public_exponent=7, - modulus=15 + modulus=33 ) # Test a public_exponent < 3 with pytest.raises(ValueError): rsa.RSAPrivateKey( p=3, - q=5, - private_exponent=14, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, public_exponent=1, - modulus=15 + modulus=33 ) # Test a public_exponent > modulus with pytest.raises(ValueError): rsa.RSAPrivateKey( p=3, - q=5, - private_exponent=14, - public_exponent=17, - modulus=15 + 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=5, - private_exponent=14, + q=11, + private_exponent=3, + dmp1=1, + dmq1=3, + iqmp=2, public_exponent=6, - modulus=15 + 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): diff --git a/tests/test_utils.py b/tests/test_utils.py index a0571ad6..0e1d77b5 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -768,7 +768,19 @@ def test_load_pkcs1_vectors(): 'q': int( '847e732376fc7900f898ea82eb2b0fc418565fdae62f7d9ec4ce2217b' '97990dd272db157f99f63c0dcbb9fbacdbd4c4dadb6df67756358ca41' - '74825b48f49706d', 16) + '74825b48f49706d', 16), + 'dmp1': int( + '05c2a83c124b3621a2aa57ea2c3efe035eff4560f33ddebb7adab81fc' + 'e69a0c8c2edc16520dda83d59a23be867963ac65f2cc710bbcfb96ee1' + '03deb771d105fd85', 16), + 'dmq1': int( + '04cae8aa0d9faa165c87b682ec140b8ed3b50b24594b7a3b2c220b366' + '9bb819f984f55310a1ae7823651d4a02e99447972595139363434e5e3' + '0a7e7d241551e1b9', 16), + 'iqmp': int( + '07d3e47bf686600b11ac283ce88dbb3f6051e8efd04680e44c171ef53' + '1b80b2b7c39fc766320e2cf15d8d99820e96ff30dc69691839c4b40d7' + 'b06e45307dc91f3f', 16) }, { @@ -809,7 +821,22 @@ def test_load_pkcs1_vectors(): 'ed4d71d0a6e24b93c2e5f6b4bbe05f5fb0afa042d204fe3378d365c2f' '288b6a8dad7efe45d153eef40cacc7b81ff934002d108994b94a5e472' '8cd9c963375ae49965bda55cbf0efed8d6553b4027f2d86208a6e6b48' - '9c176128092d629e49d3d', 16) + '9c176128092d629e49d3d', 16), + 'dmp1': int( + '2bb68bddfb0c4f56c8558bffaf892d8043037841e7fa81cfa61a38c5e' + '39b901c8ee71122a5da2227bd6cdeeb481452c12ad3d61d5e4f776a0a' + 'b556591befe3e59e5a7fddb8345e1f2f35b9f4cee57c32414c086aec9' + '93e9353e480d9eec6289f', 16), + 'dmq1': int( + '4ff897709fad079746494578e70fd8546130eeab5627c49b080f05ee4' + 'ad9f3e4b7cba9d6a5dff113a41c3409336833f190816d8a6bc42e9bec' + '56b7567d0f3c9c696db619b245d901dd856db7c8092e77e9a1cccd56e' + 'e4dba42c5fdb61aec2669', 16), + 'iqmp': int( + '77b9d1137b50404a982729316efafc7dfe66d34e5a182600d5f30a0a8' + '512051c560d081d4d0a1835ec3d25a60f4e4d6aa948b2bf3dbb5b124c' + 'bbc3489255a3a948372f6978496745f943e1db4f18382ceaa505dfc65' + '757bb3f857a58dce52156', 16) }, { diff --git a/tests/utils.py b/tests/utils.py index 408b05f6..2bbecd7d 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -262,6 +262,12 @@ def load_pkcs1_vectors(vector_data): attr = "p" elif line.startswith("# Prime 2:"): attr = "q" + elif line.startswith("# Prime exponent 1:"): + attr = "dmp1" + elif line.startswith("# Prime exponent 2:"): + attr = "dmq1" + elif line.startswith("# Coefficient:"): + attr = "iqmp" elif line.startswith("#"): attr = None else: -- cgit v1.2.3