From e025be284e1a1d19e761b0fff907d126f17b4fb0 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 24 Sep 2014 11:26:48 -0500 Subject: add EC WithNumbers interfaces and docs --- cryptography/hazmat/primitives/interfaces.py | 18 +++++++++++++++ docs/hazmat/primitives/interfaces.rst | 34 ++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index d60f9e0e..c7ad0cf8 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -443,6 +443,15 @@ class EllipticCurvePrivateKey(object): """ +@six.add_metaclass(abc.ABCMeta) +class EllipticCurvePrivateKeyWithNumbers(EllipticCurvePrivateKey): + @abc.abstractmethod + def private_numbers(self): + """ + Returns an EllipticCurvePrivateNumbers. + """ + + @six.add_metaclass(abc.ABCMeta) class EllipticCurvePublicKey(object): @abc.abstractmethod @@ -456,3 +465,12 @@ class EllipticCurvePublicKey(object): """ The EllipticCurve that this key is on. """ + + +@six.add_metaclass(abc.ABCMeta) +class EllipticCurvePublicKeyWithNumbers(EllipticCurvePublicKey): + @abc.abstractmethod + def public_numbers(self): + """ + Returns an EllipticCurvePublicNumbers. + """ diff --git a/docs/hazmat/primitives/interfaces.rst b/docs/hazmat/primitives/interfaces.rst index ac47c1e1..14be6982 100644 --- a/docs/hazmat/primitives/interfaces.rst +++ b/docs/hazmat/primitives/interfaces.rst @@ -492,6 +492,23 @@ Elliptic Curve The EllipticCurvePublicKey object for this private key. +.. class:: EllipticCurvePrivateKeyWithNumbers + + .. versionadded:: 0.6 + + Extends :class:`EllipticCurvePrivateKey`. + + .. method:: private_numbers() + + Create a + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateNumbers` + object. + + :returns: An + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateNumbers` + instance. + + .. class:: EllipticCurvePublicKey .. versionadded:: 0.5 @@ -518,6 +535,23 @@ Elliptic Curve The elliptic curve for this key. +.. class:: EllipticCurvePublicKeyWithNumbers + + .. versionadded:: 0.6 + + Extends :class:`EllipticCurvePublicKey`. + + .. method:: private_numbers() + + Create a + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers` + object. + + :returns: An + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers` + instance. + + Hash algorithms --------------- -- cgit v1.2.3 From c6323f16014748bcda0cc755af7dd2a0e8cc457e Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 24 Sep 2014 11:45:41 -0500 Subject: Support EC WithNumbers on OpenSSL backend + tests --- cryptography/hazmat/backends/openssl/ec.py | 59 +++++++++++++++++++++++++++++- tests/hazmat/primitives/test_ec.py | 36 ++++++++++++++++++ 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/ec.py b/cryptography/hazmat/backends/openssl/ec.py index 611dba2c..879d674a 100644 --- a/cryptography/hazmat/backends/openssl/ec.py +++ b/cryptography/hazmat/backends/openssl/ec.py @@ -129,7 +129,7 @@ class _ECDSAVerificationContext(object): return True -@utils.register_interface(interfaces.EllipticCurvePrivateKey) +@utils.register_interface(interfaces.EllipticCurvePrivateKeyWithNumbers) class _EllipticCurvePrivateKey(object): def __init__(self, backend, ec_key_cdata, curve): self._backend = backend @@ -172,8 +172,16 @@ class _EllipticCurvePrivateKey(object): self._backend, public_ec_key, self._curve ) + def private_numbers(self): + bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key) + private_value = self._backend._bn_to_int(bn) + return ec.EllipticCurvePrivateNumbers( + private_value=private_value, + public_numbers=self.public_key().public_numbers() + ) + -@utils.register_interface(interfaces.EllipticCurvePublicKey) +@utils.register_interface(interfaces.EllipticCurvePublicKeyWithNumbers) class _EllipticCurvePublicKey(object): def __init__(self, backend, ec_key_cdata, curve): self._backend = backend @@ -193,3 +201,50 @@ class _EllipticCurvePublicKey(object): raise UnsupportedAlgorithm( "Unsupported elliptic curve signature algorithm.", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + + def public_numbers(self): + bn_ctx = self._backend._lib.BN_CTX_new() + assert bn_ctx != self._backend._ffi.NULL + bn_ctx = self._backend._ffi.gc(bn_ctx, self._backend._lib.BN_CTX_free) + + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + assert group != self._backend._ffi.NULL + + method = self._backend._lib.EC_GROUP_method_of(group) + assert method != self._backend._ffi.NULL + + nid = self._backend._lib.EC_METHOD_get_field_type(method) + assert nid != self._backend._lib.NID_undef + + nid_two_field = self._backend._lib.OBJ_sn2nid( + b"characteristic-two-field" + ) + assert nid_two_field != self._backend._lib.NID_undef + + if nid == nid_two_field and self._backend._lib.Cryptography_HAS_EC2M: + get_func = self._backend._lib.EC_POINT_get_affine_coordinates_GF2m + else: + get_func = self._backend._lib.EC_POINT_get_affine_coordinates_GFp + + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + assert point != self._backend._ffi.NULL + + try: + self._backend._lib.BN_CTX_start(bn_ctx) + + bn_x = self._backend._lib.BN_CTX_get(bn_ctx) + bn_y = self._backend._lib.BN_CTX_get(bn_ctx) + + res = get_func(group, point, bn_x, bn_y, bn_ctx) + assert res == 1 + + x = self._backend._bn_to_int(bn_x) + y = self._backend._bn_to_int(bn_y) + finally: + self._backend._lib.BN_CTX_end(bn_ctx) + + return ec.EllipticCurvePublicNumbers( + x=x, + y=y, + curve=self._curve + ) diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py index 65461f70..a2613db8 100644 --- a/tests/hazmat/primitives/test_ec.py +++ b/tests/hazmat/primitives/test_ec.py @@ -128,6 +128,42 @@ def test_ec_numbers(): ) +@pytest.mark.elliptic +class TestECWithNumbers(object): + @pytest.mark.parametrize( + ("vector", "hash_type"), + list(itertools.product( + load_vectors_from_file( + os.path.join( + "asymmetric", "ECDSA", "FIPS_186-3", "KeyPair.rsp"), + load_fips_ecdsa_key_pair_vectors + ), + _HASH_TYPES.values() + )) + ) + def test_with_numbers(self, backend, vector, hash_type): + curve_type = _CURVE_TYPES[vector['curve']] + + _skip_ecdsa_vector(backend, curve_type, hash_type) + + key = ec.EllipticCurvePrivateNumbers( + vector['d'], + ec.EllipticCurvePublicNumbers( + vector['x'], + vector['y'], + curve_type() + ) + ).private_key(backend) + assert key + + if isinstance(key, interfaces.EllipticCurvePrivateKeyWithNumbers): + priv_num = key.private_numbers() + assert priv_num.private_value == vector['d'] + assert priv_num.public_numbers.x == vector['x'] + assert priv_num.public_numbers.y == vector['y'] + assert curve_type().name == priv_num.public_numbers.curve.name + + @pytest.mark.elliptic class TestECDSAVectors(object): @pytest.mark.parametrize( -- cgit v1.2.3 From 5cfd2111133f31cea6d296d8e93665c9f43265d2 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 24 Sep 2014 14:51:01 -0500 Subject: fix naming mistake in the docs (for DSA and the new EC docs) --- docs/hazmat/primitives/interfaces.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hazmat/primitives/interfaces.rst b/docs/hazmat/primitives/interfaces.rst index 14be6982..2d594c8d 100644 --- a/docs/hazmat/primitives/interfaces.rst +++ b/docs/hazmat/primitives/interfaces.rst @@ -416,7 +416,7 @@ DSA Extends :class:`DSAPublicKey`. - .. method:: private_numbers() + .. method:: public_numbers() Create a :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers` @@ -541,7 +541,7 @@ Elliptic Curve Extends :class:`EllipticCurvePublicKey`. - .. method:: private_numbers() + .. method:: public_numbers() Create a :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers` -- cgit v1.2.3 From 1061453bfb9d5555e80dcabf82b5b43596c8bd04 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 24 Sep 2014 19:03:40 -0500 Subject: refactor to use ctx manager and share logic with set_public_key_affine --- cryptography/hazmat/backends/openssl/backend.py | 39 ++++++++++++++++--------- cryptography/hazmat/backends/openssl/ec.py | 30 ++----------------- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 389ef0be..3667232b 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -1085,30 +1085,19 @@ class Backend(object): finally: self._lib.BN_CTX_end(bn_ctx) - def _ec_key_set_public_key_affine_coordinates(self, ctx, x, y): + def _ec_key_determine_group_get_set_funcs(self, ctx): """ - This is a port of EC_KEY_set_public_key_affine_coordinates that was - added in 1.0.1. - - Sets the public key point in the EC_KEY context to the affine x and y - values. + Given an EC_KEY determine the group and what methods are required to + get/set point coordinates. """ - assert ctx != self._ffi.NULL - bn_x = self._int_to_bn(x) - bn_y = self._int_to_bn(y) - nid_two_field = self._lib.OBJ_sn2nid(b"characteristic-two-field") assert nid_two_field != self._lib.NID_undef group = self._lib.EC_KEY_get0_group(ctx) assert group != self._ffi.NULL - point = self._lib.EC_POINT_new(group) - assert point != self._ffi.NULL - point = self._ffi.gc(point, self._lib.EC_POINT_free) - method = self._lib.EC_GROUP_method_of(group) assert method != self._ffi.NULL @@ -1124,6 +1113,28 @@ class Backend(object): assert set_func and get_func + return set_func, get_func, group + + def _ec_key_set_public_key_affine_coordinates(self, ctx, x, y): + """ + This is a port of EC_KEY_set_public_key_affine_coordinates that was + added in 1.0.1. + + Sets the public key point in the EC_KEY context to the affine x and y + values. + """ + + bn_x = self._int_to_bn(x) + bn_y = self._int_to_bn(y) + + set_func, get_func, group = ( + self._ec_key_determine_group_get_set_funcs(ctx) + ) + + point = self._lib.EC_POINT_new(group) + assert point != self._ffi.NULL + point = self._ffi.gc(point, self._lib.EC_POINT_free) + with self._tmp_bn_ctx() as bn_ctx: check_x = self._lib.BN_CTX_get(bn_ctx) check_y = self._lib.BN_CTX_get(bn_ctx) diff --git a/cryptography/hazmat/backends/openssl/ec.py b/cryptography/hazmat/backends/openssl/ec.py index 879d674a..369b185b 100644 --- a/cryptography/hazmat/backends/openssl/ec.py +++ b/cryptography/hazmat/backends/openssl/ec.py @@ -203,35 +203,13 @@ class _EllipticCurvePublicKey(object): _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) def public_numbers(self): - bn_ctx = self._backend._lib.BN_CTX_new() - assert bn_ctx != self._backend._ffi.NULL - bn_ctx = self._backend._ffi.gc(bn_ctx, self._backend._lib.BN_CTX_free) - - group = self._backend._lib.EC_KEY_get0_group(self._ec_key) - assert group != self._backend._ffi.NULL - - method = self._backend._lib.EC_GROUP_method_of(group) - assert method != self._backend._ffi.NULL - - nid = self._backend._lib.EC_METHOD_get_field_type(method) - assert nid != self._backend._lib.NID_undef - - nid_two_field = self._backend._lib.OBJ_sn2nid( - b"characteristic-two-field" + set_func, get_func, group = ( + self._backend._ec_key_determine_group_get_set_funcs(self._ec_key) ) - assert nid_two_field != self._backend._lib.NID_undef - - if nid == nid_two_field and self._backend._lib.Cryptography_HAS_EC2M: - get_func = self._backend._lib.EC_POINT_get_affine_coordinates_GF2m - else: - get_func = self._backend._lib.EC_POINT_get_affine_coordinates_GFp - point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) assert point != self._backend._ffi.NULL - try: - self._backend._lib.BN_CTX_start(bn_ctx) - + with self._backend._tmp_bn_ctx() as bn_ctx: bn_x = self._backend._lib.BN_CTX_get(bn_ctx) bn_y = self._backend._lib.BN_CTX_get(bn_ctx) @@ -240,8 +218,6 @@ class _EllipticCurvePublicKey(object): x = self._backend._bn_to_int(bn_x) y = self._backend._bn_to_int(bn_y) - finally: - self._backend._lib.BN_CTX_end(bn_ctx) return ec.EllipticCurvePublicNumbers( x=x, -- cgit v1.2.3 From 7ee7d5ba847b0e1c6db4afc02fa858ac8734ba6b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 27 Sep 2014 09:43:14 -0500 Subject: fix invalid dict reference in test --- tests/hazmat/primitives/test_ec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py index a2613db8..f9eab7ac 100644 --- a/tests/hazmat/primitives/test_ec.py +++ b/tests/hazmat/primitives/test_ec.py @@ -142,7 +142,7 @@ class TestECWithNumbers(object): )) ) def test_with_numbers(self, backend, vector, hash_type): - curve_type = _CURVE_TYPES[vector['curve']] + curve_type = ec._CURVE_TYPES[vector['curve']] _skip_ecdsa_vector(backend, curve_type, hash_type) -- cgit v1.2.3