From aada52b3923bcd41f548fc7fce89c204d0cbbc54 Mon Sep 17 00:00:00 2001 From: tuxxy Date: Wed, 7 Mar 2018 18:29:41 -0700 Subject: [PATCH 1/7] Implement to_cryptography_pubkey/privkey in keys.py --- umbral/keys.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/umbral/keys.py b/umbral/keys.py index 3f19dce..3ea5f68 100644 --- a/umbral/keys.py +++ b/umbral/keys.py @@ -3,10 +3,13 @@ import base64 from typing import Union +from nacl.secret import SecretBox from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.kdf.scrypt import Scrypt from cryptography.hazmat.backends import default_backend -from nacl.secret import SecretBox +from cryptography.hazmat.backends.openssl.ec import ( + _EllipticCurvePublicKey, _EllipticCurvePrivateKey +) from umbral.config import default_params from umbral.point import Point, BigNum @@ -108,6 +111,43 @@ class UmbralPrivateKey(object): """ return UmbralPublicKey(self.bn_key * self.params.g) + def to_cryptography_privkey(self): + """ + Returns a cryptography.io EllipticCurvePrivateKey from the Umbral key. + """ + backend = default_backend() + + backend.openssl_assert(self.bn_key.group != backend._ffi.NULL) + backend.openssl_assert(self.bn_key.bignum != backend._ffi.NULL) + + ec_key = backend._lib.EC_KEY_new() + backend.openssl_assert(ec_key != backend._ffi.NULL) + ec_key = backend._ffi.gc(ec_key, backend._lib.EC_KEY_free) + + res = backend._lib.EC_KEY_set_group(ec_key, self.bn_key.group) + backend.openssl_assert(res == 1) + + res = backend._lib.EC_KEY_set_private_key(ec_key, self.bn_key.bignum) + backend.openssl_assert(res == 1) + + # Get public key + point = backend._lib.EC_POINT_new(self.bn_key.group) + backend.openssl_assert(point != backend._ffi.NULL) + point = backend._ffi.gc(point, backend._lib.EC_POINT_free) + + with backend._tmp_bn_ctx() as bn_ctx: + res = backend._lib.EC_POINT_mul( + self.bn_key.group, point, self.bn_key.bignum, backend._ffi.NULL, + backend._ffi.NULL, bn_ctx + ) + backend.openssl_assert(res == 1) + + res = backend._lib.EC_KEY_set_public_key(ec_key, point) + backend.openssl_assert(res == 1) + + evp_pkey = backend._ec_cdata_to_evp_pkey(ec_key) + return _EllipticCurvePrivateKey(backend, ec_key, evp_pkey) + class UmbralPublicKey(object): def __init__(self, point_key, params: UmbralParameters=None): @@ -152,6 +192,28 @@ class UmbralPublicKey(object): def get_pubkey(self): raise NotImplementedError + def to_cryptography_pubkey(self): + """ + Returns a cryptography.io EllipticCurvePublicKey from the Umbral key. + """ + backend = default_backend() + + backend.openssl_assert(self.point_key.group != backend._ffi.NULL) + backend.openssl_assert(self.point_key.ec_point != backend._ffi.NULL) + + ec_key = backend._lib.EC_KEY_new() + backend.openssl_assert(ec_key != backend._ffi.NULL) + ec_key = backend._ffi.gc(ec_key, backend._lib.EC_KEY_free) + + res = backend._lib.EC_KEY_set_group(ec_key, self.point_key.group) + backend.openssl_assert(res == 1) + + res = backend._lib.EC_KEY_set_public_key(ec_key, self.point_key.ec_point) + backend.openssl_assert(res == 1) + + evp_pkey = backend._ec_cdata_to_evp_pkey(ec_key) + return _EllipticCurvePublicKey(backend, ec_key, evp_pkey) + def __bytes__(self): """ Returns an Umbral Public key as a bytestring. From 9578a3d52edcda3556eb6b83153ecac3d614b2f5 Mon Sep 17 00:00:00 2001 From: tuxxy Date: Wed, 7 Mar 2018 18:30:25 -0700 Subject: [PATCH 2/7] Remove to_cryptography_pub_key and to_cryptography_priv_key on bignum and point --- umbral/bignum.py | 36 ------------------------------------ umbral/point.py | 21 --------------------- 2 files changed, 57 deletions(-) diff --git a/umbral/bignum.py b/umbral/bignum.py index 2e74568..ce1c2b2 100644 --- a/umbral/bignum.py +++ b/umbral/bignum.py @@ -3,7 +3,6 @@ import os from cryptography.hazmat.backends.openssl import backend from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.backends.openssl.ec import _EllipticCurvePrivateKey from umbral.config import default_curve from umbral.utils import get_curve_keysize_bytes @@ -105,41 +104,6 @@ class BigNum(object): return int.to_bytes(int(self), size, 'big') - def to_cryptography_priv_key(self): - """ - Converts the BigNum object to a cryptography.io EllipticCurvePrivateKey - """ - backend.openssl_assert(self.group != backend._ffi.NULL) - backend.openssl_assert(self.bignum != backend._ffi.NULL) - - ec_key = backend._lib.EC_KEY_new() - backend.openssl_assert(ec_key != backend._ffi.NULL) - ec_key = backend._ffi.gc(ec_key, backend._lib.EC_KEY_free) - - res = backend._lib.EC_KEY_set_group(ec_key, self.group) - backend.openssl_assert(res == 1) - - res = backend._lib.EC_KEY_set_private_key(ec_key, self.bignum) - backend.openssl_assert(res == 1) - - # Get public key - point = backend._lib.EC_POINT_new(self.group) - backend.openssl_assert(point != backend._ffi.NULL) - point = backend._ffi.gc(point, backend._lib.EC_POINT_free) - - with backend._tmp_bn_ctx() as bn_ctx: - res = backend._lib.EC_POINT_mul( - self.group, point, self.bignum, backend._ffi.NULL, - backend._ffi.NULL, bn_ctx - ) - backend.openssl_assert(res == 1) - - res = backend._lib.EC_KEY_set_public_key(ec_key, point) - backend.openssl_assert(res == 1) - - evp_pkey = backend._ec_cdata_to_evp_pkey(ec_key) - return _EllipticCurvePrivateKey(backend, ec_key, evp_pkey) - def __int__(self): """ Converts the BigNum to a Python int. diff --git a/umbral/point.py b/umbral/point.py index f3993de..cd6ffbc 100644 --- a/umbral/point.py +++ b/umbral/point.py @@ -3,7 +3,6 @@ from cryptography.hazmat.backends.openssl import backend from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import hashes from cryptography.exceptions import InternalError -from cryptography.hazmat.backends.openssl.ec import _EllipticCurvePublicKey from umbral.config import default_curve from umbral.utils import get_curve_keysize_bytes @@ -214,26 +213,6 @@ class Point(object): return BigNum(order, curve_nid, group, order) - def to_cryptography_pub_key(self): - """ - Converts the Point object to a cryptography.io EllipticCurvePublicKey - """ - backend.openssl_assert(self.group != backend._ffi.NULL) - backend.openssl_assert(self.ec_point != backend._ffi.NULL) - - ec_key = backend._lib.EC_KEY_new() - backend.openssl_assert(ec_key != backend._ffi.NULL) - ec_key = backend._ffi.gc(ec_key, backend._lib.EC_KEY_free) - - res = backend._lib.EC_KEY_set_group(ec_key, self.group) - backend.openssl_assert(res == 1) - - res = backend._lib.EC_KEY_set_public_key(ec_key, self.ec_point) - backend.openssl_assert(res == 1) - - evp_pkey = backend._ec_cdata_to_evp_pkey(ec_key) - return _EllipticCurvePublicKey(backend, ec_key, evp_pkey) - def __eq__(self, other): """ Compares two EC_POINTS for equality. From 2b7742f9d27c0472bf45e40934af6a8963d433f0 Mon Sep 17 00:00:00 2001 From: tuxxy Date: Wed, 7 Mar 2018 18:30:40 -0700 Subject: [PATCH 3/7] Add tests --- tests/test_keys/test_umbral_keys.py | 13 +++++++++++++ .../test_bignum/test_bignum_methods.py | 6 ------ .../test_point/test_point_serializers.py | 8 -------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/tests/test_keys/test_umbral_keys.py b/tests/test_keys/test_umbral_keys.py index ccde83b..9e1e9bc 100644 --- a/tests/test_keys/test_umbral_keys.py +++ b/tests/test_keys/test_umbral_keys.py @@ -50,3 +50,16 @@ def test_public_key_to_bytes(): key_bytes = bytes(umbral_key) assert type(key_bytes) == bytes + + +def test_umbral_key_to_cryptography_keys(): + umbral_priv_key = keys.UmbralPrivateKey.gen_key() + umbral_pub_key = umbral_priv_key.get_pubkey() + + crypto_privkey = umbral_priv_key.to_cryptography_privkey() + assert int(umbral_priv_key.bn_key) == crypto_privkey.private_numbers().private_value + + crypto_pubkey = umbral_pub_key.to_cryptography_pubkey() + umbral_affine = umbral_pub_key.point_key.to_affine() + x, y = crypto_pubkey.public_numbers().x, crypto_pubkey.public_numbers().y + assert umbral_affine == (x, y) diff --git a/tests/test_primitives/test_bignum/test_bignum_methods.py b/tests/test_primitives/test_bignum/test_bignum_methods.py index 3a3c600..83cc287 100644 --- a/tests/test_primitives/test_bignum/test_bignum_methods.py +++ b/tests/test_primitives/test_bignum/test_bignum_methods.py @@ -11,9 +11,3 @@ def test_cast_bignum_to_int(): y = BigNum.from_int(x) assert x == y - - -def test_bignum_to_cryptography_privkey(): - bn = BigNum.gen_rand() - crypto_privkey = bn.to_cryptography_priv_key() - assert int(bn) == crypto_privkey.private_numbers().private_value diff --git a/tests/test_primitives/test_point/test_point_serializers.py b/tests/test_primitives/test_point/test_point_serializers.py index 5964eff..39d1788 100644 --- a/tests/test_primitives/test_point/test_point_serializers.py +++ b/tests/test_primitives/test_point/test_point_serializers.py @@ -65,14 +65,6 @@ def test_affine(point_affine, nid, curve): assert point_affine == point_affine2 -def test_point_to_cryptography_pubkey(random_ec_point2): - crypto_pub_key = random_ec_point2.to_cryptography_pub_key() - p_affine = random_ec_point2.to_affine() - x, y = crypto_pub_key.public_numbers().x, crypto_pub_key.public_numbers().y - crypto_affine = (x, y) - assert p_affine == crypto_affine - - def test_invalid_points(random_ec_point2): point_bytes = bytearray(random_ec_point2.to_bytes(is_compressed=False)) From 1d96f84fca95d1abfb7a1a1fa0c81b2410d2f04c Mon Sep 17 00:00:00 2001 From: tuxxy Date: Wed, 7 Mar 2018 18:37:33 -0700 Subject: [PATCH 4/7] Uses a constant CHAHCA20_KEY_SIZE instead of unused SecretBox constant --- umbral/pre.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/umbral/pre.py b/umbral/pre.py index d5839c7..cedcf5a 100644 --- a/umbral/pre.py +++ b/umbral/pre.py @@ -3,7 +3,6 @@ import hmac from typing import Tuple, Union, List from cryptography.hazmat.primitives.asymmetric import ec -from nacl.secret import SecretBox from umbral.bignum import BigNum, hash_to_bn from umbral.config import default_params, default_curve @@ -17,6 +16,9 @@ from umbral.utils import poly_eval, lambda_coeff, kdf, get_curve_keysize_bytes from io import BytesIO +CHACHA20_KEY_SIZE = 32 + + class GenericUmbralError(Exception): pass @@ -445,7 +447,7 @@ def encrypt(alice_pubkey: UmbralPublicKey, plaintext: bytes) -> Tuple[bytes, Cap Returns the ciphertext and the KEM Capsule. """ - key, capsule = _encapsulate(alice_pubkey.point_key, SecretBox.KEY_SIZE) + key, capsule = _encapsulate(alice_pubkey.point_key, CHACHA20_KEY_SIZE) capsule_bytes = bytes(capsule) From 9c348eb9dff57ba65573af54f0f3c26a8f085634 Mon Sep 17 00:00:00 2001 From: jMyles Date: Thu, 8 Mar 2018 09:54:18 -0800 Subject: [PATCH 5/7] Cleaner names for OpenSSL operations and results. Also, closing the context manager when it's no longer needed. --- umbral/keys.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/umbral/keys.py b/umbral/keys.py index 3ea5f68..66d96d2 100644 --- a/umbral/keys.py +++ b/umbral/keys.py @@ -120,30 +120,30 @@ class UmbralPrivateKey(object): backend.openssl_assert(self.bn_key.group != backend._ffi.NULL) backend.openssl_assert(self.bn_key.bignum != backend._ffi.NULL) - ec_key = backend._lib.EC_KEY_new() - backend.openssl_assert(ec_key != backend._ffi.NULL) - ec_key = backend._ffi.gc(ec_key, backend._lib.EC_KEY_free) + new_ec_key = backend._lib.EC_KEY_new() + backend.openssl_assert(new_ec_key != backend._ffi.NULL) + ec_key = backend._ffi.gc(new_ec_key, backend._lib.EC_KEY_free) - res = backend._lib.EC_KEY_set_group(ec_key, self.bn_key.group) - backend.openssl_assert(res == 1) + set_group_result = backend._lib.EC_KEY_set_group(ec_key, self.bn_key.group) + backend.openssl_assert(set_group_result == 1) - res = backend._lib.EC_KEY_set_private_key(ec_key, self.bn_key.bignum) - backend.openssl_assert(res == 1) + set_private_key_result = backend._lib.EC_KEY_set_private_key(ec_key, self.bn_key.bignum) + backend.openssl_assert(set_private_key_result == 1) # Get public key - point = backend._lib.EC_POINT_new(self.bn_key.group) - backend.openssl_assert(point != backend._ffi.NULL) - point = backend._ffi.gc(point, backend._lib.EC_POINT_free) + new_point = backend._lib.EC_POINT_new(self.bn_key.group) + backend.openssl_assert(new_point != backend._ffi.NULL) + point = backend._ffi.gc(new_point, backend._lib.EC_POINT_free) with backend._tmp_bn_ctx() as bn_ctx: - res = backend._lib.EC_POINT_mul( + multiplication_result = backend._lib.EC_POINT_mul( self.bn_key.group, point, self.bn_key.bignum, backend._ffi.NULL, backend._ffi.NULL, bn_ctx ) - backend.openssl_assert(res == 1) + backend.openssl_assert(multiplication_result == 1) - res = backend._lib.EC_KEY_set_public_key(ec_key, point) - backend.openssl_assert(res == 1) + set_public_key_result = backend._lib.EC_KEY_set_public_key(ec_key, point) + backend.openssl_assert(set_public_key_result == 1) evp_pkey = backend._ec_cdata_to_evp_pkey(ec_key) return _EllipticCurvePrivateKey(backend, ec_key, evp_pkey) From e57473b70c915b478c968b186c371a7f0a80c2a5 Mon Sep 17 00:00:00 2001 From: tuxxy Date: Thu, 8 Mar 2018 13:21:33 -0700 Subject: [PATCH 6/7] Reduce verbosity of names --- umbral/keys.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/umbral/keys.py b/umbral/keys.py index 66d96d2..106c9d3 100644 --- a/umbral/keys.py +++ b/umbral/keys.py @@ -120,30 +120,34 @@ class UmbralPrivateKey(object): backend.openssl_assert(self.bn_key.group != backend._ffi.NULL) backend.openssl_assert(self.bn_key.bignum != backend._ffi.NULL) - new_ec_key = backend._lib.EC_KEY_new() - backend.openssl_assert(new_ec_key != backend._ffi.NULL) - ec_key = backend._ffi.gc(new_ec_key, backend._lib.EC_KEY_free) + ec_key = backend._lib.EC_KEY_new() + backend.openssl_assert(ec_key != backend._ffi.NULL) + ec_key = backend._ffi.gc(ec_key, backend._lib.EC_KEY_free) - set_group_result = backend._lib.EC_KEY_set_group(ec_key, self.bn_key.group) + set_group_result = backend._lib.EC_KEY_set_group( + ec_key, self.bn_key.group + ) backend.openssl_assert(set_group_result == 1) - set_private_key_result = backend._lib.EC_KEY_set_private_key(ec_key, self.bn_key.bignum) - backend.openssl_assert(set_private_key_result == 1) + set_privkey_result = backend._lib.EC_KEY_set_private_key( + ec_key, self.bn_key.bignum + ) + backend.openssl_assert(set_privkey_result == 1) # Get public key - new_point = backend._lib.EC_POINT_new(self.bn_key.group) - backend.openssl_assert(new_point != backend._ffi.NULL) - point = backend._ffi.gc(new_point, backend._lib.EC_POINT_free) + point = backend._lib.EC_POINT_new(self.bn_key.group) + backend.openssl_assert(point != backend._ffi.NULL) + point = backend._ffi.gc(point, backend._lib.EC_POINT_free) with backend._tmp_bn_ctx() as bn_ctx: - multiplication_result = backend._lib.EC_POINT_mul( + mult_result = backend._lib.EC_POINT_mul( self.bn_key.group, point, self.bn_key.bignum, backend._ffi.NULL, backend._ffi.NULL, bn_ctx ) - backend.openssl_assert(multiplication_result == 1) + backend.openssl_assert(mult_result == 1) - set_public_key_result = backend._lib.EC_KEY_set_public_key(ec_key, point) - backend.openssl_assert(set_public_key_result == 1) + set_pubkey_result = backend._lib.EC_KEY_set_public_key(ec_key, point) + backend.openssl_assert(set_pubkey_result == 1) evp_pkey = backend._ec_cdata_to_evp_pkey(ec_key) return _EllipticCurvePrivateKey(backend, ec_key, evp_pkey) From ec88c7b8568693bb6e49f1ffa6842a45450faf13 Mon Sep 17 00:00:00 2001 From: tuxxy Date: Thu, 8 Mar 2018 13:22:02 -0700 Subject: [PATCH 7/7] Use better result names for OpenSSL calls in to_cryptography_pubkey (thanks, @jmyles) --- umbral/keys.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/umbral/keys.py b/umbral/keys.py index 106c9d3..eb362a1 100644 --- a/umbral/keys.py +++ b/umbral/keys.py @@ -209,11 +209,15 @@ class UmbralPublicKey(object): backend.openssl_assert(ec_key != backend._ffi.NULL) ec_key = backend._ffi.gc(ec_key, backend._lib.EC_KEY_free) - res = backend._lib.EC_KEY_set_group(ec_key, self.point_key.group) - backend.openssl_assert(res == 1) + set_group_result = backend._lib.EC_KEY_set_group( + ec_key, self.point_key.group + ) + backend.openssl_assert(set_group_result == 1) - res = backend._lib.EC_KEY_set_public_key(ec_key, self.point_key.ec_point) - backend.openssl_assert(res == 1) + set_pubkey_result = backend._lib.EC_KEY_set_public_key( + ec_key, self.point_key.ec_point + ) + backend.openssl_assert(set_pubkey_result == 1) evp_pkey = backend._ec_cdata_to_evp_pkey(ec_key) return _EllipticCurvePublicKey(backend, ec_key, evp_pkey)