aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py44
-rw-r--r--docs/hazmat/backends/openssl.rst1
-rw-r--r--tests/hazmat/primitives/test_rsa.py57
3 files changed, 96 insertions, 6 deletions
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 6da90cef..d8869328 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -20,7 +20,7 @@ from cryptography.exceptions import (
UnsupportedAlgorithm, InvalidTag, InternalError
)
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, HashBackend, HMACBackend, PBKDF2HMACBackend
+ CipherBackend, HashBackend, HMACBackend, PBKDF2HMACBackend, RSABackend
)
from cryptography.hazmat.primitives import interfaces, hashes
from cryptography.hazmat.primitives.ciphers.algorithms import (
@@ -30,12 +30,14 @@ from cryptography.hazmat.primitives.ciphers.modes import (
CBC, CTR, ECB, OFB, CFB, GCM,
)
from cryptography.hazmat.bindings.openssl.binding import Binding
+from cryptography.hazmat.primitives.asymmetric import rsa
@utils.register_interface(CipherBackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
@utils.register_interface(PBKDF2HMACBackend)
+@utils.register_interface(RSABackend)
class Backend(object):
"""
OpenSSL API binding interfaces.
@@ -259,6 +261,46 @@ class Backend(object):
)
)
+ def _bn_to_int(self, bn):
+ hex_cdata = self._lib.BN_bn2hex(bn)
+ assert hex_cdata != self._ffi.NULL
+ hex_str = self._ffi.string(hex_cdata)
+ self._lib.OPENSSL_free(hex_cdata)
+ return int(hex_str, 16)
+
+ def generate_rsa_private_key(self, public_exponent, key_size):
+ if public_exponent < 3:
+ raise ValueError("public_exponent must be >= 3")
+
+ if public_exponent & 1 == 0:
+ raise ValueError("public_exponent must be odd")
+
+ if key_size < 512:
+ raise ValueError("key_size must be at least 512-bits")
+
+ ctx = backend._lib.RSA_new()
+ ctx = backend._ffi.gc(ctx, backend._lib.RSA_free)
+
+ bn = backend._lib.BN_new()
+ assert bn != self._ffi.NULL
+ bn = backend._ffi.gc(bn, backend._lib.BN_free)
+
+ res = backend._lib.BN_set_word(bn, public_exponent)
+ assert res == 1
+
+ res = backend._lib.RSA_generate_key_ex(
+ ctx, key_size, bn, backend._ffi.NULL
+ )
+ assert res == 1
+
+ return rsa.RSAPrivateKey(
+ p=self._bn_to_int(ctx.p),
+ q=self._bn_to_int(ctx.q),
+ private_exponent=self._bn_to_int(ctx.d),
+ public_exponent=self._bn_to_int(ctx.e),
+ modulus=self._bn_to_int(ctx.n),
+ )
+
class GetCipherByName(object):
def __init__(self, fmt):
diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst
index ea72af96..e3880875 100644
--- a/docs/hazmat/backends/openssl.rst
+++ b/docs/hazmat/backends/openssl.rst
@@ -15,6 +15,7 @@ The `OpenSSL`_ C library.
* :class:`~cryptography.hazmat.backends.interfaces.HashBackend`
* :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
* :class:`~cryptography.hazmat.backends.interfaces.PBKDF2HMACBackend`
+ * :class:`~cryptography.hazmat.backends.interfaces.RSABackend`
It also exposes the following:
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index e2aca028..fdd55e73 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -14,6 +14,7 @@
from __future__ import absolute_import, division, print_function
+import itertools
import os
import pytest
@@ -23,8 +24,53 @@ from cryptography.hazmat.primitives.asymmetric import rsa
from ...utils import load_pkcs1_vectors, load_vectors_from_file
+def _check_rsa_private_key(skey):
+ assert skey
+ assert skey.modulus
+ assert skey.public_exponent
+ assert skey.private_exponent
+ assert skey.p * skey.q == skey.modulus
+ assert skey.key_size
+
+ pkey = skey.public_key()
+ assert pkey
+ assert skey.modulus == pkey.modulus
+ assert skey.public_exponent == pkey.public_exponent
+ assert skey.key_size == pkey.key_size
+
+
+@pytest.mark.rsa
class TestRSA(object):
@pytest.mark.parametrize(
+ "public_exponent,key_size",
+ itertools.product(
+ (3, 5, 65537),
+ (1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1536, 2048)
+ )
+ )
+ def test_generate_rsa_keys(self, backend, public_exponent, key_size):
+ skey = backend.generate_rsa_private_key(public_exponent, key_size)
+ _check_rsa_private_key(skey)
+ assert skey.key_size == key_size
+ assert skey.public_exponent == public_exponent
+
+ def test_generate_bad_rsa_key(self, backend):
+ with pytest.raises(ValueError):
+ backend.generate_rsa_private_key(public_exponent=1, key_size=2048)
+
+ with pytest.raises(ValueError):
+ backend.generate_rsa_private_key(public_exponent=4, key_size=2048)
+
+ def test_cant_generate_insecure_tiny_key(self, backend):
+ with pytest.raises(ValueError):
+ backend.generate_rsa_private_key(public_exponent=65537,
+ key_size=511)
+
+ with pytest.raises(ValueError):
+ backend.generate_rsa_private_key(public_exponent=65537,
+ key_size=256)
+
+ @pytest.mark.parametrize(
"pkcs1_example",
load_vectors_from_file(
os.path.join(
@@ -36,12 +82,15 @@ class TestRSA(object):
secret, public = pkcs1_example
skey = rsa.RSAPrivateKey(**secret)
+ assert skey
+ _check_rsa_private_key(skey)
+
pkey = rsa.RSAPublicKey(**public)
- pkey2 = skey.public_key()
+ assert pkey
- assert skey and pkey and pkey2
+ pkey2 = skey.public_key()
+ assert pkey2
- assert skey.modulus
assert skey.modulus == pkey.modulus
assert skey.modulus == skey.n
assert skey.public_exponent == pkey.public_exponent
@@ -58,8 +107,6 @@ class TestRSA(object):
assert skey.key_size == pkey.key_size
assert skey.key_size == pkey2.key_size
- assert skey.p * skey.q == skey.modulus
-
def test_invalid_private_key_argument_types(self):
with pytest.raises(TypeError):
rsa.RSAPrivateKey(None, None, None, None, None)