diff options
author | Mohammed Attia <skeuomorf@gmail.com> | 2014-03-30 02:35:13 +0200 |
---|---|---|
committer | Mohammed Attia <skeuomorf@gmail.com> | 2014-03-30 23:54:27 +0200 |
commit | 230457a605999bbdd49df7592290956d80863f3c (patch) | |
tree | ed3e442cfc66e62a1ba7133404856b0752ba7295 | |
parent | 99b0b1f78d5ca9888f996d8d9b0392ca32b8210f (diff) | |
download | cryptography-230457a605999bbdd49df7592290956d80863f3c.tar.gz cryptography-230457a605999bbdd49df7592290956d80863f3c.tar.bz2 cryptography-230457a605999bbdd49df7592290956d80863f3c.zip |
Add DSA private key api, docs and tests
-rw-r--r-- | cryptography/hazmat/primitives/asymmetric/dsa.py | 45 | ||||
-rw-r--r-- | docs/hazmat/primitives/asymmetric/dsa.rst | 17 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_dsa.py | 292 |
3 files changed, 351 insertions, 3 deletions
diff --git a/cryptography/hazmat/primitives/asymmetric/dsa.py b/cryptography/hazmat/primitives/asymmetric/dsa.py index a0631ce8..974db0a6 100644 --- a/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -74,6 +74,49 @@ class DSAParameters(object): return self.generator +@utils.register_interface(interfaces.DSAPrivateKey) +class DSAPrivateKey(object): + def __init__(self, modulus, subgroup_order, generator, x, y): + _check_dsa_parameters(modulus, subgroup_order, generator) + if ( + not isinstance(x, six.integer_types) or + not isinstance(y, six.integer_types) + ): + raise TypeError("DSAPrivateKey arguments must be integers") + + if x <= 0 or x >= subgroup_order: + raise ValueError("x must be > 0 and < subgroup_order") + + if y != pow(generator, x, modulus): + raise ValueError("y must be equal to (generator ** x % modulus)") + + self._modulus = modulus + self._subgroup_order = subgroup_order + self._generator = generator + self._x = x + self._y = y + + @property + def key_size(self): + return utils.bit_length(self._modulus) + + def public_key(self): + return DSAPublicKey(self._modulus, self._subgroup_order, + self._generator, self.y) + + @property + def x(self): + return self._x + + @property + def y(self): + return self._y + + def parameters(self): + return DSAParameters(self._modulus, self._subgroup_order, + self._generator) + + @utils.register_interface(interfaces.DSAPublicKey) class DSAPublicKey(object): def __init__(self, modulus, subgroup_order, generator, y): @@ -96,4 +139,4 @@ class DSAPublicKey(object): def parameters(self): return DSAParameters(self._modulus, self._subgroup_order, - self._generator)
\ No newline at end of file + self._generator) diff --git a/docs/hazmat/primitives/asymmetric/dsa.rst b/docs/hazmat/primitives/asymmetric/dsa.rst index e93bd447..69e8d58e 100644 --- a/docs/hazmat/primitives/asymmetric/dsa.rst +++ b/docs/hazmat/primitives/asymmetric/dsa.rst @@ -24,6 +24,23 @@ DSA not match the bounds specified in `FIPS 186-4`_. +.. class:: DSAPrivateKey(modulus, subgroup_order, generator, x, y) + + .. versionadded:: 0.4 + + A DSA private key is required for signing messages. + + This class conforms to the + :class:`~cryptography.hazmat.primitives.interfaces.DSAPrivateKey` + interface. + + :raises TypeError: This is raised when the arguments are not all integers. + + :raises ValueError: This is raised when the values of ``modulus``, + ``subgroup_order``, or ``generator`` do + not match the bounds specified in `FIPS 186-4`_. + + .. class:: DSAPublicKey(modulus, subgroup_order, generator, y) .. versionadded:: 0.4 diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py index fe610ef3..2a2b9bda 100644 --- a/tests/hazmat/primitives/test_dsa.py +++ b/tests/hazmat/primitives/test_dsa.py @@ -19,6 +19,40 @@ import pytest from cryptography.hazmat.primitives.asymmetric import dsa +def _check_dsa_private_key(skey): + assert skey + assert skey.x + assert skey.y + assert skey.key_size + + skey_parameters = skey.parameters() + assert skey_parameters + assert skey_parameters.modulus + assert skey_parameters.subgroup_order + assert skey_parameters.generator + assert skey_parameters.modulus == skey_parameters.p + assert skey_parameters.subgroup_order == skey_parameters.q + assert skey_parameters.generator == skey_parameters.g + + pkey = skey.public_key() + assert pkey + assert skey.y == pkey.y + assert skey.key_size == pkey.key_size + + pkey_parameters = pkey.parameters() + assert pkey_parameters + assert pkey_parameters.modulus + assert pkey_parameters.subgroup_order + assert pkey_parameters.generator + assert pkey_parameters.modulus == pkey_parameters.p + assert pkey_parameters.subgroup_order == pkey_parameters.q + assert pkey_parameters.generator == pkey_parameters.g + + assert skey_parameters.modulus == pkey_parameters.modulus + assert skey_parameters.subgroup_order == pkey_parameters.subgroup_order + assert skey_parameters.generator == pkey_parameters.generator + + class TestDSA(object): _parameters_1024 = { 'p': 'd38311e2cd388c3ed698e82fdf88eb92b5a9a483dc88005d4b725ef341eabb47' @@ -127,6 +161,10 @@ class TestDSA(object): with pytest.raises(TypeError): dsa.DSAParameters(None, None, None) + def test_invalid_private_key_argument_types(self): + with pytest.raises(TypeError): + dsa.DSAPrivateKey(None, None, None, None, None) + def test_invalid_public_key_argument_types(self): with pytest.raises(TypeError): dsa.DSAPublicKey(None, None, None, None) @@ -145,6 +183,36 @@ class TestDSA(object): assert parameters.subgroup_order == parameters.q assert parameters.generator == parameters.g + pub_key = dsa.DSAPublicKey( + modulus=int(self._parameters_1024["p"], 16), + subgroup_order=int(self._parameters_1024["q"], 16), + generator=int(self._parameters_1024["g"], 16), + y=int(self._parameters_1024["y"], 16) + ) + assert pub_key + assert pub_key.key_size + assert pub_key.y + pub_key_parameters = pub_key.parameters() + assert pub_key_parameters + assert pub_key_parameters.modulus + assert pub_key_parameters.subgroup_order + assert pub_key_parameters.generator + + skey = dsa.DSAPrivateKey( + modulus=int(self._parameters_1024["p"], 16), + subgroup_order=int(self._parameters_1024["q"], 16), + generator=int(self._parameters_1024["g"], 16), + x=int(self._parameters_1024["x"], 16), + y=int(self._parameters_1024["y"], 16) + ) + assert skey + _check_dsa_private_key(skey) + skey_parameters = skey.parameters() + assert skey_parameters + assert skey_parameters.modulus + assert skey_parameters.subgroup_order + assert skey_parameters.generator + pkey = dsa.DSAPublicKey( modulus=int(self._parameters_1024["p"], 16), subgroup_order=int(self._parameters_1024["q"], 16), @@ -152,14 +220,33 @@ class TestDSA(object): y=int(self._parameters_1024["y"], 16) ) assert pkey - assert pkey.key_size - assert pkey.y pkey_parameters = pkey.parameters() assert pkey_parameters assert pkey_parameters.modulus assert pkey_parameters.subgroup_order assert pkey_parameters.generator + pkey2 = skey.public_key() + assert pkey2 + pkey2_parameters = pkey.parameters() + assert pkey2_parameters + assert pkey2_parameters.modulus + assert pkey2_parameters.subgroup_order + assert pkey2_parameters.generator + + assert skey_parameters.modulus == pkey_parameters.modulus + assert skey_parameters.subgroup_order == pkey_parameters.subgroup_order + assert skey_parameters.generator == pkey_parameters.generator + assert skey.y == pkey.y + assert skey.key_size == pkey.key_size + + assert pkey_parameters.modulus == pkey2_parameters.modulus + assert pkey_parameters.subgroup_order == \ + pkey2_parameters.subgroup_order + assert pkey_parameters.generator == pkey2_parameters.generator + assert pkey.y == pkey2.y + assert pkey.key_size == pkey2.key_size + def test_invalid_parameters_values(self): # Test a modulus < 1024 bits in length with pytest.raises(ValueError): @@ -265,6 +352,207 @@ class TestDSA(object): generator=2 ** 1200 ) + def test_invalid_dsa_private_key_arguments(self): + # Test a modulus < 1024 bits in length + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=2 ** 1000, + subgroup_order=int(self._parameters_1024['q'], 16), + generator=int(self._parameters_1024['g'], 16), + x=int(self._parameters_1024['x'], 16), + y=int(self._parameters_1024['y'], 16) + ) + + # Test a modulus < 2048 bits in length + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=2 ** 2000, + subgroup_order=int(self._parameters_2048['q'], 16), + generator=int(self._parameters_2048['g'], 16), + x=int(self._parameters_2048['x'], 16), + y=int(self._parameters_2048['y'], 16) + ) + + # Test a modulus < 3072 bits in length + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=2 ** 3000, + subgroup_order=int(self._parameters_3072['q'], 16), + generator=int(self._parameters_3072['g'], 16), + x=int(self._parameters_3072['x'], 16), + y=int(self._parameters_3072['y'], 16) + ) + + # Test a modulus > 3072 bits in length + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=2 ** 3100, + subgroup_order=int(self._parameters_3072['q'], 16), + generator=int(self._parameters_3072['g'], 16), + x=int(self._parameters_3072['x'], 16), + y=int(self._parameters_3072['y'], 16) + ) + + # Test a subgroup_order < 160 bits in length + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=2 ** 150, + generator=int(self._parameters_1024['g'], 16), + x=int(self._parameters_1024['x'], 16), + y=int(self._parameters_1024['y'], 16) + ) + + # Test a subgroup_order < 256 bits in length + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_2048['p'], 16), + subgroup_order=2 ** 250, + generator=int(self._parameters_2048['g'], 16), + x=int(self._parameters_2048['x'], 16), + y=int(self._parameters_2048['y'], 16) + ) + + # Test a subgroup_order > 256 bits in length + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_3072['p'], 16), + subgroup_order=2 ** 260, + generator=int(self._parameters_3072['g'], 16), + x=int(self._parameters_3072['x'], 16), + y=int(self._parameters_3072['y'], 16) + ) + + # Test a modulus, subgroup_order pair of (1024, 256) bit lengths + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_2048['q'], 16), + generator=int(self._parameters_1024['g'], 16), + x=int(self._parameters_1024['x'], 16), + y=int(self._parameters_1024['y'], 16) + ) + + # Test a modulus, subgroup_order pair of (2048, 160) bit lengths + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_2048['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=int(self._parameters_2048['g'], 16), + x=int(self._parameters_2048['x'], 16), + y=int(self._parameters_2048['y'], 16) + ) + + # Test a modulus, subgroup_order pair of (3072, 160) bit lengths + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_3072['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=int(self._parameters_3072['g'], 16), + x=int(self._parameters_3072['x'], 16), + y=int(self._parameters_3072['y'], 16) + ) + + # Test a generator < 1 + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=0, + x=int(self._parameters_1024['x'], 16), + y=int(self._parameters_1024['y'], 16) + ) + + # Test a generator = 1 + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=1, + x=int(self._parameters_1024['x'], 16), + y=int(self._parameters_1024['y'], 16) + ) + + # Test a generator > modulus + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=2 ** 1200, + x=int(self._parameters_1024['x'], 16), + y=int(self._parameters_1024['y'], 16) + ) + + # Test x = 0 + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=int(self._parameters_1024['g'], 16), + x=0, + y=int(self._parameters_1024['y'], 16) + ) + + # Test x < 0 + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=int(self._parameters_1024['g'], 16), + x=-2, + y=int(self._parameters_1024['y'], 16) + ) + + # Test x = subgroup_order + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=int(self._parameters_1024['g'], 16), + x=2 ** 159, + y=int(self._parameters_1024['y'], 16) + ) + + # Test x > subgroup_order + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=int(self._parameters_1024['g'], 16), + x=2 ** 200, + y=int(self._parameters_1024['y'], 16) + ) + + # Test y != (generator ** x) % modulus + with pytest.raises(ValueError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=int(self._parameters_1024['g'], 16), + x=int(self._parameters_1024['x'], 16), + y=2 ** 100 + ) + + # Test a non-integer y value + with pytest.raises(TypeError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=int(self._parameters_1024['g'], 16), + x=int(self._parameters_1024['x'], 16), + y=None + ) + + # Test a non-integer x value + with pytest.raises(TypeError): + dsa.DSAPrivateKey( + modulus=int(self._parameters_1024['p'], 16), + subgroup_order=int(self._parameters_1024['q'], 16), + generator=int(self._parameters_1024['g'], 16), + x=None, + y=int(self._parameters_1024['x'], 16) + ) + def test_invalid_dsa_public_key_arguments(self): # Test a modulus < 1024 bits in length with pytest.raises(ValueError): |