aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst2
-rw-r--r--cryptography/hazmat/backends/multibackend.py57
-rw-r--r--cryptography/hazmat/primitives/asymmetric/rsa.py11
-rw-r--r--docs/hazmat/primitives/asymmetric/ec.rst4
-rw-r--r--docs/hazmat/primitives/asymmetric/rsa.rst26
-rw-r--r--tests/hazmat/backends/test_multibackend.py107
-rw-r--r--tests/hazmat/primitives/test_rsa.py37
7 files changed, 221 insertions, 23 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 13c62de5..a38534d4 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -18,7 +18,7 @@ Changelog
and
:class:`~cryptography.hazmat.backends.interfaces.TraditionalOpenSSLSerializationBackend`
support to the :doc:`/hazmat/backends/openssl`.
-
+* Added :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`.
0.4 - 2014-05-03
~~~~~~~~~~~~~~~~
diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py
index f3c79376..27ab0636 100644
--- a/cryptography/hazmat/backends/multibackend.py
+++ b/cryptography/hazmat/backends/multibackend.py
@@ -16,8 +16,8 @@ from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import (
- CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
- PBKDF2HMACBackend, RSABackend
+ CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend,
+ HashBackend, PBKDF2HMACBackend, RSABackend
)
@@ -28,6 +28,7 @@ from cryptography.hazmat.backends.interfaces import (
@utils.register_interface(PBKDF2HMACBackend)
@utils.register_interface(RSABackend)
@utils.register_interface(DSABackend)
+@utils.register_interface(EllipticCurveBackend)
class MultiBackend(object):
name = "multibackend"
@@ -243,3 +244,55 @@ class MultiBackend(object):
pass
raise UnsupportedAlgorithm("This backend does not support CMAC.",
_Reasons.UNSUPPORTED_CIPHER)
+
+ def elliptic_curve_supported(self, curve):
+ return any(
+ b.elliptic_curve_supported(curve)
+ for b in self._filtered_backends(EllipticCurveBackend)
+ )
+
+ def elliptic_curve_signature_algorithm_supported(
+ self, signature_algorithm, curve
+ ):
+ return any(
+ b.elliptic_curve_signature_algorithm_supported(
+ signature_algorithm, curve
+ )
+ for b in self._filtered_backends(EllipticCurveBackend)
+ )
+
+ def generate_elliptic_curve_private_key(self, curve):
+ for b in self._filtered_backends(EllipticCurveBackend):
+ try:
+ return b.generate_elliptic_curve_private_key(curve)
+ except UnsupportedAlgorithm:
+ continue
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this elliptic curve.",
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
+
+ def elliptic_curve_private_key_from_numbers(self, numbers):
+ for b in self._filtered_backends(EllipticCurveBackend):
+ try:
+ return b.elliptic_curve_private_key_from_numbers(numbers)
+ except UnsupportedAlgorithm:
+ continue
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this elliptic curve.",
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
+
+ def elliptic_curve_public_key_from_numbers(self, numbers):
+ for b in self._filtered_backends(EllipticCurveBackend):
+ try:
+ return b.elliptic_curve_public_key_from_numbers(numbers)
+ except UnsupportedAlgorithm:
+ continue
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this elliptic curve.",
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py
index 481797fe..b256ddcc 100644
--- a/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -21,6 +21,17 @@ from cryptography.hazmat.backends.interfaces import RSABackend
from cryptography.hazmat.primitives import interfaces
+def generate_private_key(public_exponent, key_size, backend):
+ if not isinstance(backend, RSABackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement RSABackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ _verify_rsa_parameters(public_exponent, key_size)
+ return backend.generate_rsa_private_key(public_exponent, key_size)
+
+
def _verify_rsa_parameters(public_exponent, key_size):
if public_exponent < 3:
raise ValueError("public_exponent must be >= 3.")
diff --git a/docs/hazmat/primitives/asymmetric/ec.rst b/docs/hazmat/primitives/asymmetric/ec.rst
index 798fbab1..3773e0ae 100644
--- a/docs/hazmat/primitives/asymmetric/ec.rst
+++ b/docs/hazmat/primitives/asymmetric/ec.rst
@@ -6,7 +6,7 @@ Elliptic Curve Cryptography
.. currentmodule:: cryptography.hazmat.primitives.asymmetric.ec
-,, method:: generate_private_key(curve, backend):
+.. method:: generate_private_key(curve, backend):
.. versionadded:: 0.5
@@ -109,7 +109,7 @@ Elliptic Curve Signature Algorithms
:class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
provider.
- .. code-block:: pycon
+ .. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import hashes
diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst
index 54839119..71b7cd9c 100644
--- a/docs/hazmat/primitives/asymmetric/rsa.rst
+++ b/docs/hazmat/primitives/asymmetric/rsa.rst
@@ -7,13 +7,37 @@ RSA
`RSA`_ is a `public-key`_ algorithm for encrypting and signing messages.
+
+.. function:: generate_private_key(public_exponent, key_size, backend)
+
+ .. versionadded:: 0.5
+
+ Generate an RSA private key using the provided ``backend``.
+
+ :param int public_exponent: The public exponent of the new key.
+ Usually one of the small Fermat primes 3, 5, 17, 257, 65537. If in
+ doubt you should `use 65537`_.
+ :param int key_size: The length of the modulus in bits. For keys
+ generated in 2014 it is strongly recommended to be
+ `at least 2048`_ (See page 41). It must not be less than 512.
+ Some backends may have additional limitations.
+ :param backend: A
+ :class:`~cryptography.hazmat.backends.interfaces.RSABackend`
+ provider.
+ :return: A :class:`~cryptography.hazmat.primitives.interfaces.RSAPrivateKey`
+ provider.
+
+ :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if
+ the provided ``backend`` does not implement
+ :class:`~cryptography.hazmat.backends.interfaces.RSABackend`
+
.. class:: RSAPrivateKey(p, q, private_exponent, dmp1, dmq1, iqmp, public_exponent, modulus)
.. versionadded:: 0.2
An RSA private key is required for decryption and signing of messages.
- You should use :meth:`~generate` to generate new keys.
+ You should use :func:`generate_private_key` to generate new keys.
.. warning::
This method only checks a limited set of properties of its arguments.
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index 93d58483..64dc062c 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -18,12 +18,12 @@ from cryptography.exceptions import (
UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import (
- CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
- PBKDF2HMACBackend, RSABackend
+ CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend,
+ HashBackend, PBKDF2HMACBackend, RSABackend
)
from cryptography.hazmat.backends.multibackend import MultiBackend
from cryptography.hazmat.primitives import cmac, hashes, hmac
-from cryptography.hazmat.primitives.asymmetric import padding
+from cryptography.hazmat.primitives.asymmetric import ec, padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from ...utils import raises_unsupported_algorithm
@@ -154,6 +154,41 @@ class DummyCMACBackend(object):
raise UnsupportedAlgorithm("", _Reasons.UNSUPPORTED_CIPHER)
+@utils.register_interface(EllipticCurveBackend)
+class DummyEllipticCurveBackend(object):
+ def __init__(self, supported_curves):
+ self._curves = supported_curves
+
+ def elliptic_curve_supported(self, curve):
+ return any(
+ isinstance(curve, curve_type)
+ for curve_type in self._curves
+ )
+
+ def elliptic_curve_signature_algorithm_supported(
+ self, signature_algorithm, curve
+ ):
+ return (
+ isinstance(signature_algorithm, ec.ECDSA) and
+ any(
+ isinstance(curve, curve_type)
+ for curve_type in self._curves
+ )
+ )
+
+ def generate_elliptic_curve_private_key(self, curve):
+ if not self.elliptic_curve_supported(curve):
+ raise UnsupportedAlgorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE)
+
+ def elliptic_curve_private_key_from_numbers(self, numbers):
+ if not self.elliptic_curve_supported(numbers.public_numbers.curve):
+ raise UnsupportedAlgorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE)
+
+ def elliptic_curve_public_key_from_numbers(self, numbers):
+ if not self.elliptic_curve_supported(numbers.curve):
+ raise UnsupportedAlgorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE)
+
+
class TestMultiBackend(object):
def test_ciphers(self):
backend = MultiBackend([
@@ -361,3 +396,69 @@ class TestMultiBackend(object):
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
cmac.CMAC(algorithms.TripleDES(fake_key), backend)
+
+ def test_elliptic_curve(self):
+ backend = MultiBackend([
+ DummyEllipticCurveBackend([
+ ec.SECT283K1
+ ])
+ ])
+
+ assert backend.elliptic_curve_supported(ec.SECT283K1()) is True
+
+ assert backend.elliptic_curve_signature_algorithm_supported(
+ ec.ECDSA(hashes.SHA256()),
+ ec.SECT283K1()
+ ) is True
+
+ backend.generate_elliptic_curve_private_key(ec.SECT283K1())
+
+ backend.elliptic_curve_private_key_from_numbers(
+ ec.EllipticCurvePrivateNumbers(
+ 1,
+ ec.EllipticCurvePublicNumbers(
+ 2,
+ 3,
+ ec.SECT283K1()
+ )
+ )
+ )
+
+ backend.elliptic_curve_public_key_from_numbers(
+ ec.EllipticCurvePublicNumbers(
+ 2,
+ 3,
+ ec.SECT283K1()
+ )
+ )
+
+ assert backend.elliptic_curve_supported(ec.SECT163K1()) is False
+
+ assert backend.elliptic_curve_signature_algorithm_supported(
+ ec.ECDSA(hashes.SHA256()),
+ ec.SECT163K1()
+ ) is False
+
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE):
+ backend.generate_elliptic_curve_private_key(ec.SECT163K1())
+
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE):
+ backend.elliptic_curve_private_key_from_numbers(
+ ec.EllipticCurvePrivateNumbers(
+ 1,
+ ec.EllipticCurvePublicNumbers(
+ 2,
+ 3,
+ ec.SECT163K1()
+ )
+ )
+ )
+
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE):
+ backend.elliptic_curve_public_key_from_numbers(
+ ec.EllipticCurvePublicNumbers(
+ 2,
+ 3,
+ ec.SECT163K1()
+ )
+ )
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index 610fa625..8f10fb10 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -97,32 +97,38 @@ class TestRSA(object):
)
)
def test_generate_rsa_keys(self, backend, public_exponent, key_size):
- skey = rsa.RSAPrivateKey.generate(public_exponent, key_size, backend)
+ skey = rsa.generate_private_key(public_exponent, key_size, backend)
_check_rsa_private_key(skey)
assert skey.key_size == key_size
assert skey.public_exponent == public_exponent
+ def test_generate_rsa_key_class_method(self, backend):
+ skey = rsa.RSAPrivateKey.generate(65537, 512, backend)
+ _check_rsa_private_key(skey)
+ assert skey.key_size == 512
+ assert skey.public_exponent == 65537
+
def test_generate_bad_public_exponent(self, backend):
with pytest.raises(ValueError):
- rsa.RSAPrivateKey.generate(public_exponent=1,
- key_size=2048,
- backend=backend)
+ rsa.generate_private_key(public_exponent=1,
+ key_size=2048,
+ backend=backend)
with pytest.raises(ValueError):
- rsa.RSAPrivateKey.generate(public_exponent=4,
- key_size=2048,
- backend=backend)
+ rsa.generate_private_key(public_exponent=4,
+ key_size=2048,
+ backend=backend)
def test_cant_generate_insecure_tiny_key(self, backend):
with pytest.raises(ValueError):
- rsa.RSAPrivateKey.generate(public_exponent=65537,
- key_size=511,
- backend=backend)
+ rsa.generate_private_key(public_exponent=65537,
+ key_size=511,
+ backend=backend)
with pytest.raises(ValueError):
- rsa.RSAPrivateKey.generate(public_exponent=65537,
- key_size=256,
- backend=backend)
+ rsa.generate_private_key(public_exponent=65537,
+ key_size=256,
+ backend=backend)
@pytest.mark.parametrize(
"pkcs1_example",
@@ -380,6 +386,9 @@ def test_rsa_generate_invalid_backend():
pretend_backend = object()
with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
+ rsa.generate_private_key(65537, 2048, pretend_backend)
+
+ with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
rsa.RSAPrivateKey.generate(65537, 2048, pretend_backend)
@@ -966,7 +975,7 @@ class TestRSAVerification(object):
def test_rsa_verifier_invalid_backend(self, backend):
pretend_backend = object()
- private_key = rsa.RSAPrivateKey.generate(65537, 2048, backend)
+ private_key = rsa.generate_private_key(65537, 2048, backend)
public_key = private_key.public_key()
with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):