diff options
Diffstat (limited to 'cryptography/hazmat')
| -rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 395 | ||||
| -rw-r--r-- | cryptography/hazmat/bindings/openssl/ssl.py | 45 | ||||
| -rw-r--r-- | cryptography/hazmat/primitives/asymmetric/ec.py | 186 | ||||
| -rw-r--r-- | cryptography/hazmat/primitives/interfaces.py | 94 | ||||
| -rw-r--r-- | cryptography/hazmat/primitives/serialization.py | 8 |
5 files changed, 628 insertions, 100 deletions
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index ffe09663..7746dafb 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -25,13 +25,13 @@ from cryptography.exceptions import ( UnsupportedAlgorithm, _Reasons ) from cryptography.hazmat.backends.interfaces import ( - CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend, - PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend, + CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend, + HashBackend, PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend, TraditionalOpenSSLSerializationBackend ) from cryptography.hazmat.bindings.openssl.binding import Binding from cryptography.hazmat.primitives import hashes, interfaces -from cryptography.hazmat.primitives.asymmetric import dsa, rsa +from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa from cryptography.hazmat.primitives.asymmetric.padding import ( MGF1, OAEP, PKCS1v15, PSS ) @@ -51,12 +51,13 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError", @utils.register_interface(CipherBackend) @utils.register_interface(CMACBackend) @utils.register_interface(DSABackend) +@utils.register_interface(EllipticCurveBackend) @utils.register_interface(HashBackend) @utils.register_interface(HMACBackend) @utils.register_interface(PBKDF2HMACBackend) +@utils.register_interface(PKCS8SerializationBackend) @utils.register_interface(RSABackend) @utils.register_interface(TraditionalOpenSSLSerializationBackend) -@utils.register_interface(PKCS8SerializationBackend) class Backend(object): """ OpenSSL API binding interfaces. @@ -425,8 +426,8 @@ class Backend(object): The char* is the storage for the BIO and it must stay alive until the BIO is finished with. """ - data_char_p = backend._ffi.new("char[]", data) - bio = backend._lib.BIO_new_mem_buf( + data_char_p = self._ffi.new("char[]", data) + bio = self._lib.BIO_new_mem_buf( data_char_p, len(data) ) assert bio != self._ffi.NULL @@ -890,6 +891,236 @@ class Backend(object): return self._evp_pkey_to_private_key(evp_pkey) + def elliptic_curve_supported(self, curve): + if self._lib.Cryptography_HAS_EC != 1: + return False + + curves = self._supported_curves() + return curve.name.encode("ascii") in curves + + def elliptic_curve_signature_algorithm_supported( + self, signature_algorithm, curve + ): + if self._lib.Cryptography_HAS_EC != 1: + return False + + # We only support ECDSA right now. + if isinstance(signature_algorithm, ec.ECDSA) is False: + return False + + # Before 0.9.8m OpenSSL can't cope with digests longer than the curve. + if ( + self._lib.OPENSSL_VERSION_NUMBER < 0x009080df and + curve.key_size < signature_algorithm.algorithm.digest_size * 8 + ): + return False + + return self.elliptic_curve_supported(curve) + + def _supported_curves(self): + if self._lib.Cryptography_HAS_EC != 1: + return [] + + num_curves = self._lib.EC_get_builtin_curves(self._ffi.NULL, 0) + curve_array = self._ffi.new("EC_builtin_curve[]", num_curves) + num_curves_assigned = self._lib.EC_get_builtin_curves( + curve_array, num_curves) + assert num_curves == num_curves_assigned + + curves = [ + self._ffi.string(self._lib.OBJ_nid2sn(curve.nid)).decode() + for curve in curve_array + ] + + curve_aliases = { + "prime192v1": "secp192r1", + "prime256v1": "secp256r1" + } + return [ + curve_aliases.get(curve, curve) + for curve in curves + ] + + def _create_ecdsa_signature_ctx(self, private_key, ecdsa): + return _ECDSASignatureContext(self, private_key, ecdsa.algorithm) + + def _create_ecdsa_verification_ctx(self, public_key, signature, ecdsa): + return _ECDSAVerificationContext(self, public_key, signature, + ecdsa.algorithm) + + def generate_elliptic_curve_private_key(self, curve): + """ + Generate a new private key on the named curve. + """ + + curve_nid = self._elliptic_curve_to_nid(curve) + + ctx = self._lib.EC_KEY_new_by_curve_name(curve_nid) + assert ctx != self._ffi.NULL + ctx = self._ffi.gc(ctx, self._lib.EC_KEY_free) + + res = self._lib.EC_KEY_generate_key(ctx) + assert res == 1 + + res = self._lib.EC_KEY_check_key(ctx) + assert res == 1 + + return _EllipticCurvePrivateKey(self, ctx, curve) + + def elliptic_curve_private_key_from_numbers(self, numbers): + ec_key = self._ec_key_cdata_from_private_numbers(numbers) + return _EllipticCurvePrivateKey(self, ec_key, + numbers.public_numbers.curve) + + def elliptic_curve_public_key_from_numbers(self, numbers): + ec_key = self._ec_key_cdata_from_public_numbers(numbers) + return _EllipticCurvePublicKey(self, ec_key, numbers.curve) + + def _elliptic_curve_to_nid(self, curve): + """ + Get the NID for a curve name. + """ + + curve_aliases = { + "secp192r1": "prime192v1", + "secp256r1": "prime256v1" + } + + curve_name = curve_aliases.get(curve.name, curve.name) + + curve_nid = self._lib.OBJ_sn2nid(curve_name.encode()) + if curve_nid == self._lib.NID_undef: + raise UnsupportedAlgorithm( + "{0} is not a supported elliptic curve".format(curve.name), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE + ) + return curve_nid + + def _ec_key_cdata_from_private_numbers(self, numbers): + """ + Build an EC_KEY from a private key object. + """ + + public = numbers.public_numbers + + curve_nid = self._elliptic_curve_to_nid(public.curve) + + ctx = self._lib.EC_KEY_new_by_curve_name(curve_nid) + assert ctx != self._ffi.NULL + ctx = self._ffi.gc(ctx, self._lib.EC_KEY_free) + + ctx = self._ec_key_set_public_key_affine_coordinates( + ctx, public.x, public.y) + + res = self._lib.EC_KEY_set_private_key( + ctx, self._int_to_bn(numbers.private_value)) + assert res == 1 + + return ctx + + def _ec_key_cdata_from_public_numbers(self, numbers): + """ + Build an EC_KEY from a public key object. + """ + + curve_nid = self._elliptic_curve_to_nid(numbers.curve) + + ctx = self._lib.EC_KEY_new_by_curve_name(curve_nid) + assert ctx != self._ffi.NULL + ctx = self._ffi.gc(ctx, self._lib.EC_KEY_free) + + ctx = self._ec_key_set_public_key_affine_coordinates( + ctx, numbers.x, numbers.y) + + return ctx + + def _public_ec_key_from_private_ec_key(self, private_key_cdata): + """ + Copy the public portions out of one EC key into a new one. + """ + + group = self._lib.EC_KEY_get0_group(private_key_cdata) + assert group != self._ffi.NULL + + curve_nid = self._lib.EC_GROUP_get_curve_name(group) + + ctx = self._lib.EC_KEY_new_by_curve_name(curve_nid) + assert ctx != self._ffi.NULL + ctx = self._ffi.gc(ctx, self._lib.EC_KEY_free) + + point = self._lib.EC_KEY_get0_public_key(private_key_cdata) + assert point != self._ffi.NULL + + res = self._lib.EC_KEY_set_public_key(ctx, point) + assert res == 1 + + return ctx + + 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. + """ + + 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 + + bn_ctx = self._lib.BN_CTX_new() + assert bn_ctx != self._ffi.NULL + bn_ctx = self._ffi.gc(bn_ctx, self._lib.BN_CTX_free) + + 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 + + nid = self._lib.EC_METHOD_get_field_type(method) + assert nid != self._lib.NID_undef + + check_x = self._lib.BN_CTX_get(bn_ctx) + check_y = self._lib.BN_CTX_get(bn_ctx) + + if nid == nid_two_field and self._lib.Cryptography_HAS_EC2M: + set_func = self._lib.EC_POINT_set_affine_coordinates_GF2m + get_func = self._lib.EC_POINT_get_affine_coordinates_GF2m + else: + set_func = self._lib.EC_POINT_set_affine_coordinates_GFp + get_func = self._lib.EC_POINT_get_affine_coordinates_GFp + + assert set_func and get_func + + res = set_func(group, point, bn_x, bn_y, bn_ctx) + assert res == 1 + + res = get_func(group, point, check_x, check_y, bn_ctx) + assert res == 1 + + assert ( + self._lib.BN_cmp(bn_x, check_x) == 0 and + self._lib.BN_cmp(bn_y, check_y) == 0 + ) + + res = self._lib.EC_KEY_set_public_key(ctx, point) + assert res == 1 + + res = self._lib.EC_KEY_check_key(ctx) + assert res == 1 + + return ctx + class GetCipherByName(object): def __init__(self, fmt): @@ -1727,4 +1958,156 @@ class _CMACContext(object): ) +def _truncate_digest_for_ecdsa(ec_key_cdata, digest, backend): + _lib = backend._lib + _ffi = backend._ffi + + digest_len = len(digest) + + group = _lib.EC_KEY_get0_group(ec_key_cdata) + + bn_ctx = _lib.BN_CTX_new() + assert bn_ctx != _ffi.NULL + bn_ctx = _ffi.gc(bn_ctx, _lib.BN_CTX_free) + + order = _lib.BN_CTX_get(bn_ctx) + assert order != _ffi.NULL + + res = _lib.EC_GROUP_get_order(group, order, bn_ctx) + assert res == 1 + + order_bits = _lib.BN_num_bits(order) + + if 8 * digest_len > order_bits: + digest_len = (order_bits + 7) // 8 + digest = digest[:digest_len] + + if 8 * digest_len > order_bits: + rshift = 8 - (order_bits & 0x7) + assert rshift > 0 and rshift < 8 + + mask = 0xFF >> rshift << rshift + + # Set the bottom rshift bits to 0 + digest = digest[:-1] + six.int2byte(six.byte2int(digest[-1]) & mask) + + return digest + + +@utils.register_interface(interfaces.AsymmetricSignatureContext) +class _ECDSASignatureContext(object): + def __init__(self, backend, private_key, algorithm): + self._backend = backend + self._private_key = private_key + self._digest = hashes.Hash(algorithm, backend) + + def update(self, data): + self._digest.update(data) + + def finalize(self): + ec_key = self._private_key._ec_key + + digest = self._digest.finalize() + + digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend) + + max_size = self._backend._lib.ECDSA_size(ec_key) + assert max_size > 0 + + sigbuf = self._backend._ffi.new("char[]", max_size) + siglen_ptr = self._backend._ffi.new("unsigned int[]", 1) + res = self._backend._lib.ECDSA_sign( + 0, + digest, + len(digest), + sigbuf, + siglen_ptr, + ec_key + ) + assert res == 1 + return self._backend._ffi.buffer(sigbuf)[:siglen_ptr[0]] + + +@utils.register_interface(interfaces.AsymmetricVerificationContext) +class _ECDSAVerificationContext(object): + def __init__(self, backend, public_key, signature, algorithm): + self._backend = backend + self._public_key = public_key + self._signature = signature + self._digest = hashes.Hash(algorithm, backend) + + def update(self, data): + self._digest.update(data) + + def verify(self): + ec_key = self._public_key._ec_key + + digest = self._digest.finalize() + + digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend) + + res = self._backend._lib.ECDSA_verify( + 0, + digest, + len(digest), + self._signature, + len(self._signature), + ec_key + ) + if res != 1: + self._backend._consume_errors() + raise InvalidSignature + return True + + +@utils.register_interface(interfaces.EllipticCurvePrivateKey) +class _EllipticCurvePrivateKey(object): + def __init__(self, backend, ec_key_cdata, curve): + self._backend = backend + self._ec_key = ec_key_cdata + self._curve = curve + + @property + def curve(self): + return self._curve + + def signer(self, signature_algorithm): + if isinstance(signature_algorithm, ec.ECDSA): + return self._backend._create_ecdsa_signature_ctx( + self, signature_algorithm) + else: + raise UnsupportedAlgorithm( + "Unsupported elliptic curve signature algorithm.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + + def public_key(self): + public_ec_key = self._backend._public_ec_key_from_private_ec_key( + self._ec_key + ) + + return _EllipticCurvePublicKey( + self._backend, public_ec_key, self._curve) + + +@utils.register_interface(interfaces.EllipticCurvePublicKey) +class _EllipticCurvePublicKey(object): + def __init__(self, backend, ec_key_cdata, curve): + self._backend = backend + self._ec_key = ec_key_cdata + self._curve = curve + + @property + def curve(self): + return self._curve + + def verifier(self, signature, signature_algorithm): + if isinstance(signature_algorithm, ec.ECDSA): + return self._backend._create_ecdsa_verification_ctx( + self, signature, signature_algorithm) + else: + raise UnsupportedAlgorithm( + "Unsupported elliptic curve signature algorithm.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + + backend = Backend() diff --git a/cryptography/hazmat/bindings/openssl/ssl.py b/cryptography/hazmat/bindings/openssl/ssl.py index 94b96d98..165bc7a1 100644 --- a/cryptography/hazmat/bindings/openssl/ssl.py +++ b/cryptography/hazmat/bindings/openssl/ssl.py @@ -46,6 +46,7 @@ static const long Cryptography_HAS_SSL_SET_SSL_CTX; static const long Cryptography_HAS_SSL_OP_NO_TICKET; static const long Cryptography_HAS_NETBSD_D1_METH; static const long Cryptography_HAS_NEXTPROTONEG; +static const long Cryptography_HAS_ALPN; static const long SSL_FILETYPE_PEM; static const long SSL_FILETYPE_ASN1; @@ -367,6 +368,21 @@ void SSL_get0_next_proto_negotiated(const SSL *, int sk_SSL_CIPHER_num(Cryptography_STACK_OF_SSL_CIPHER *); SSL_CIPHER *sk_SSL_CIPHER_value(Cryptography_STACK_OF_SSL_CIPHER *, int); + +/* ALPN APIs were introduced in OpenSSL 1.0.2. To continue to support earlier + * versions some special handling of these is necessary. + */ +int SSL_CTX_set_alpn_protos(SSL_CTX *, const unsigned char*, unsigned); +int SSL_set_alpn_protos(SSL *, const unsigned char*, unsigned); +void SSL_CTX_set_alpn_select_cb(SSL_CTX *, + int (*) (SSL *, + const unsigned char **, + unsigned char *, + const unsigned char *, + unsigned int, + void *), + void *); +void SSL_get0_alpn_selected(const SSL *, const unsigned char **, unsigned *); """ CUSTOMIZATIONS = """ @@ -515,6 +531,28 @@ void (*SSL_get0_next_proto_negotiated)(const SSL *, #else static const long Cryptography_HAS_NEXTPROTONEG = 1; #endif + +// ALPN was added in OpenSSL 1.0.2. +#if OPENSSL_VERSION_NUMBER < 0x10002001L +int (*SSL_CTX_set_alpn_protos)(SSL_CTX *, + const unsigned char*, + unsigned) = NULL; +int (*SSL_set_alpn_protos)(SSL *, const unsigned char*, unsigned) = NULL; +void (*SSL_CTX_set_alpn_select_cb)(SSL_CTX *, + int (*) (SSL *, + const unsigned char **, + unsigned char *, + const unsigned char *, + unsigned int, + void *), + void *) = NULL; +void (*SSL_get0_alpn_selected)(const SSL *, + const unsigned char **, + unsigned *) = NULL; +static const long Cryptography_HAS_ALPN = 0; +#else +static const long Cryptography_HAS_ALPN = 1; +#endif """ CONDITIONAL_NAMES = { @@ -585,4 +623,11 @@ CONDITIONAL_NAMES = { "SSL_OP_LEGACY_SERVER_CONNECT", "SSL_get_secure_renegotiation_support", ], + + "Cryptography_HAS_ALPN": [ + "SSL_CTX_set_alpn_protos", + "SSL_set_alpn_protos", + "SSL_CTX_set_alpn_select_cb", + "SSL_get0_alpn_selected", + ] } diff --git a/cryptography/hazmat/primitives/asymmetric/ec.py b/cryptography/hazmat/primitives/asymmetric/ec.py index 1e49ad7b..220a419c 100644 --- a/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/cryptography/hazmat/primitives/asymmetric/ec.py @@ -15,9 +15,189 @@ from __future__ import absolute_import, division, print_function import six +from cryptography import utils from cryptography.hazmat.primitives import interfaces +@utils.register_interface(interfaces.EllipticCurve) +class SECT571R1(object): + @property + def name(self): + return "sect571r1" + + @property + def key_size(self): + return 571 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECT409R1(object): + @property + def name(self): + return "sect409r1" + + @property + def key_size(self): + return 409 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECT283R1(object): + @property + def name(self): + return "sect283r1" + + @property + def key_size(self): + return 283 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECT233R1(object): + @property + def name(self): + return "sect233r1" + + @property + def key_size(self): + return 233 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECT163R2(object): + @property + def name(self): + return "sect163r2" + + @property + def key_size(self): + return 163 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECT571K1(object): + @property + def name(self): + return "sect571k1" + + @property + def key_size(self): + return 571 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECT409K1(object): + @property + def name(self): + return "sect409k1" + + @property + def key_size(self): + return 409 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECT283K1(object): + @property + def name(self): + return "sect283k1" + + @property + def key_size(self): + return 283 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECT233K1(object): + @property + def name(self): + return "sect233k1" + + @property + def key_size(self): + return 233 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECT163K1(object): + @property + def name(self): + return "sect163k1" + + @property + def key_size(self): + return 163 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECP521R1(object): + @property + def name(self): + return "secp521r1" + + @property + def key_size(self): + return 521 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECP384R1(object): + @property + def name(self): + return "secp384r1" + + @property + def key_size(self): + return 384 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECP256R1(object): + @property + def name(self): + return "secp256r1" + + @property + def key_size(self): + return 256 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECP224R1(object): + @property + def name(self): + return "secp224r1" + + @property + def key_size(self): + return 224 + + +@utils.register_interface(interfaces.EllipticCurve) +class SECP192R1(object): + @property + def name(self): + return "secp192r1" + + @property + def key_size(self): + return 192 + + +@utils.register_interface(interfaces.EllipticCurveSignatureAlgorithm) +class ECDSA(object): + def __init__(self, algorithm): + self._algorithm = algorithm + + @property + def algorithm(self): + return self._algorithm + + +def generate_private_key(curve, backend): + return backend.generate_elliptic_curve_private_key(curve) + + class EllipticCurvePublicNumbers(object): def __init__(self, x, y, curve): if ( @@ -33,6 +213,9 @@ class EllipticCurvePublicNumbers(object): self._x = x self._curve = curve + def public_key(self, backend): + return backend.elliptic_curve_public_key_from_numbers(self) + @property def curve(self): return self._curve @@ -60,6 +243,9 @@ class EllipticCurvePrivateNumbers(object): self._private_value = private_value self._public_numbers = public_numbers + def private_key(self, backend): + return backend.elliptic_curve_private_key_from_numbers(self) + @property def private_value(self): return self._private_value diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index 0dd1d01a..d805bd1a 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -192,24 +192,6 @@ class RSAPrivateKey(object): """ @abc.abstractproperty - def modulus(self): - """ - The public modulus of the RSA key. - """ - - @abc.abstractproperty - def public_exponent(self): - """ - The public exponent of the RSA key. - """ - - @abc.abstractproperty - def private_exponent(self): - """ - The private exponent of the RSA key. - """ - - @abc.abstractproperty def key_size(self): """ The bit length of the public modulus. @@ -221,58 +203,6 @@ class RSAPrivateKey(object): The RSAPublicKey associated with this private key. """ - @abc.abstractproperty - def n(self): - """ - The public modulus of the RSA key. Alias for modulus. - """ - - @abc.abstractproperty - def p(self): - """ - One of the two primes used to generate d. - """ - - @abc.abstractproperty - def q(self): - """ - One of the two primes used to generate d. - """ - - @abc.abstractproperty - def d(self): - """ - The private exponent. This can be calculated using p and q. Alias for - private_exponent. - """ - - @abc.abstractproperty - def dmp1(self): - """ - A Chinese remainder theorem coefficient used to speed up RSA - calculations. Calculated as: d mod (p-1) - """ - - @abc.abstractproperty - def dmq1(self): - """ - A Chinese remainder theorem coefficient used to speed up RSA - calculations. Calculated as: d mod (q-1) - """ - - @abc.abstractproperty - def iqmp(self): - """ - A Chinese remainder theorem coefficient used to speed up RSA - calculations. The modular inverse of q modulo p - """ - - @abc.abstractproperty - def e(self): - """ - The public exponent of the RSA key. Alias for public_exponent. - """ - @six.add_metaclass(abc.ABCMeta) class RSAPublicKey(object): @@ -283,35 +213,11 @@ class RSAPublicKey(object): """ @abc.abstractproperty - def modulus(self): - """ - The public modulus of the RSA key. - """ - - @abc.abstractproperty - def public_exponent(self): - """ - The public exponent of the RSA key. - """ - - @abc.abstractproperty def key_size(self): """ The bit length of the public modulus. """ - @abc.abstractproperty - def n(self): - """ - The public modulus of the RSA key. Alias for modulus. - """ - - @abc.abstractproperty - def e(self): - """ - The public exponent of the RSA key. Alias for public_exponent. - """ - @six.add_metaclass(abc.ABCMeta) class DSAParameters(object): diff --git a/cryptography/hazmat/primitives/serialization.py b/cryptography/hazmat/primitives/serialization.py index ed73c4c4..056d4a06 100644 --- a/cryptography/hazmat/primitives/serialization.py +++ b/cryptography/hazmat/primitives/serialization.py @@ -24,3 +24,11 @@ def load_pem_pkcs8_private_key(data, password, backend): return backend.load_pkcs8_pem_private_key( data, password ) + + +def load_rsa_private_numbers(numbers, backend): + return backend.load_rsa_private_numbers(numbers) + + +def load_rsa_public_numbers(numbers, backend): + return backend.load_rsa_public_numbers(numbers) |
