aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.travis/install.sh6
-rw-r--r--CHANGELOG.rst2
-rw-r--r--cryptography/hazmat/backends/interfaces.py10
-rw-r--r--cryptography/hazmat/backends/multibackend.py20
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py191
-rw-r--r--cryptography/hazmat/bindings/commoncrypto/binding.py6
-rw-r--r--cryptography/hazmat/bindings/openssl/bignum.py13
-rw-r--r--cryptography/hazmat/bindings/openssl/binding.py10
-rw-r--r--cryptography/hazmat/bindings/openssl/dsa.py13
-rw-r--r--cryptography/hazmat/bindings/openssl/ec.py2
-rw-r--r--cryptography/hazmat/bindings/openssl/err.py3
-rw-r--r--cryptography/hazmat/bindings/openssl/evp.py11
-rw-r--r--cryptography/hazmat/bindings/openssl/ssl.py28
-rw-r--r--cryptography/hazmat/bindings/openssl/x509.py54
-rw-r--r--cryptography/hazmat/bindings/utils.py5
-rw-r--r--cryptography/hazmat/primitives/asymmetric/padding.py13
-rw-r--r--cryptography/hazmat/primitives/asymmetric/rsa.py45
-rw-r--r--cryptography/hazmat/primitives/cmac.py75
-rw-r--r--dev-requirements.txt3
-rw-r--r--docs/hazmat/backends/interfaces.rst37
-rw-r--r--docs/hazmat/backends/openssl.rst2
-rw-r--r--docs/hazmat/primitives/asymmetric/padding.rst22
-rw-r--r--docs/hazmat/primitives/asymmetric/rsa.rst89
-rw-r--r--docs/hazmat/primitives/index.rst2
-rw-r--r--docs/hazmat/primitives/interfaces.rst18
-rw-r--r--docs/hazmat/primitives/mac/cmac.rst107
-rw-r--r--docs/hazmat/primitives/mac/hmac.rst (renamed from docs/hazmat/primitives/hmac.rst)0
-rw-r--r--docs/hazmat/primitives/mac/index.rst10
-rw-r--r--docs/hazmat/primitives/padding.rst2
-rw-r--r--docs/hazmat/primitives/symmetric-encryption.rst4
-rw-r--r--docs/installation.rst17
-rw-r--r--docs/spelling_wordlist.txt1
-rw-r--r--pytest.ini2
-rw-r--r--setup.py2
-rw-r--r--tests/conftest.py11
-rw-r--r--tests/hazmat/backends/test_multibackend.py34
-rw-r--r--tests/hazmat/backends/test_openssl.py90
-rw-r--r--tests/hazmat/bindings/test_openssl.py36
-rw-r--r--tests/hazmat/primitives/test_cmac.py217
-rw-r--r--tests/hazmat/primitives/test_dsa.py2
-rw-r--r--tests/hazmat/primitives/test_pbkdf2hmac.py1
-rw-r--r--tests/hazmat/primitives/test_rsa.py193
-rw-r--r--tests/hazmat/primitives/utils.py18
-rw-r--r--tests/test_utils.py572
-rw-r--r--tests/utils.py69
-rw-r--r--tox.ini7
-rw-r--r--vectors/cryptography_vectors/__init__.py4
-rw-r--r--vectors/setup.py2
48 files changed, 1938 insertions, 143 deletions
diff --git a/.travis/install.sh b/.travis/install.sh
index 58d7404d..79790050 100755
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -32,12 +32,12 @@ if [[ "$(uname -s)" == "Darwin" ]]; then
if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi
case "${TOX_ENV}" in
py26)
- curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
+ curl -O https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py
sudo python get-pip.py
sudo pip install virtualenv
;;
py27)
- curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
+ curl -O https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py
sudo python get-pip.py
sudo pip install virtualenv
;;
@@ -62,7 +62,7 @@ if [[ "$(uname -s)" == "Darwin" ]]; then
pip install virtualenv
;;
docs)
- curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
+ curl -O https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py
sudo python get-pip.py
sudo pip install virtualenv
;;
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 9e89e563..2fdf8c9b 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -10,6 +10,8 @@ Changelog
:class:`~cryptography.hazmat.primitives.asymmetric.padding.MGF1` and added it
to :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS`. It will be
removed from ``MGF1`` in two releases per our :doc:`/api-stability` policy.
+* Added :class:`~cryptography.hazmat.primitives.ciphers.algorithms.SEED` support.
+* Added :class:`~cryptography.hazmat.primitives.cmac.CMAC`.
0.3 - 2014-03-27
~~~~~~~~~~~~~~~~
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index 92413d8c..1ddf0785 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -117,6 +117,12 @@ class RSABackend(object):
Return True if the hash algorithm is supported for MGF1 in PSS.
"""
+ @abc.abstractmethod
+ def decrypt_rsa(self, private_key, ciphertext, padding):
+ """
+ Returns decrypted bytes.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class DSABackend(object):
@@ -135,9 +141,9 @@ class DSABackend(object):
@six.add_metaclass(abc.ABCMeta)
-class OpenSSLSerializationBackend(object):
+class TraditionalOpenSSLSerializationBackend(object):
@abc.abstractmethod
- def load_openssl_pem_private_key(self, data, password):
+ def load_traditional_openssl_pem_private_key(self, data, password):
"""
Load a private key from PEM encoded data, using password if the data
is encrypted.
diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py
index 86cded85..981a60bd 100644
--- a/cryptography/hazmat/backends/multibackend.py
+++ b/cryptography/hazmat/backends/multibackend.py
@@ -16,11 +16,12 @@ from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- RSABackend
+ CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
+ PBKDF2HMACBackend, RSABackend
)
+@utils.register_interface(CMACBackend)
@utils.register_interface(CipherBackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
@@ -156,3 +157,18 @@ class MultiBackend(object):
return b.generate_dsa_private_key(parameters)
raise UnsupportedAlgorithm("DSA is not supported by the backend",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def cmac_algorithm_supported(self, algorithm):
+ return any(
+ b.cmac_algorithm_supported(algorithm)
+ for b in self._filtered_backends(CMACBackend)
+ )
+
+ def create_cmac_ctx(self, algorithm):
+ for b in self._filtered_backends(CMACBackend):
+ try:
+ return b.create_cmac_ctx(algorithm)
+ except UnsupportedAlgorithm:
+ pass
+ raise UnsupportedAlgorithm("This backend does not support CMAC",
+ _Reasons.UNSUPPORTED_CIPHER)
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 9ac062c2..2d7e2307 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -25,14 +25,14 @@ from cryptography.exceptions import (
UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- RSABackend
+ CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
+ PBKDF2HMACBackend, RSABackend
)
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.padding import (
- MGF1, PKCS1v15, PSS
+ MGF1, OAEP, PKCS1v15, PSS
)
from cryptography.hazmat.primitives.ciphers.algorithms import (
AES, ARC4, Blowfish, CAST5, Camellia, IDEA, SEED, TripleDES
@@ -47,6 +47,7 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError",
@utils.register_interface(CipherBackend)
+@utils.register_interface(CMACBackend)
@utils.register_interface(DSABackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
@@ -293,7 +294,7 @@ class Backend(object):
self._lib.OPENSSL_free(hex_cdata)
return int(hex_str, 16)
- def _int_to_bn(self, num):
+ def _int_to_bn(self, num, bn=None):
"""
Converts a python integer to a BIGNUM. The returned BIGNUM will not
be garbage collected (to support adding them to structs that take
@@ -301,11 +302,14 @@ class Backend(object):
be discarded after use.
"""
+ if bn is None:
+ bn = self._ffi.NULL
+
if six.PY3:
# Python 3 has constant time to_bytes, so use that.
binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big")
- bn_ptr = self._lib.BN_bin2bn(binary, len(binary), self._ffi.NULL)
+ bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn)
assert bn_ptr != self._ffi.NULL
return bn_ptr
@@ -314,6 +318,7 @@ class Backend(object):
hex_num = hex(num).rstrip("L").lstrip("0x").encode("ascii") or b"0"
bn_ptr = self._ffi.new("BIGNUM **")
+ bn_ptr[0] = bn
res = self._lib.BN_hex2bn(bn_ptr, hex_num)
assert res != 0
assert bn_ptr[0] != self._ffi.NULL
@@ -346,7 +351,7 @@ class Backend(object):
def _new_evp_pkey(self):
evp_pkey = self._lib.EVP_PKEY_new()
assert evp_pkey != self._ffi.NULL
- return self._ffi.gc(evp_pkey, backend._lib.EVP_PKEY_free)
+ return self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
def _rsa_private_key_to_evp_pkey(self, private_key):
evp_pkey = self._new_evp_pkey()
@@ -469,6 +474,120 @@ class Backend(object):
y=self._bn_to_int(ctx.pub_key)
)
+ def decrypt_rsa(self, private_key, ciphertext, padding):
+ if isinstance(padding, PKCS1v15):
+ padding_enum = self._lib.RSA_PKCS1_PADDING
+ elif isinstance(padding, OAEP):
+ padding_enum = self._lib.RSA_PKCS1_OAEP_PADDING
+ if not isinstance(padding._mgf, MGF1):
+ raise UnsupportedAlgorithm(
+ "Only MGF1 is supported by this backend",
+ _Reasons.UNSUPPORTED_MGF
+ )
+
+ if not isinstance(padding._mgf._algorithm, hashes.SHA1):
+ raise UnsupportedAlgorithm(
+ "This backend supports only SHA1 inside MGF1 when "
+ "using OAEP",
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ if padding._label is not None and padding._label != b"":
+ raise ValueError("This backend does not support OAEP labels")
+
+ if not isinstance(padding._algorithm, hashes.SHA1):
+ raise UnsupportedAlgorithm(
+ "This backend only supports SHA1 when using OAEP",
+ _Reasons.UNSUPPORTED_HASH
+ )
+ else:
+ raise UnsupportedAlgorithm(
+ "{0} is not supported by this backend".format(
+ padding.name
+ ),
+ _Reasons.UNSUPPORTED_PADDING
+ )
+
+ key_size_bytes = int(math.ceil(private_key.key_size / 8.0))
+ if key_size_bytes < len(ciphertext):
+ raise ValueError("Ciphertext too large for key size")
+
+ if self._lib.Cryptography_HAS_PKEY_CTX:
+ return self._decrypt_rsa_pkey_ctx(private_key, ciphertext,
+ padding_enum)
+ else:
+ return self._decrypt_rsa_098(private_key, ciphertext, padding_enum)
+
+ def _decrypt_rsa_pkey_ctx(self, private_key, ciphertext, padding_enum):
+ evp_pkey = self._rsa_private_key_to_evp_pkey(private_key)
+ pkey_ctx = self._lib.EVP_PKEY_CTX_new(
+ evp_pkey, self._ffi.NULL
+ )
+ assert pkey_ctx != self._ffi.NULL
+ pkey_ctx = self._ffi.gc(pkey_ctx, self._lib.EVP_PKEY_CTX_free)
+ res = self._lib.EVP_PKEY_decrypt_init(pkey_ctx)
+ assert res == 1
+ res = self._lib.EVP_PKEY_CTX_set_rsa_padding(
+ pkey_ctx, padding_enum)
+ assert res > 0
+ buf_size = self._lib.EVP_PKEY_size(evp_pkey)
+ assert buf_size > 0
+ outlen = self._ffi.new("size_t *", buf_size)
+ buf = self._ffi.new("char[]", buf_size)
+ res = self._lib.Cryptography_EVP_PKEY_decrypt(
+ pkey_ctx,
+ buf,
+ outlen,
+ ciphertext,
+ len(ciphertext)
+ )
+ if res <= 0:
+ errors = self._consume_errors()
+ assert errors
+ assert errors[0].lib == self._lib.ERR_LIB_RSA
+ assert (
+ errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or
+ errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_02
+ )
+ raise ValueError("Decryption failed")
+
+ return self._ffi.buffer(buf)[:outlen[0]]
+
+ def _decrypt_rsa_098(self, private_key, ciphertext, padding_enum):
+ rsa_cdata = self._rsa_cdata_from_private_key(private_key)
+ rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
+ key_size = self._lib.RSA_size(rsa_cdata)
+ assert key_size > 0
+ buf = self._ffi.new("unsigned char[]", key_size)
+ res = self._lib.RSA_private_decrypt(
+ len(ciphertext),
+ ciphertext,
+ buf,
+ rsa_cdata,
+ padding_enum
+ )
+ if res < 0:
+ errors = self._consume_errors()
+ assert errors
+ assert errors[0].lib == self._lib.ERR_LIB_RSA
+ assert (
+ errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or
+ errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_02
+ )
+ raise ValueError("Decryption failed")
+
+ return self._ffi.buffer(buf)[:res]
+
+ def cmac_algorithm_supported(self, algorithm):
+ return (
+ self._lib.Cryptography_HAS_CMAC == 1
+ and self.cipher_supported(algorithm, CBC(
+ b"\x00" * algorithm.block_size))
+ )
+
+ def create_cmac_ctx(self, algorithm):
+ return _CMACContext(self, algorithm)
+
class GetCipherByName(object):
def __init__(self, fmt):
@@ -1155,4 +1274,64 @@ class _RSAVerificationContext(object):
raise InvalidSignature
+@utils.register_interface(interfaces.CMACContext)
+class _CMACContext(object):
+ def __init__(self, backend, algorithm, ctx=None):
+ if not backend.cmac_algorithm_supported(algorithm):
+ raise UnsupportedAlgorithm("This backend does not support CMAC",
+ _Reasons.UNSUPPORTED_CIPHER)
+
+ self._backend = backend
+ self._key = algorithm.key
+ self._algorithm = algorithm
+ self._output_length = algorithm.block_size // 8
+
+ if ctx is None:
+ registry = self._backend._cipher_registry
+ adapter = registry[type(algorithm), CBC]
+
+ evp_cipher = adapter(self._backend, algorithm, CBC)
+
+ ctx = self._backend._lib.CMAC_CTX_new()
+
+ assert ctx != self._backend._ffi.NULL
+ ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free)
+
+ self._backend._lib.CMAC_Init(
+ ctx, self._key, len(self._key),
+ evp_cipher, self._backend._ffi.NULL
+ )
+
+ self._ctx = ctx
+
+ def update(self, data):
+ res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
+ assert res == 1
+
+ def finalize(self):
+ buf = self._backend._ffi.new("unsigned char[]", self._output_length)
+ length = self._backend._ffi.new("size_t *", self._output_length)
+ res = self._backend._lib.CMAC_Final(
+ self._ctx, buf, length
+ )
+ assert res == 1
+
+ self._ctx = None
+
+ return self._backend._ffi.buffer(buf)[:]
+
+ def copy(self):
+ copied_ctx = self._backend._lib.CMAC_CTX_new()
+ copied_ctx = self._backend._ffi.gc(
+ copied_ctx, self._backend._lib.CMAC_CTX_free
+ )
+ res = self._backend._lib.CMAC_CTX_copy(
+ copied_ctx, self._ctx
+ )
+ assert res == 1
+ return _CMACContext(
+ self._backend, self._algorithm, ctx=copied_ctx
+ )
+
+
backend = Backend()
diff --git a/cryptography/hazmat/bindings/commoncrypto/binding.py b/cryptography/hazmat/bindings/commoncrypto/binding.py
index 3673ea36..144bb099 100644
--- a/cryptography/hazmat/bindings/commoncrypto/binding.py
+++ b/cryptography/hazmat/bindings/commoncrypto/binding.py
@@ -42,8 +42,10 @@ class Binding(object):
if cls.ffi is not None and cls.lib is not None:
return
- cls.ffi, cls.lib = build_ffi(cls._module_prefix, cls._modules,
- "", "", [])
+ cls.ffi, cls.lib = build_ffi(
+ module_prefix=cls._module_prefix,
+ modules=cls._modules,
+ )
@classmethod
def is_available(cls):
diff --git a/cryptography/hazmat/bindings/openssl/bignum.py b/cryptography/hazmat/bindings/openssl/bignum.py
index 94c2914e..1d944ee9 100644
--- a/cryptography/hazmat/bindings/openssl/bignum.py
+++ b/cryptography/hazmat/bindings/openssl/bignum.py
@@ -87,12 +87,25 @@ int BN_mod_exp(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
BN_CTX *);
int BN_gcd(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
BIGNUM *BN_mod_inverse(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int BN_set_bit(BIGNUM *, int);
+int BN_clear_bit(BIGNUM *, int);
+
+int BN_is_bit_set(const BIGNUM *, int);
+
+int BN_mask_bits(BIGNUM *, int);
"""
MACROS = """
int BN_zero(BIGNUM *);
int BN_one(BIGNUM *);
int BN_mod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int BN_lshift(BIGNUM *, const BIGNUM *, int);
+int BN_lshift1(BIGNUM *, BIGNUM *);
+
+int BN_rshift(BIGNUM *, BIGNUM *, int);
+int BN_rshift1(BIGNUM *, BIGNUM *);
"""
CUSTOMIZATIONS = """
diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py
index cc40a108..f0ff3275 100644
--- a/cryptography/hazmat/bindings/openssl/binding.py
+++ b/cryptography/hazmat/bindings/openssl/binding.py
@@ -97,9 +97,13 @@ class Binding(object):
else: # pragma: no cover
libraries = ["libeay32", "ssleay32", "advapi32"]
- cls.ffi, cls.lib = build_ffi(cls._module_prefix, cls._modules,
- _OSX_PRE_INCLUDE, _OSX_POST_INCLUDE,
- libraries)
+ cls.ffi, cls.lib = build_ffi(
+ module_prefix=cls._module_prefix,
+ modules=cls._modules,
+ pre_include=_OSX_PRE_INCLUDE,
+ post_include=_OSX_POST_INCLUDE,
+ libraries=libraries,
+ )
res = cls.lib.Cryptography_add_osrandom_engine()
assert res != 0
diff --git a/cryptography/hazmat/bindings/openssl/dsa.py b/cryptography/hazmat/bindings/openssl/dsa.py
index 40d3b8ee..7db03326 100644
--- a/cryptography/hazmat/bindings/openssl/dsa.py
+++ b/cryptography/hazmat/bindings/openssl/dsa.py
@@ -31,6 +31,10 @@ typedef struct dsa_st {
BIGNUM *pub_key;
...;
} DSA;
+typedef struct {
+ BIGNUM *r;
+ BIGNUM *s;
+} DSA_SIG;
"""
FUNCTIONS = """
@@ -39,6 +43,15 @@ DSA *DSA_generate_parameters(int, unsigned char *, int, int *, unsigned long *,
int DSA_generate_key(DSA *);
DSA *DSA_new(void);
void DSA_free(DSA *);
+DSA_SIG *DSA_SIG_new(void);
+void DSA_SIG_free(DSA_SIG *);
+int i2d_DSA_SIG(const DSA_SIG *, unsigned char **);
+DSA_SIG *d2i_DSA_SIG(DSA_SIG **, const unsigned char **, long);
+int DSA_size(const DSA *);
+int DSA_sign(int, const unsigned char *, int, unsigned char *, unsigned int *,
+ DSA *);
+int DSA_verify(int, const unsigned char *, int, const unsigned char *, int,
+ DSA *);
"""
MACROS = """
diff --git a/cryptography/hazmat/bindings/openssl/ec.py b/cryptography/hazmat/bindings/openssl/ec.py
index 8ae2ae9a..45c17c2e 100644
--- a/cryptography/hazmat/bindings/openssl/ec.py
+++ b/cryptography/hazmat/bindings/openssl/ec.py
@@ -77,6 +77,7 @@ EC_KEY *EC_KEY_copy(EC_KEY *, const EC_KEY *);
EC_KEY *EC_KEY_dup(const EC_KEY *);
int EC_KEY_up_ref(EC_KEY *);
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *);
+int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *, BN_CTX *);
int EC_KEY_set_group(EC_KEY *, const EC_GROUP *);
const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *);
int EC_KEY_set_private_key(EC_KEY *, const BIGNUM *);
@@ -214,6 +215,7 @@ EC_KEY *(*EC_KEY_copy)(EC_KEY *, const EC_KEY *) = NULL;
EC_KEY *(*EC_KEY_dup)(const EC_KEY *) = NULL;
int (*EC_KEY_up_ref)(EC_KEY *) = NULL;
const EC_GROUP *(*EC_KEY_get0_group)(const EC_KEY *) = NULL;
+int (*EC_GROUP_get_order)(const EC_GROUP *, BIGNUM *, BN_CTX *) = NULL;
int (*EC_KEY_set_group)(EC_KEY *, const EC_GROUP *) = NULL;
const BIGNUM *(*EC_KEY_get0_private_key)(const EC_KEY *) = NULL;
int (*EC_KEY_set_private_key)(EC_KEY *, const BIGNUM *) = NULL;
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index f51393aa..f6456d66 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -138,6 +138,7 @@ static const int EVP_F_RC5_CTRL;
static const int EVP_R_AES_KEY_SETUP_FAILED;
static const int EVP_R_ASN1_LIB;
static const int EVP_R_BAD_BLOCK_LENGTH;
+static const int EVP_R_BAD_DECRYPT;
static const int EVP_R_BAD_KEY_LENGTH;
static const int EVP_R_BN_DECODE_ERROR;
static const int EVP_R_BN_PUBKEY_ERROR;
@@ -216,6 +217,8 @@ static const int PEM_R_UNSUPPORTED_ENCRYPTION;
static const int RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE;
static const int RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY;
+static const int RSA_R_BLOCK_TYPE_IS_NOT_01;
+static const int RSA_R_BLOCK_TYPE_IS_NOT_02;
"""
FUNCTIONS = """
diff --git a/cryptography/hazmat/bindings/openssl/evp.py b/cryptography/hazmat/bindings/openssl/evp.py
index 963537c8..b3d958e6 100644
--- a/cryptography/hazmat/bindings/openssl/evp.py
+++ b/cryptography/hazmat/bindings/openssl/evp.py
@@ -87,6 +87,8 @@ int EVP_PKEY_type(int);
int EVP_PKEY_bits(EVP_PKEY *);
int EVP_PKEY_size(EVP_PKEY *);
RSA *EVP_PKEY_get1_RSA(EVP_PKEY *);
+DSA *EVP_PKEY_get1_DSA(EVP_PKEY *);
+DH *EVP_PKEY_get1_DH(EVP_PKEY *);
int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *);
int EVP_SignUpdate(EVP_MD_CTX *, const void *, size_t);
@@ -104,6 +106,7 @@ int PKCS5_PBKDF2_HMAC_SHA1(const char *, int, const unsigned char *, int, int,
int EVP_PKEY_set1_RSA(EVP_PKEY *, struct rsa_st *);
int EVP_PKEY_set1_DSA(EVP_PKEY *, struct dsa_st *);
+int EVP_PKEY_set1_DH(EVP_PKEY *, DH *);
int EVP_PKEY_get_attr_count(const EVP_PKEY *);
int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *, int, int);
@@ -123,7 +126,11 @@ MACROS = """
void OpenSSL_add_all_algorithms(void);
int EVP_PKEY_assign_RSA(EVP_PKEY *, RSA *);
int EVP_PKEY_assign_DSA(EVP_PKEY *, DSA *);
+
int EVP_PKEY_assign_EC_KEY(EVP_PKEY *, EC_KEY *);
+EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *);
+int EVP_PKEY_set1_EC_KEY(EVP_PKEY *, EC_KEY *);
+
int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *);
int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *);
@@ -215,6 +222,8 @@ int (*Cryptography_EVP_PKEY_decrypt)(EVP_PKEY_CTX *, unsigned char *, size_t *,
#endif
#ifdef OPENSSL_NO_EC
int (*EVP_PKEY_assign_EC_KEY)(EVP_PKEY *, EC_KEY *) = NULL;
+EC_KEY *(*EVP_PKEY_get1_EC_KEY)(EVP_PKEY *) = NULL;
+int (*EVP_PKEY_set1_EC_KEY)(EVP_PKEY *, EC_KEY *) = NULL;
#endif
"""
@@ -245,5 +254,7 @@ CONDITIONAL_NAMES = {
],
"Cryptography_HAS_EC": [
"EVP_PKEY_assign_EC_KEY",
+ "EVP_PKEY_get1_EC_KEY",
+ "EVP_PKEY_set1_EC_KEY",
]
}
diff --git a/cryptography/hazmat/bindings/openssl/ssl.py b/cryptography/hazmat/bindings/openssl/ssl.py
index 094310f3..7ed42f9f 100644
--- a/cryptography/hazmat/bindings/openssl/ssl.py
+++ b/cryptography/hazmat/bindings/openssl/ssl.py
@@ -237,26 +237,28 @@ size_t SSL_get_peer_finished(const SSL *, void *, size_t);
"""
MACROS = """
-long SSL_set_mode(SSL *, long);
-long SSL_get_mode(SSL *);
+unsigned long SSL_set_mode(SSL *, unsigned long);
+unsigned long SSL_get_mode(SSL *);
-long SSL_set_options(SSL *, long);
-long SSL_get_options(SSL *);
+unsigned long SSL_set_options(SSL *, unsigned long);
+unsigned long SSL_get_options(SSL *);
int SSL_want_read(const SSL *);
int SSL_want_write(const SSL *);
long SSL_total_renegotiations(SSL *);
-long SSL_CTX_set_options(SSL_CTX *, long);
-long SSL_CTX_get_options(SSL_CTX *);
-long SSL_CTX_set_mode(SSL_CTX *, long);
-long SSL_CTX_get_mode(SSL_CTX *);
-long SSL_CTX_set_session_cache_mode(SSL_CTX *, long);
-long SSL_CTX_get_session_cache_mode(SSL_CTX *);
-long SSL_CTX_set_tmp_dh(SSL_CTX *, DH *);
-long SSL_CTX_set_tmp_ecdh(SSL_CTX *, EC_KEY *);
-long SSL_CTX_add_extra_chain_cert(SSL_CTX *, X509 *);
+/* Defined as unsigned long because SSL_OP_ALL is greater than signed 32-bit
+ and Windows defines long as 32-bit. */
+unsigned long SSL_CTX_set_options(SSL_CTX *, unsigned long);
+unsigned long SSL_CTX_get_options(SSL_CTX *);
+unsigned long SSL_CTX_set_mode(SSL_CTX *, unsigned long);
+unsigned long SSL_CTX_get_mode(SSL_CTX *);
+unsigned long SSL_CTX_set_session_cache_mode(SSL_CTX *, unsigned long);
+unsigned long SSL_CTX_get_session_cache_mode(SSL_CTX *);
+unsigned long SSL_CTX_set_tmp_dh(SSL_CTX *, DH *);
+unsigned long SSL_CTX_set_tmp_ecdh(SSL_CTX *, EC_KEY *);
+unsigned long SSL_CTX_add_extra_chain_cert(SSL_CTX *, X509 *);
/*- These aren't macros these functions are all const X on openssl > 1.0.x -*/
diff --git a/cryptography/hazmat/bindings/openssl/x509.py b/cryptography/hazmat/bindings/openssl/x509.py
index e800d272..36a15e4a 100644
--- a/cryptography/hazmat/bindings/openssl/x509.py
+++ b/cryptography/hazmat/bindings/openssl/x509.py
@@ -160,6 +160,8 @@ X509_REQ *d2i_X509_REQ_bio(BIO *, X509_REQ **);
int i2d_PrivateKey_bio(BIO *, EVP_PKEY *);
EVP_PKEY *d2i_PrivateKey_bio(BIO *, EVP_PKEY **);
+int i2d_PUBKEY_bio(BIO *, EVP_PKEY *);
+EVP_PKEY *d2i_PUBKEY_bio(BIO *, EVP_PKEY **);
ASN1_INTEGER *X509_get_serialNumber(X509 *);
int X509_set_serialNumber(X509 *, ASN1_INTEGER *);
@@ -178,6 +180,27 @@ const char *X509_get_default_cert_file(void);
const char *X509_get_default_cert_dir_env(void);
const char *X509_get_default_cert_file_env(void);
const char *X509_get_default_private_dir(void);
+
+int i2d_RSA_PUBKEY(RSA *, unsigned char **);
+RSA *d2i_RSA_PUBKEY(RSA **, const unsigned char **, long);
+RSA *d2i_RSAPublicKey(RSA **, const unsigned char **, long);
+RSA *d2i_RSAPrivateKey(RSA **, const unsigned char **, long);
+int i2d_DSA_PUBKEY(DSA *, unsigned char **);
+DSA *d2i_DSA_PUBKEY(DSA **, const unsigned char **, long);
+DSA *d2i_DSAPublicKey(DSA **, const unsigned char **, long);
+DSA *d2i_DSAPrivateKey(DSA **, const unsigned char **, long);
+
+
+RSA *d2i_RSAPrivateKey_bio(BIO *, RSA **);
+int i2d_RSAPrivateKey_bio(BIO *, RSA *);
+RSA *d2i_RSAPublicKey_bio(BIO *, RSA **);
+int i2d_RSAPublicKey_bio(BIO *, RSA *);
+RSA *d2i_RSA_PUBKEY_bio(BIO *, RSA **);
+int i2d_RSA_PUBKEY_bio(BIO *, RSA *);
+DSA *d2i_DSA_PUBKEY_bio(BIO *, DSA **);
+int i2d_DSA_PUBKEY_bio(BIO *, DSA *);
+DSA *d2i_DSAPrivateKey_bio(BIO *, DSA **);
+int i2d_DSAPrivateKey_bio(BIO *, DSA *);
"""
MACROS = """
@@ -205,6 +228,11 @@ void sk_X509_EXTENSION_free(X509_EXTENSIONS *);
int sk_X509_REVOKED_num(Cryptography_STACK_OF_X509_REVOKED *);
X509_REVOKED *sk_X509_REVOKED_value(Cryptography_STACK_OF_X509_REVOKED *, int);
+int i2d_RSAPublicKey(RSA *, unsigned char **);
+int i2d_RSAPrivateKey(RSA *, unsigned char **);
+int i2d_DSAPublicKey(DSA *, unsigned char **);
+int i2d_DSAPrivateKey(DSA *, unsigned char **);
+
/* These aren't macros these arguments are all const X on openssl > 1.0.x */
int X509_CRL_set_lastUpdate(X509_CRL *, ASN1_TIME *);
int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *);
@@ -213,6 +241,13 @@ int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *);
RHEL/CentOS 5 we should move these back to FUNCTIONS. */
int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *);
X509_EXTENSIONS *X509_REQ_get_extensions(X509_REQ *);
+
+int i2d_EC_PUBKEY(EC_KEY *, unsigned char **);
+EC_KEY *d2i_EC_PUBKEY(EC_KEY **, const unsigned char **, long);
+EC_KEY *d2i_EC_PUBKEY_bio(BIO *, EC_KEY **);
+int i2d_EC_PUBKEY_bio(BIO *, EC_KEY *);
+EC_KEY *d2i_ECPrivateKey_bio(BIO *, EC_KEY **);
+int i2d_ECPrivateKey_bio(BIO *, EC_KEY *);
"""
CUSTOMIZATIONS = """
@@ -220,6 +255,23 @@ CUSTOMIZATIONS = """
#if OPENSSL_VERSION_NUMBER <= 0x0090805fL
typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
#endif
+#ifdef OPENSSL_NO_EC
+int (*i2d_EC_PUBKEY)(EC_KEY *, unsigned char **) = NULL;
+EC_KEY *(*d2i_EC_PUBKEY)(EC_KEY **, const unsigned char **, long) = NULL;
+EC_KEY *(*d2i_EC_PUBKEY_bio)(BIO *, EC_KEY **) = NULL;
+int (*i2d_EC_PUBKEY_bio)(BIO *, EC_KEY *) = NULL;
+EC_KEY *(*d2i_ECPrivateKey_bio)(BIO *, EC_KEY **) = NULL;
+int (*i2d_ECPrivateKey_bio)(BIO *, EC_KEY *) = NULL;
+#endif
"""
-CONDITIONAL_NAMES = {}
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_EC": [
+ "i2d_EC_PUBKEY",
+ "d2i_EC_PUBKEY",
+ "d2i_EC_PUBKEY_bio",
+ "i2d_EC_PUBKEY_bio",
+ "d2i_ECPrivateKey_bio",
+ "i2d_ECPrivateKey_bio",
+ ]
+}
diff --git a/cryptography/hazmat/bindings/utils.py b/cryptography/hazmat/bindings/utils.py
index 318b82bb..1c48116e 100644
--- a/cryptography/hazmat/bindings/utils.py
+++ b/cryptography/hazmat/bindings/utils.py
@@ -20,7 +20,8 @@ import sys
import cffi
-def build_ffi(module_prefix, modules, pre_include, post_include, libraries):
+def build_ffi(module_prefix, modules, pre_include="", post_include="",
+ libraries=[], extra_compile_args=[], extra_link_args=[]):
"""
Modules listed in ``modules`` should have the following attributes:
@@ -75,6 +76,8 @@ def build_ffi(module_prefix, modules, pre_include, post_include, libraries):
modulename=_create_modulename(cdef_sources, source, sys.version),
libraries=libraries,
ext_package="cryptography",
+ extra_compile_args=extra_compile_args,
+ extra_link_args=extra_link_args,
)
for name in modules:
diff --git a/cryptography/hazmat/primitives/asymmetric/padding.py b/cryptography/hazmat/primitives/asymmetric/padding.py
index 72806a61..dcc6fe06 100644
--- a/cryptography/hazmat/primitives/asymmetric/padding.py
+++ b/cryptography/hazmat/primitives/asymmetric/padding.py
@@ -54,6 +54,19 @@ class PSS(object):
self._salt_length = salt_length
+@utils.register_interface(interfaces.AsymmetricPadding)
+class OAEP(object):
+ name = "EME-OAEP"
+
+ def __init__(self, mgf, algorithm, label):
+ if not isinstance(algorithm, interfaces.HashAlgorithm):
+ raise TypeError("Expected instance of interfaces.HashAlgorithm.")
+
+ self._mgf = mgf
+ self._algorithm = algorithm
+ self._label = label
+
+
class MGF1(object):
MAX_LENGTH = object()
diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py
index 94cc4645..cffd4e98 100644
--- a/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -73,6 +73,42 @@ class RSAPublicKey(object):
return self.modulus
+def _modinv(e, m):
+ """
+ Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
+ """
+ x1, y1, x2, y2 = 1, 0, 0, 1
+ a, b = e, m
+ while b > 0:
+ q, r = divmod(a, b)
+ xn, yn = x1 - q * x2, y1 - q * y2
+ a, b, x1, y1, x2, y2 = b, r, x2, y2, xn, yn
+ return x1 % m
+
+
+def rsa_crt_iqmp(p, q):
+ """
+ Compute the CRT (q ** -1) % p value from RSA primes p and q.
+ """
+ return _modinv(q, p)
+
+
+def rsa_crt_dmp1(private_exponent, p):
+ """
+ Compute the CRT private_exponent % (p - 1) value from the RSA
+ private_exponent and p.
+ """
+ return private_exponent % (p - 1)
+
+
+def rsa_crt_dmq1(private_exponent, q):
+ """
+ Compute the CRT private_exponent % (q - 1) value from the RSA
+ private_exponent and q.
+ """
+ return private_exponent % (q - 1)
+
+
@utils.register_interface(interfaces.RSAPrivateKey)
class RSAPrivateKey(object):
def __init__(self, p, q, private_exponent, dmp1, dmq1, iqmp,
@@ -153,6 +189,15 @@ class RSAPrivateKey(object):
return backend.create_rsa_signature_ctx(self, padding, algorithm)
+ def decrypt(self, ciphertext, padding, backend):
+ if not isinstance(backend, RSABackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement RSABackend",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ return backend.decrypt_rsa(self, ciphertext, padding)
+
@property
def key_size(self):
return utils.bit_length(self.modulus)
diff --git a/cryptography/hazmat/primitives/cmac.py b/cryptography/hazmat/primitives/cmac.py
new file mode 100644
index 00000000..7e7f65ab
--- /dev/null
+++ b/cryptography/hazmat/primitives/cmac.py
@@ -0,0 +1,75 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import, division, print_function
+
+import six
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import CMACBackend
+from cryptography.hazmat.primitives import constant_time, interfaces
+
+
+@utils.register_interface(interfaces.CMACContext)
+class CMAC(object):
+ def __init__(self, algorithm, backend, ctx=None):
+ if not isinstance(backend, CMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement CMACBackend",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ if not isinstance(algorithm, interfaces.BlockCipherAlgorithm):
+ raise TypeError(
+ "Expected instance of interfaces.BlockCipherAlgorithm"
+ )
+ self._algorithm = algorithm
+
+ self._backend = backend
+ if ctx is None:
+ self._ctx = self._backend.create_cmac_ctx(self._algorithm)
+ else:
+ self._ctx = ctx
+
+ def update(self, data):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
+ if isinstance(data, six.text_type):
+ raise TypeError("Unicode-objects must be encoded before hashing")
+ self._ctx.update(data)
+
+ def finalize(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
+ digest = self._ctx.finalize()
+ self._ctx = None
+ return digest
+
+ def verify(self, signature):
+ if isinstance(signature, six.text_type):
+ raise TypeError("Unicode-objects must be encoded before verifying")
+ digest = self.finalize()
+ if not constant_time.bytes_eq(digest, signature):
+ raise InvalidSignature("Signature did not match digest.")
+
+ def copy(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
+ return CMAC(
+ self._algorithm,
+ backend=self._backend,
+ ctx=self._ctx.copy()
+ )
diff --git a/dev-requirements.txt b/dev-requirements.txt
index 9dabba1b..092b9914 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -1,5 +1,6 @@
coverage
flake8
+flake8-import-order
invoke
iso8601
pep8-naming
@@ -7,8 +8,8 @@ pretend
pytest
requests
sphinx
-sphinxcontrib-spelling
sphinx_rtd_theme
+sphinxcontrib-spelling
tox
twine
-e .
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index 394d060b..11ff9305 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -9,7 +9,7 @@ Backend interfaces
Backend implementations may provide a number of interfaces to support operations
such as :doc:`/hazmat/primitives/symmetric-encryption`,
:doc:`/hazmat/primitives/cryptographic-hashes`, and
-:doc:`/hazmat/primitives/hmac`.
+:doc:`/hazmat/primitives/mac/hmac`.
A specific ``backend`` may provide one or more of these interfaces.
@@ -263,8 +263,20 @@ A specific ``backend`` may provide one or more of these interfaces.
:returns: ``True`` if the specified ``algorithm`` is supported by this
backend, otherwise ``False``.
+ .. method:: decrypt_rsa(private_key, ciphertext, padding)
-.. class:: OpenSSLSerializationBackend
+ :param private_key: An instance of an
+ :class:`~cryptography.hazmat.primitives.interfaces.RSAPrivateKey`
+ provider.
+
+ :param bytes ciphertext: The ciphertext to decrypt.
+
+ :param padding: An instance of an
+ :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricPadding`
+ provider.
+
+
+.. class:: TraditionalOpenSSLSerializationBackend
.. versionadded:: 0.3
@@ -278,8 +290,8 @@ A specific ``backend`` may provide one or more of these interfaces.
:param bytes password: The password to use if this data is encrypted.
Should be None if the data is not encrypted.
- :return: A new instance of
- :class:`~cryptography.hazmat.primitives.serialization.OpenSSLPrivateKey`
+ :return: A new instance of the appropriate private key or public key
+ that the serialized data contains.
:raises ValueError: If the data could not be deserialized correctly.
@@ -295,12 +307,12 @@ A specific ``backend`` may provide one or more of these interfaces.
.. method:: generate_dsa_parameters(key_size)
- :param int key_size: The length of the modulus in bits. It should be
- either "1024, 2048 or 3072". For keys generated in 2014 this should
+ :param int key_size: The length of the modulus in bits. It should be
+ either 1024, 2048 or 3072. For keys generated in 2014 this should
be at least 2048.
- Note that some applications (such as SSH) have not yet gained support
- for larger key sizes specified in FIPS 186-3 and are still restricted
- to only the 1024-bit keys specified in FIPS 186-2.
+ Note that some applications (such as SSH) have not yet gained
+ support for larger key sizes specified in FIPS 186-3 and are still
+ restricted to only the 1024-bit keys specified in FIPS 186-2.
:return: A new instance of a
:class:`~cryptography.hazmat.primitives.interfaces.DSAParameters`
@@ -316,9 +328,10 @@ A specific ``backend`` may provide one or more of these interfaces.
:class:`~cryptography.hazmat.primitives.interfaces.DSAPrivateKey`
provider.
- :raises ValueError: This is raised if the key size is not (1024 or 2048 or 3072)
- or if the OpenSSL version is older than 1.0.0 and the key size is larger than 1024
- because older OpenSSL versions don't support a key size larger than 1024.
+ :raises ValueError: This is raised if the key size is not one of 1024,
+ 2048, or 3072. It is also raised when OpenSSL is older than version
+ 1.0.0 and the key size is larger than 1024; older OpenSSL versions
+ do not support keys larger than 1024 bits.
.. class:: CMACBackend
diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst
index fdfadf0b..43e5d8f3 100644
--- a/docs/hazmat/backends/openssl.rst
+++ b/docs/hazmat/backends/openssl.rst
@@ -73,6 +73,6 @@ from the same pool as ``/dev/random``.
.. _`OpenSSL`: https://www.openssl.org/
-.. _`initializing the RNG`: http://en.wikipedia.org/wiki/OpenSSL#Vulnerability_in_the_Debian_implementation
+.. _`initializing the RNG`: https://en.wikipedia.org/wiki/OpenSSL#Predictable_keys_.28Debian-specific.29
.. _`Yarrow`: http://en.wikipedia.org/wiki/Yarrow_algorithm
.. _`Microsoft documentation`: http://msdn.microsoft.com/en-us/library/windows/desktop/aa379942(v=vs.85).aspx
diff --git a/docs/hazmat/primitives/asymmetric/padding.rst b/docs/hazmat/primitives/asymmetric/padding.rst
index 89af7eaa..40084799 100644
--- a/docs/hazmat/primitives/asymmetric/padding.rst
+++ b/docs/hazmat/primitives/asymmetric/padding.rst
@@ -19,7 +19,8 @@ Padding
PSS (Probabilistic Signature Scheme) is a signature scheme defined in
:rfc:`3447`. It is more complex than PKCS1 but possesses a `security proof`_.
- This is the `recommended padding algorithm`_ for RSA signatures.
+ This is the `recommended padding algorithm`_ for RSA signatures. It cannot
+ be used with RSA encryption.
:param mgf: A mask generation function object. At this time the only
supported MGF is :class:`MGF1`.
@@ -32,12 +33,28 @@ Padding
Pass this attribute to ``salt_length`` to get the maximum salt length
available.
+.. class:: OAEP(mgf, label)
+
+ .. versionadded:: 0.4
+
+ OAEP (Optimal Asymmetric Encryption Padding) is a padding scheme defined in
+ :rfc:`3447`. It provides probabilistic encryption and is `proven secure`_
+ against several attack types. This is the `recommended padding algorithm`_
+ for RSA encryption. It cannot be used with RSA signing.
+
+ :param mgf: A mask generation function object. At this time the only
+ supported MGF is :class:`MGF1`.
+
+ :param bytes label: A label to apply. This is a rarely used field and
+ should typically be set to ``None`` or ``b""``, which are equivalent.
+
.. class:: PKCS1v15()
.. versionadded:: 0.3
PKCS1 v1.5 (also known as simply PKCS1) is a simple padding scheme
- developed for use with RSA keys. It is defined in :rfc:`3447`.
+ developed for use with RSA keys. It is defined in :rfc:`3447`. This padding
+ can be used for signing and encryption.
Mask generation functions
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -60,3 +77,4 @@ Mask generation functions
.. _`Padding is critical`: http://rdist.root.org/2009/10/06/why-rsa-encryption-padding-is-critical/
.. _`security proof`: http://eprint.iacr.org/2001/062.pdf
.. _`recommended padding algorithm`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html
+.. _`proven secure`: http://cseweb.ucsd.edu/users/mihir/papers/oae.pdf
diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst
index 5074f1c5..862df635 100644
--- a/docs/hazmat/primitives/asymmetric/rsa.rst
+++ b/docs/hazmat/primitives/asymmetric/rsa.rst
@@ -116,6 +116,60 @@ RSA
:raises ValueError: This is raised when the chosen hash algorithm is
too large for the key size.
+ .. method:: decrypt(ciphertext, padding, backend)
+
+ .. versionadded:: 0.4
+
+ Decrypt data that was encrypted with the public key.
+
+ :param bytes ciphertext: The ciphertext to decrypt.
+
+ :param padding: An instance of a
+ :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricPadding`
+ provider.
+
+ :param backend: A
+ :class:`~cryptography.hazmat.backends.interfaces.RSABackend`
+ provider.
+
+ :return bytes: Decrypted data.
+
+ :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if
+ the provided ``backend`` does not implement
+ :class:`~cryptography.hazmat.backends.interfaces.RSABackend` or if
+ the backend does not support the chosen hash or padding algorithm.
+ If the padding is
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.OAEP`
+ with the
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.MGF1`
+ mask generation function it may also refer to the ``MGF1`` hash
+ algorithm.
+
+ :raises TypeError: This is raised when the padding is not an
+ :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricPadding`
+ provider.
+
+ :raises ValueError: This is raised when decryption fails or the data
+ is too large for the key size. If the padding is
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.OAEP`
+ it may also be raised for invalid label values.
+
+ .. code-block:: python
+
+ from cryptography.hazmat.backends import default_backend
+ from cryptography.hazmat.primitives import hashes
+ from cryptography.hazmat.primitives.asymmetric import padding
+
+ plaintext = private_key.decrypt(
+ ciphertext,
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ algorithm=hashes.SHA1(),
+ label=None
+ ),
+ default_backend()
+ )
+
.. class:: RSAPublicKey(public_exponent, modulus)
@@ -214,7 +268,42 @@ RSA
too large for the key size.
+Handling partial RSA private keys
+---------------------------------
+
+If you are trying to load RSA private keys yourself you may find that not all
+parameters required by ``RSAPrivateKey`` are available. In particular the
+`Chinese Remainder Theorem`_ (CRT) values ``dmp1``, ``dmq1``, ``iqmp`` may be
+missing or present in a different form. For example `OpenPGP`_ does not include
+the ``iqmp``, ``dmp1`` or ``dmq1`` parameters.
+
+The following functions are provided for users who want to work with keys like
+this without having to do the math themselves.
+
+.. function:: rsa_crt_iqmp(p, q)
+
+ .. versionadded:: 0.4
+
+ Generates the ``iqmp`` (also known as ``qInv``) parameter from the RSA
+ primes ``p`` and ``q``.
+
+.. function:: rsa_crt_dmp1(private_exponent, p)
+
+ .. versionadded:: 0.4
+
+ Generates the ``dmp1`` parameter from the RSA private exponent and prime
+ ``p``.
+
+.. function:: rsa_crt_dmq1(private_exponent, q)
+
+ .. versionadded:: 0.4
+
+ Generates the ``dmq1`` parameter from the RSA private exponent and prime
+ ``q``.
+
.. _`RSA`: https://en.wikipedia.org/wiki/RSA_(cryptosystem)
.. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography
.. _`use 65537`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html
.. _`at least 2048`: http://www.ecrypt.eu.org/documents/D.SPA.20.pdf
+.. _`OpenPGP`: https://en.wikipedia.org/wiki/Pretty_Good_Privacy
+.. _`Chinese Remainder Theorem`: http://en.wikipedia.org/wiki/RSA_%28cryptosystem%29#Using_the_Chinese_remainder_algorithm
diff --git a/docs/hazmat/primitives/index.rst b/docs/hazmat/primitives/index.rst
index 90deec8b..a9ab38a0 100644
--- a/docs/hazmat/primitives/index.rst
+++ b/docs/hazmat/primitives/index.rst
@@ -7,7 +7,7 @@ Primitives
:maxdepth: 1
cryptographic-hashes
- hmac
+ mac/index
symmetric-encryption
padding
key-derivation-functions
diff --git a/docs/hazmat/primitives/interfaces.rst b/docs/hazmat/primitives/interfaces.rst
index 95fd6f9f..3b837a0d 100644
--- a/docs/hazmat/primitives/interfaces.rst
+++ b/docs/hazmat/primitives/interfaces.rst
@@ -133,6 +133,24 @@ Asymmetric interfaces
:returns:
:class:`~cryptography.hazmat.primitives.interfaces.AsymmetricSignatureContext`
+ .. method:: decrypt(ciphertext, padding, backend)
+
+ .. versionadded:: 0.4
+
+ Decrypt data that was encrypted via the public key.
+
+ :param bytes ciphertext: The ciphertext to decrypt.
+
+ :param padding: An instance of a
+ :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricPadding`
+ provider.
+
+ :param backend: A
+ :class:`~cryptography.hazmat.backends.interfaces.RSABackend`
+ provider.
+
+ :return bytes: Decrypted data.
+
.. method:: public_key()
:return: :class:`~cryptography.hazmat.primitives.interfaces.RSAPublicKey`
diff --git a/docs/hazmat/primitives/mac/cmac.rst b/docs/hazmat/primitives/mac/cmac.rst
new file mode 100644
index 00000000..a6b048b5
--- /dev/null
+++ b/docs/hazmat/primitives/mac/cmac.rst
@@ -0,0 +1,107 @@
+.. hazmat::
+
+Cipher-based message authentication code
+========================================
+
+.. currentmodule:: cryptography.hazmat.primitives.cmac
+
+.. testsetup::
+
+ import binascii
+ key = binascii.unhexlify(b"0" * 32)
+
+`Cipher-based message authentication codes`_ (or CMACs) are a tool for calculating
+message authentication codes using a block cipher coupled with a
+secret key. You can use an CMAC to verify both the integrity and authenticity
+of a message.
+
+A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`.
+
+.. class:: CMAC(algorithm, backend)
+
+ .. versionadded:: 0.4
+
+ CMAC objects take a
+ :class:`~cryptography.hazmat.primitives.interfaces.BlockCipherAlgorithm` provider.
+
+ .. doctest::
+
+ >>> from cryptography.hazmat.backends import default_backend
+ >>> from cryptography.hazmat.primitives import cmac
+ >>> from cryptography.hazmat.primitives.ciphers import algorithms
+ >>> c = cmac.CMAC(algorithms.AES(key), backend=default_backend())
+ >>> c.update(b"message to authenticate")
+ >>> c.finalize()
+ 'CT\x1d\xc8\x0e\x15\xbe4e\xdb\xb6\x84\xca\xd9Xk'
+
+ If the backend doesn't support the requested ``algorithm`` an
+ :class:`~cryptography.exceptions.UnsupportedAlgorithm` exception will be
+ raised.
+
+ If the `algorithm`` isn't a
+ :class:`~cryptography.primitives.interfaces.BlockCipherAlgorithm` provider,
+ ``TypeError`` will be raised.
+
+ To check that a given signature is correct use the :meth:`verify` method.
+ You will receive an exception if the signature is wrong:
+
+ .. code-block:: pycon
+
+ >>> c.verify(b"an incorrect signature")
+ Traceback (most recent call last):
+ ...
+ cryptography.exceptions.InvalidSignature: Signature did not match digest.
+
+ :param algorithm: An
+ :class:`~cryptography.hazmat.primitives.interfaces.BlockCipherAlgorithm`
+ provider.
+ :param backend: An
+ :class:`~cryptography.hazmat.backends.interfaces.CMACBackend`
+ provider.
+ :raises TypeError: This is raised if the provided ``algorithm`` is not an instance of
+ :class:`~cryptography.hazmat.primitives.interfaces.BlockCipherAlgorithm`
+ :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the
+ provided ``backend`` does not implement
+ :class:`~cryptography.hazmat.backends.interfaces.CMACBackend`
+
+ .. method:: update(data)
+
+ :param bytes data: The bytes to hash and authenticate.
+ :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
+
+ .. method:: copy()
+
+ Copy this :class:`CMAC` instance, usually so that we may call
+ :meth:`finalize` to get an intermediate value while we continue
+ to call :meth:`update` on the original instance.
+
+ :return: A new instance of :class:`CMAC` that can be updated
+ and finalized independently of the original instance.
+ :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
+
+ .. method:: verify(signature)
+
+ Finalize the current context and securely compare the MAC to
+ ``signature``.
+
+ :param bytes signature: The bytes to compare the current CMAC
+ against.
+ :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
+ :raises cryptography.exceptions.InvalidSignature: If signature does not
+ match digest
+
+ .. method:: finalize()
+
+ Finalize the current context and return the message authentication code
+ as bytes.
+
+ After ``finalize`` has been called this object can no longer be used
+ and :meth:`update`, :meth:`copy`, :meth:`verify` and :meth:`finalize`
+ will raise an :class:`~cryptography.exceptions.AlreadyFinalized`
+ exception.
+
+ :return bytes: The message authentication code as bytes.
+ :raises cryptography.exceptions.AlreadyFinalized:
+
+
+.. _`Cipher-based message authentication codes`: https://en.wikipedia.org/wiki/CMAC
diff --git a/docs/hazmat/primitives/hmac.rst b/docs/hazmat/primitives/mac/hmac.rst
index 11b10735..11b10735 100644
--- a/docs/hazmat/primitives/hmac.rst
+++ b/docs/hazmat/primitives/mac/hmac.rst
diff --git a/docs/hazmat/primitives/mac/index.rst b/docs/hazmat/primitives/mac/index.rst
new file mode 100644
index 00000000..59fb8da2
--- /dev/null
+++ b/docs/hazmat/primitives/mac/index.rst
@@ -0,0 +1,10 @@
+.. hazmat::
+
+Message Authentication Codes
+============================
+
+.. toctree::
+ :maxdepth: 1
+
+ cmac
+ hmac
diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst
index d23f31bb..3056eb92 100644
--- a/docs/hazmat/primitives/padding.rst
+++ b/docs/hazmat/primitives/padding.rst
@@ -5,7 +5,7 @@ Padding
.. currentmodule:: cryptography.hazmat.primitives.padding
-Padding is a way to take data that may or may not be be a multiple of the block
+Padding is a way to take data that may or may not be a multiple of the block
size for a cipher and extend it out so that it is. This is required for many
block cipher modes as they require the data to be encrypted to be an exact
multiple of the block size.
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index 1a4df222..c2692ae2 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -21,7 +21,7 @@ message but an attacker can create bogus messages and force the application to
decrypt them.
For this reason it is *strongly* recommended to combine encryption with a
-message authentication code, such as :doc:`HMAC </hazmat/primitives/hmac>`, in
+message authentication code, such as :doc:`HMAC </hazmat/primitives/mac/hmac>`, in
an "encrypt-then-MAC" formulation as `described by Colin Percival`_.
.. class:: Cipher(algorithm, mode, backend)
@@ -289,7 +289,7 @@ Modes
block cipher mode that simultaneously encrypts the message as well as
authenticating it. Additional unencrypted data may also be authenticated.
Additional means of verifying integrity such as
- :doc:`HMAC </hazmat/primitives/hmac>` are not necessary.
+ :doc:`HMAC </hazmat/primitives/mac/hmac>` are not necessary.
**This mode does not require padding.**
diff --git a/docs/installation.rst b/docs/installation.rst
index a0dd5f22..3ebbecfd 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -10,16 +10,27 @@ You can install ``cryptography`` with ``pip``:
Supported platforms
-------------------
-Currently we test ``cryptography`` on Python 2.6, 2.7, 3.2, 3.3 and PyPy on
-these operating systems.
+Currently we test ``cryptography`` on Python 2.6, 2.7, 3.2, 3.3, 3.4 and PyPy
+on these operating systems.
-* x86-64 CentOS 6.4 and CentOS 5
+* x86-64 CentOS 6.4 and CentOS 5.x
* x86-64 FreeBSD 9.2 and FreeBSD 10
* OS X 10.9 Mavericks, 10.8 Mountain Lion, and 10.7 Lion
* x86-64 Ubuntu 12.04 LTS
* 32-bit Python on 64-bit Windows Server 2008
* 64-bit Python on 64-bit Windows Server 2012
+We test compiling with ``clang`` as well as ``gcc`` and use the following
+OpenSSL releases:
+
+* ``OpenSSL 0.9.8e-fips-rhel5`` (``RHEL/CentOS 5``)
+* ``OpenSSL 0.9.8y``
+* ``OpenSSL 1.0.0-fips`` (``RHEL/CentOS 6.4``)
+* ``OpenSSL 1.0.1``
+* ``OpenSSL 1.0.1e-freebsd``
+* ``OpenSSL 1.0.1g``
+* ``OpenSSL 1.0.2 beta``
+
On Windows
----------
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index 02b9f9ef..aae52ae7 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -25,6 +25,7 @@ interoperable
introspectability
invariants
iOS
+metadata
pickleable
plaintext
pseudorandom
diff --git a/pytest.ini b/pytest.ini
index b590d0be..f717693d 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -2,9 +2,11 @@
addopts = -r s
markers =
cipher: this test requires a backend providing CipherBackend
+ cmac: this test requires a backend providing CMACBackend
dsa: this test requires a backend providing DSABackend
hash: this test requires a backend providing HashBackend
hmac: this test requires a backend providing HMACBackend
pbkdf2hmac: this test requires a backend providing PBKDF2HMACBackend
rsa: this test requires a backend providing RSABackend
+ traditional_openssl_serialization: this test requires a backend providing TraditionalOpenSSLSerializationBackend
supported: parametrized test requiring only_if and skip_message
diff --git a/setup.py b/setup.py
index c1a6d642..c841911f 100644
--- a/setup.py
+++ b/setup.py
@@ -14,9 +14,9 @@
from __future__ import absolute_import, division, print_function
import os
+import subprocess
import sys
from distutils.command.build import build
-import subprocess
import pkg_resources
diff --git a/tests/conftest.py b/tests/conftest.py
index 1ee2a993..86d5a03b 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -17,10 +17,9 @@ import pytest
from cryptography.hazmat.backends import _available_backends
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- RSABackend
+ CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
+ PBKDF2HMACBackend, RSABackend, TraditionalOpenSSLSerializationBackend
)
-
from .utils import check_backend_support, check_for_iface, select_backends
@@ -36,10 +35,16 @@ def pytest_generate_tests(metafunc):
def pytest_runtest_setup(item):
check_for_iface("hmac", HMACBackend, item)
check_for_iface("cipher", CipherBackend, item)
+ check_for_iface("cmac", CMACBackend, item)
check_for_iface("hash", HashBackend, item)
check_for_iface("pbkdf2hmac", PBKDF2HMACBackend, item)
check_for_iface("dsa", DSABackend, item)
check_for_iface("rsa", RSABackend, item)
+ check_for_iface(
+ "traditional_openssl_serialization",
+ TraditionalOpenSSLSerializationBackend,
+ item
+ )
check_backend_support(item)
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index f46009d4..d8c09bd7 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -18,11 +18,11 @@ from cryptography.exceptions import (
UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- RSABackend
+ CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
+ PBKDF2HMACBackend, RSABackend
)
from cryptography.hazmat.backends.multibackend import MultiBackend
-from cryptography.hazmat.primitives import hashes, hmac
+from cryptography.hazmat.primitives import cmac, hashes, hmac
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
@@ -108,6 +108,19 @@ class DummyDSABackend(object):
pass
+@utils.register_interface(CMACBackend)
+class DummyCMACBackend(object):
+ def __init__(self, supported_algorithms):
+ self._algorithms = supported_algorithms
+
+ def cmac_algorithm_supported(self, algorithm):
+ return type(algorithm) in self._algorithms
+
+ def create_cmac_ctx(self, algorithm):
+ if not self.cmac_algorithm_supported(algorithm):
+ raise UnsupportedAlgorithm("", _Reasons.UNSUPPORTED_CIPHER)
+
+
class TestMultiBackend(object):
def test_ciphers(self):
backend = MultiBackend([
@@ -224,3 +237,18 @@ class TestMultiBackend(object):
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
):
backend.generate_dsa_private_key(parameters)
+
+ def test_cmac(self):
+ backend = MultiBackend([
+ DummyCMACBackend([algorithms.AES])
+ ])
+
+ fake_key = b"\x00" * 16
+
+ assert backend.cmac_algorithm_supported(
+ algorithms.AES(fake_key)) is True
+
+ cmac.CMAC(algorithms.AES(fake_key), backend)
+
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
+ cmac.CMAC(algorithms.TripleDES(fake_key), backend)
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 4f682f66..58511666 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -23,6 +23,7 @@ from cryptography.hazmat.primitives.asymmetric import dsa, padding, rsa
from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import CBC
+from cryptography.hazmat.primitives.interfaces import BlockCipherAlgorithm
from ...utils import raises_unsupported_algorithm
@@ -143,8 +144,8 @@ class TestOpenSSL(object):
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH):
backend.derive_pbkdf2_hmac(hashes.SHA256(), 10, b"", 1000, b"")
- # This test is not in the next class because to check if it's really
- # default we don't want to run the setup_method before it
+ # This test is not in the TestOpenSSLRandomEngine class because to check
+ # if it's really default we don't want to run the setup_method before it
def test_osrandom_engine_is_default(self):
e = backend._lib.ENGINE_get_default_RAND()
name = backend._lib.ENGINE_get_name(e)
@@ -233,6 +234,25 @@ class TestOpenSSLRandomEngine(object):
e = backend._lib.ENGINE_get_default_RAND()
assert e == backend._ffi.NULL
+ def test_int_to_bn(self):
+ value = (2 ** 4242) - 4242
+ bn = backend._int_to_bn(value)
+ assert bn != backend._ffi.NULL
+ bn = backend._ffi.gc(bn, backend._lib.BN_free)
+
+ assert bn
+ assert backend._bn_to_int(bn) == value
+
+ def test_int_to_bn_inplace(self):
+ value = (2 ** 4242) - 4242
+ bn_ptr = backend._lib.BN_new()
+ assert bn_ptr != backend._ffi.NULL
+ bn_ptr = backend._ffi.gc(bn_ptr, backend._lib.BN_free)
+ bn = backend._int_to_bn(value, bn_ptr)
+
+ assert bn == bn_ptr
+ assert backend._bn_to_int(bn_ptr) == value
+
class TestOpenSSLRSA(object):
@pytest.mark.skipif(
@@ -272,3 +292,69 @@ class TestOpenSSLRSA(object):
def test_unsupported_mgf1_hash_algorithm(self):
assert backend.mgf1_hash_supported(DummyHash()) is False
+
+ def test_unsupported_mgf1_hash_algorithm_decrypt(self):
+ private_key = rsa.RSAPrivateKey.generate(
+ public_exponent=65537,
+ key_size=512,
+ backend=backend
+ )
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH):
+ private_key.decrypt(
+ b"ciphertext",
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA1(),
+ label=None
+ ),
+ backend
+ )
+
+ def test_unsupported_oaep_hash_algorithm_decrypt(self):
+ private_key = rsa.RSAPrivateKey.generate(
+ public_exponent=65537,
+ key_size=512,
+ backend=backend
+ )
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH):
+ private_key.decrypt(
+ b"ciphertext",
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ algorithm=hashes.SHA256(),
+ label=None
+ ),
+ backend
+ )
+
+ def test_unsupported_oaep_label_decrypt(self):
+ private_key = rsa.RSAPrivateKey.generate(
+ public_exponent=65537,
+ key_size=512,
+ backend=backend
+ )
+ with pytest.raises(ValueError):
+ private_key.decrypt(
+ b"ciphertext",
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ algorithm=hashes.SHA1(),
+ label=b"label"
+ ),
+ backend
+ )
+
+
+@pytest.mark.skipif(
+ backend._lib.OPENSSL_VERSION_NUMBER <= 0x10001000,
+ reason="Requires an OpenSSL version >= 1.0.1"
+)
+class TestOpenSSLCMAC(object):
+ def test_unsupported_cipher(self):
+ @utils.register_interface(BlockCipherAlgorithm)
+ class FakeAlgorithm(object):
+ def __init__(self):
+ self.block_size = 64
+
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
+ backend.create_cmac_ctx(FakeAlgorithm())
diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py
index acab22b1..58d7602b 100644
--- a/tests/hazmat/bindings/test_openssl.py
+++ b/tests/hazmat/bindings/test_openssl.py
@@ -84,7 +84,7 @@ class TestOpenSSL(object):
with pytest.raises(RuntimeError):
b._lock_cb(0, b.lib.CRYPTO_LOCK_SSL, "<test>", 1)
- # errors shouldnt cause locking
+ # errors shouldn't cause locking
assert lock.acquire(False)
lock.release()
@@ -103,3 +103,37 @@ class TestOpenSSL(object):
b = Binding()
res = b.lib.Cryptography_add_osrandom_engine()
assert res == 2
+
+ def test_ssl_ctx_options(self):
+ # Test that we're properly handling 32-bit unsigned on all platforms.
+ b = Binding()
+ assert b.lib.SSL_OP_ALL > 0
+ ctx = b.lib.SSL_CTX_new(b.lib.TLSv1_method())
+ ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free)
+ resp = b.lib.SSL_CTX_set_options(ctx, b.lib.SSL_OP_ALL)
+ assert resp == b.lib.SSL_OP_ALL
+ assert b.lib.SSL_OP_ALL == b.lib.SSL_CTX_get_options(ctx)
+
+ def test_ssl_options(self):
+ # Test that we're properly handling 32-bit unsigned on all platforms.
+ b = Binding()
+ assert b.lib.SSL_OP_ALL > 0
+ ctx = b.lib.SSL_CTX_new(b.lib.TLSv1_method())
+ ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free)
+ ssl = b.lib.SSL_new(ctx)
+ ssl = b.ffi.gc(ssl, b.lib.SSL_free)
+ resp = b.lib.SSL_set_options(ssl, b.lib.SSL_OP_ALL)
+ assert resp == b.lib.SSL_OP_ALL
+ assert b.lib.SSL_OP_ALL == b.lib.SSL_get_options(ssl)
+
+ def test_ssl_mode(self):
+ # Test that we're properly handling 32-bit unsigned on all platforms.
+ b = Binding()
+ assert b.lib.SSL_OP_ALL > 0
+ ctx = b.lib.SSL_CTX_new(b.lib.TLSv1_method())
+ ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free)
+ ssl = b.lib.SSL_new(ctx)
+ ssl = b.ffi.gc(ssl, b.lib.SSL_free)
+ resp = b.lib.SSL_set_mode(ssl, b.lib.SSL_OP_ALL)
+ assert resp == b.lib.SSL_OP_ALL
+ assert b.lib.SSL_OP_ALL == b.lib.SSL_get_mode(ssl)
diff --git a/tests/hazmat/primitives/test_cmac.py b/tests/hazmat/primitives/test_cmac.py
new file mode 100644
index 00000000..7ec4af68
--- /dev/null
+++ b/tests/hazmat/primitives/test_cmac.py
@@ -0,0 +1,217 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import, division, print_function
+
+import binascii
+
+import pretend
+
+import pytest
+
+import six
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, InvalidSignature, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import CMACBackend
+from cryptography.hazmat.primitives.ciphers.algorithms import (
+ AES, ARC4, TripleDES
+)
+from cryptography.hazmat.primitives.cmac import CMAC
+
+from tests.utils import (
+ load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm
+)
+
+vectors_aes128 = load_vectors_from_file(
+ "CMAC/nist-800-38b-aes128.txt", load_nist_vectors)
+
+vectors_aes192 = load_vectors_from_file(
+ "CMAC/nist-800-38b-aes192.txt", load_nist_vectors)
+
+vectors_aes256 = load_vectors_from_file(
+ "CMAC/nist-800-38b-aes256.txt", load_nist_vectors)
+
+vectors_aes = vectors_aes128 + vectors_aes192 + vectors_aes256
+
+vectors_3des = load_vectors_from_file(
+ "CMAC/nist-800-38b-3des.txt", load_nist_vectors)
+
+fake_key = b"\x00" * 16
+
+
+@pytest.mark.cmac
+class TestCMAC(object):
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cmac_algorithm_supported(
+ AES(fake_key)),
+ skip_message="Does not support CMAC."
+ )
+ @pytest.mark.parametrize("params", vectors_aes)
+ def test_aes_generate(self, backend, params):
+ key = params["key"]
+ message = params["message"]
+ output = params["output"]
+
+ cmac = CMAC(AES(binascii.unhexlify(key)), backend)
+ cmac.update(binascii.unhexlify(message))
+ assert binascii.hexlify(cmac.finalize()) == output
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cmac_algorithm_supported(
+ AES(fake_key)),
+ skip_message="Does not support CMAC."
+ )
+ @pytest.mark.parametrize("params", vectors_aes)
+ def test_aes_verify(self, backend, params):
+ key = params["key"]
+ message = params["message"]
+ output = params["output"]
+
+ cmac = CMAC(AES(binascii.unhexlify(key)), backend)
+ cmac.update(binascii.unhexlify(message))
+ assert cmac.verify(binascii.unhexlify(output)) is None
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cmac_algorithm_supported(
+ TripleDES(fake_key)),
+ skip_message="Does not support CMAC."
+ )
+ @pytest.mark.parametrize("params", vectors_3des)
+ def test_3des_generate(self, backend, params):
+ key1 = params["key1"]
+ key2 = params["key2"]
+ key3 = params["key3"]
+
+ key = key1 + key2 + key3
+
+ message = params["message"]
+ output = params["output"]
+
+ cmac = CMAC(TripleDES(binascii.unhexlify(key)), backend)
+ cmac.update(binascii.unhexlify(message))
+ assert binascii.hexlify(cmac.finalize()) == output
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cmac_algorithm_supported(
+ TripleDES(fake_key)),
+ skip_message="Does not support CMAC."
+ )
+ @pytest.mark.parametrize("params", vectors_3des)
+ def test_3des_verify(self, backend, params):
+ key1 = params["key1"]
+ key2 = params["key2"]
+ key3 = params["key3"]
+
+ key = key1 + key2 + key3
+
+ message = params["message"]
+ output = params["output"]
+
+ cmac = CMAC(TripleDES(binascii.unhexlify(key)), backend)
+ cmac.update(binascii.unhexlify(message))
+ assert cmac.verify(binascii.unhexlify(output)) is None
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cmac_algorithm_supported(
+ AES(fake_key)),
+ skip_message="Does not support CMAC."
+ )
+ def test_invalid_verify(self, backend):
+ key = b"2b7e151628aed2a6abf7158809cf4f3c"
+ cmac = CMAC(AES(key), backend)
+ cmac.update(b"6bc1bee22e409f96e93d7e117393172a")
+
+ with pytest.raises(InvalidSignature):
+ cmac.verify(b"foobar")
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ ARC4(fake_key), None),
+ skip_message="Does not support CMAC."
+ )
+ def test_invalid_algorithm(self, backend):
+ key = b"0102030405"
+ with pytest.raises(TypeError):
+ CMAC(ARC4(key), backend)
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cmac_algorithm_supported(
+ AES(fake_key)),
+ skip_message="Does not support CMAC."
+ )
+ def test_raises_after_finalize(self, backend):
+ key = b"2b7e151628aed2a6abf7158809cf4f3c"
+ cmac = CMAC(AES(key), backend)
+ cmac.finalize()
+
+ with pytest.raises(AlreadyFinalized):
+ cmac.update(b"foo")
+
+ with pytest.raises(AlreadyFinalized):
+ cmac.copy()
+
+ with pytest.raises(AlreadyFinalized):
+ cmac.finalize()
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cmac_algorithm_supported(
+ AES(fake_key)),
+ skip_message="Does not support CMAC."
+ )
+ def test_verify_reject_unicode(self, backend):
+ key = b"2b7e151628aed2a6abf7158809cf4f3c"
+ cmac = CMAC(AES(key), backend)
+
+ with pytest.raises(TypeError):
+ cmac.update(six.u(''))
+
+ with pytest.raises(TypeError):
+ cmac.verify(six.u(''))
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cmac_algorithm_supported(
+ AES(fake_key)),
+ skip_message="Does not support CMAC."
+ )
+ def test_copy_with_backend(self, backend):
+ key = b"2b7e151628aed2a6abf7158809cf4f3c"
+ cmac = CMAC(AES(key), backend)
+ cmac.update(b"6bc1bee22e409f96e93d7e117393172a")
+ copy_cmac = cmac.copy()
+ assert cmac.finalize() == copy_cmac.finalize()
+
+
+def test_copy():
+ @utils.register_interface(CMACBackend)
+ class PretendBackend(object):
+ pass
+
+ pretend_backend = PretendBackend()
+ copied_ctx = pretend.stub()
+ pretend_ctx = pretend.stub(copy=lambda: copied_ctx)
+ key = b"2b7e151628aed2a6abf7158809cf4f3c"
+ cmac = CMAC(AES(key), backend=pretend_backend, ctx=pretend_ctx)
+
+ assert cmac._backend is pretend_backend
+ assert cmac.copy()._backend is pretend_backend
+
+
+def test_invalid_backend():
+ key = b"2b7e151628aed2a6abf7158809cf4f3c"
+ pretend_backend = object()
+
+ with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
+ CMAC(AES(key), pretend_backend)
diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py
index 2b5d4bb3..bc3b1db6 100644
--- a/tests/hazmat/primitives/test_dsa.py
+++ b/tests/hazmat/primitives/test_dsa.py
@@ -23,7 +23,7 @@ from cryptography.hazmat.primitives.asymmetric import dsa
from cryptography.utils import bit_length
from ...utils import (
- load_vectors_from_file, load_fips_dsa_key_pair_vectors,
+ load_fips_dsa_key_pair_vectors, load_vectors_from_file,
raises_unsupported_algorithm
)
diff --git a/tests/hazmat/primitives/test_pbkdf2hmac.py b/tests/hazmat/primitives/test_pbkdf2hmac.py
index 62ca0921..e928fc6a 100644
--- a/tests/hazmat/primitives/test_pbkdf2hmac.py
+++ b/tests/hazmat/primitives/test_pbkdf2hmac.py
@@ -14,6 +14,7 @@
from __future__ import absolute_import, division, print_function
import pytest
+
import six
from cryptography import utils
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index 1cbd1636..34b80cc3 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -26,7 +26,9 @@ from cryptography.exceptions import _Reasons
from cryptography.hazmat.primitives import hashes, interfaces
from cryptography.hazmat.primitives.asymmetric import padding, rsa
-from .utils import generate_rsa_verification_test
+from .utils import (
+ _check_rsa_private_key, generate_rsa_verification_test
+)
from ...utils import (
load_pkcs1_vectors, load_rsa_nist_vectors, load_vectors_from_file,
raises_unsupported_algorithm
@@ -42,37 +44,6 @@ class DummyMGF(object):
_salt_length = 0
-def _modinv(e, m):
- """
- Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
- """
- x1, y1, x2, y2 = 1, 0, 0, 1
- a, b = e, m
- while b > 0:
- q, r = divmod(a, b)
- xn, yn = x1 - q * x2, y1 - q * y2
- a, b, x1, y1, x2, y2 = b, r, x2, y2, xn, yn
- return x1 % m
-
-
-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
- assert skey.dmp1 == skey.d % (skey.p - 1)
- assert skey.dmq1 == skey.d % (skey.q - 1)
- assert skey.iqmp == _modinv(skey.q, skey.p)
-
- 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
-
-
def _flatten_pkcs1_examples(vectors):
flattened_vectors = []
for vector in vectors:
@@ -97,7 +68,7 @@ def test_modular_inverse():
"b2347cfcd669133088d1c159518531025297c2d67c9da856a12e80222cd03b4c6ec0f"
"86c957cb7bb8de7a127b645ec9e820aa94581e4762e209f01", 16
)
- assert _modinv(q, p) == int(
+ assert rsa._modinv(q, p) == int(
"0275e06afa722999315f8f322275483e15e2fb46d827b17800f99110b269a6732748f"
"624a382fa2ed1ec68c99f7fc56fb60e76eea51614881f497ba7034c17dde955f92f15"
"772f8b2b41f3e56d88b1e096cdd293eba4eae1e82db815e0fadea0c4ec971bc6fd875"
@@ -108,7 +79,7 @@ def test_modular_inverse():
@pytest.mark.rsa
class TestRSA(object):
@pytest.mark.parametrize(
- "public_exponent,key_size",
+ ("public_exponent", "key_size"),
itertools.product(
(3, 5, 65537),
(1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1536, 2048)
@@ -1238,3 +1209,157 @@ class TestMGF1(object):
mgf = padding.MGF1(algorithm, padding.MGF1.MAX_LENGTH)
assert mgf._algorithm == algorithm
assert mgf._salt_length == padding.MGF1.MAX_LENGTH
+
+
+class TestOAEP(object):
+ def test_invalid_algorithm(self):
+ mgf = padding.MGF1(hashes.SHA1())
+ with pytest.raises(TypeError):
+ padding.OAEP(
+ mgf=mgf,
+ algorithm=b"",
+ label=None
+ )
+
+
+@pytest.mark.rsa
+class TestRSADecryption(object):
+ @pytest.mark.parametrize(
+ "vector",
+ _flatten_pkcs1_examples(load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "RSA", "pkcs1v15crypt-vectors.txt"),
+ load_pkcs1_vectors
+ ))
+ )
+ def test_decrypt_pkcs1v15_vectors(self, vector, backend):
+ private, public, example = vector
+ skey = rsa.RSAPrivateKey(
+ p=private["p"],
+ q=private["q"],
+ private_exponent=private["private_exponent"],
+ dmp1=private["dmp1"],
+ dmq1=private["dmq1"],
+ iqmp=private["iqmp"],
+ public_exponent=private["public_exponent"],
+ modulus=private["modulus"]
+ )
+ ciphertext = binascii.unhexlify(example["encryption"])
+ assert len(ciphertext) == math.ceil(skey.key_size / 8.0)
+ message = skey.decrypt(
+ ciphertext,
+ padding.PKCS1v15(),
+ backend
+ )
+ assert message == binascii.unhexlify(example["message"])
+
+ def test_unsupported_padding(self, backend):
+ private_key = rsa.RSAPrivateKey.generate(
+ public_exponent=65537,
+ key_size=512,
+ backend=backend
+ )
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING):
+ private_key.decrypt(b"somedata", DummyPadding(), backend)
+
+ def test_decrypt_invalid_decrypt(self, backend):
+ private_key = rsa.RSAPrivateKey.generate(
+ public_exponent=65537,
+ key_size=512,
+ backend=backend
+ )
+ with pytest.raises(ValueError):
+ private_key.decrypt(
+ b"\x00" * 64,
+ padding.PKCS1v15(),
+ backend
+ )
+
+ def test_decrypt_ciphertext_too_large(self, backend):
+ private_key = rsa.RSAPrivateKey.generate(
+ public_exponent=65537,
+ key_size=512,
+ backend=backend
+ )
+ with pytest.raises(ValueError):
+ private_key.decrypt(
+ b"\x00" * 65,
+ padding.PKCS1v15(),
+ backend
+ )
+
+ def test_decrypt_ciphertext_too_small(self, backend):
+ private_key = rsa.RSAPrivateKey.generate(
+ public_exponent=65537,
+ key_size=512,
+ backend=backend
+ )
+ ct = binascii.unhexlify(
+ b"50b4c14136bd198c2f3c3ed243fce036e168d56517984a263cd66492b80804f1"
+ b"69d210f2b9bdfb48b12f9ea05009c77da257cc600ccefe3a6283789d8ea0"
+ )
+ with pytest.raises(ValueError):
+ private_key.decrypt(
+ ct,
+ padding.PKCS1v15(),
+ backend
+ )
+
+ def test_rsa_decrypt_invalid_backend(self, backend):
+ pretend_backend = object()
+ private_key = rsa.RSAPrivateKey.generate(65537, 2048, backend)
+
+ with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
+ private_key.decrypt(
+ b"irrelevant",
+ padding.PKCS1v15(),
+ pretend_backend
+ )
+
+ @pytest.mark.parametrize(
+ "vector",
+ _flatten_pkcs1_examples(load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "oaep-vect.txt"),
+ load_pkcs1_vectors
+ ))
+ )
+ def test_decrypt_oaep_vectors(self, vector, backend):
+ private, public, example = vector
+ skey = rsa.RSAPrivateKey(
+ p=private["p"],
+ q=private["q"],
+ private_exponent=private["private_exponent"],
+ dmp1=private["dmp1"],
+ dmq1=private["dmq1"],
+ iqmp=private["iqmp"],
+ public_exponent=private["public_exponent"],
+ modulus=private["modulus"]
+ )
+ message = skey.decrypt(
+ binascii.unhexlify(example["encryption"]),
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ algorithm=hashes.SHA1(),
+ label=None
+ ),
+ backend
+ )
+ assert message == binascii.unhexlify(example["message"])
+
+ def test_unsupported_oaep_mgf(self, backend):
+ private_key = rsa.RSAPrivateKey.generate(
+ public_exponent=65537,
+ key_size=512,
+ backend=backend
+ )
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF):
+ private_key.decrypt(
+ b"ciphertext",
+ padding.OAEP(
+ mgf=DummyMGF(),
+ algorithm=hashes.SHA1(),
+ label=None
+ ),
+ backend
+ )
diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py
index 2e838474..6c3f4c95 100644
--- a/tests/hazmat/primitives/utils.py
+++ b/tests/hazmat/primitives/utils.py
@@ -406,3 +406,21 @@ def rsa_verification_test(backend, params, hash_alg, pad_factory):
verifier.verify()
else:
verifier.verify()
+
+
+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
+ assert skey.dmp1 == rsa.rsa_crt_dmp1(skey.d, skey.p)
+ assert skey.dmq1 == rsa.rsa_crt_dmq1(skey.d, skey.q)
+ assert skey.iqmp == rsa.rsa_crt_iqmp(skey.p, skey.q)
+
+ 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
diff --git a/tests/test_utils.py b/tests/test_utils.py
index c91efa7f..7a0b9e74 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -28,9 +28,10 @@ import cryptography_vectors
from .utils import (
check_backend_support, check_for_iface, load_cryptrec_vectors,
- load_fips_dsa_key_pair_vectors, load_fips_ecdsa_key_pair_vectors,
- load_fips_ecdsa_signing_vectors, load_hash_vectors, load_nist_vectors,
- load_pkcs1_vectors, load_rsa_nist_vectors, load_vectors_from_file,
+ load_fips_dsa_key_pair_vectors, load_fips_dsa_sig_vectors,
+ load_fips_ecdsa_key_pair_vectors, load_fips_ecdsa_signing_vectors,
+ load_hash_vectors, load_nist_vectors, load_pkcs1_vectors,
+ load_rsa_nist_vectors, load_vectors_from_file,
raises_unsupported_algorithm, select_backends
)
@@ -1824,45 +1825,503 @@ de61329a78d526f65245380ce877e979c5b50de66c9c30d66382c8f254653d25a1eb1d3a4897d7\
assert expected == load_fips_dsa_key_pair_vectors(vector_data)
-def test_vector_version():
- assert cryptography.__version__ == cryptography_vectors.__version__
-
-
-def test_raises_unsupported_algorithm_wrong_type():
- # Check that it raises if the wrong type of exception is raised.
- class TestException(Exception):
- pass
-
- with pytest.raises(TestException):
- with raises_unsupported_algorithm(None):
- raise TestException
+def test_load_fips_dsa_sig_ver_vectors():
+ vector_data = textwrap.dedent("""
+ # CAVS 11.0
+ # "SigVer" information
+ # Mod sizes selected: SHA-1 L=1024, N=160,SHA-384 L=2048, N=256
+ # Generated on Fri Apr 01 08:37:15 2011
+
+ [mod = L=1024, N=160, SHA-1]
+
+ P = dc5bf3a88b2d99e4c95cdd7a0501cc38630d425cf5c390af3429cff1f35147b795cae\
+a923f0d3577158f8a0c89dabd1962c2c453306b5d70cacfb01430aceb54e5a5fa6f93\
+40d3bd2da612fceeb76b0ec1ebfae635a56ab141b108e00dc76eefe2edd0c514c21c4\
+57457c39065dba9d0ecb7569c247172d8438ad2827b60435b
+ Q = e956602b83d195dbe945b3ac702fc61f81571f1d
+ G = d7eb9ca20a3c7a079606bafc4c9261ccaba303a5dc9fe9953f197dfe548c234895baa\
+77f441ee6a2d97b909cbbd26ff7b869d24cae51b5c6edb127a4b5d75cd8b46608bfa1\
+48249dffdb59807c5d7dde3fe3080ca3a2d28312142becb1fa8e24003e21c72871081\
+74b95d5bc711e1c8d9b1076784f5dc37a964a5e51390da713
+
+ Msg = 0fe1bfee500bdb76026099b1d37553f6bdfe48c82094ef98cb309dd777330bedfaa\
+2f94c823ef74ef4074b50d8706041ac0e371c7c22dcf70263b8d60e17a86c7c379c\
+fda8f22469e0df9d49d59439fc99891873628fff25dda5fac5ac794e948babdde96\
+8143ba05f1128f34fdad5875edc4cd71c6c24ba2060ffbd439ce2b3
+ X = 1d93010c29ecfc432188942f46f19f44f0e1bb5d
+ Y = 6240ea0647117c38fe705106d56db578f3e10130928452d4f3587881b8a2bc6873a8b\
+efc3237f20914e2a91c7f07a928ee22adeed23d74ab7f82ea11f70497e578f7a9b4cb\
+d6f10226222b0b4da2ea1e49813d6bb9882fbf675c0846bb80cc891857b89b0ef1beb\
+6cce3378a9aab5d66ad4cb9277cf447dfe1e64434749432fb
+ R = b5af307867fb8b54390013cc67020ddf1f2c0b81
+ S = 620d3b22ab5031440c3e35eab6f481298f9e9f08
+ Result = P
+ Msg = 97d50898025d2f9ba633866e968ca75e969d394edba6517204cb3dd537c2ba38778\
+a2dc9dbc685a915e5676fcd43bc3726bc59ce3d7a9fae35565082a069c139fa37c9\
+0d922b126933db3fa6c5ef6b1edf00d174a51887bb76909c6a94fe994ecc7b7fc8f\
+26113b17f30f9d01693df99a125b4f17e184331c6b6e8ca00f54f3a
+ X = 350e13534692a7e0c4b7d58836046c436fbb2322
+ Y = 69974de550fe6bd3099150faea1623ad3fb6d9bf23a07215093f319725ad0877accff\
+d291b6da18eb0cbe51676ceb0977504eb97c27c0b191883f72fb2710a9fbd8bcf13be\
+0bf854410b32f42b33ec89d3cc1cf892bcd536c4195ca9ada302ad600c3408739935d\
+77dc247529ca47f844cc86f5016a2fe962c6e20ca7c4d4e8f
+ R = b5d05faa7005764e8dae0327c5bf1972ff7681b9
+ S = 18ea15bd9f00475b25204cbc23f8c23e01588015
+ Result = F (3 - R changed )
+
+ [mod = L=2048, N=224, SHA-1]
+
+ # unsupported so we ignore this
+
+ Msg = f9d01693df99a125b4f17e184331c6b6e8ca00f54f3a
+ X = e0c4b7d58836046c436fbb2322
+ Y = fb6d9bf23a07215093f319725ad0877accff
+ R = 5764e8dae0327c5bf1972ff7681b9
+ S = 475b25204cbc23f8c23e01588015
+ Result = F (3 - R changed )
+
+ [mod = L=2048, N=256, SHA-384]
+
+ P = e7c1c86125db9ef417da1ced7ea0861bdad629216a3f3c745df42a46b989e59f4d984\
+25ee3c932fa3c2b6f637bdb6545bec526faa037e11f5578a4363b9fca5eba60d6a9cb\
+aa2befd04141d989c7356285132c2eaf74f2d868521cdc0a17ae9a2546ef863027d3f\
+8cc7949631fd0e2971417a912c8b8c5c989730db6ea6e8baee0e667850429038093c8\
+51ccb6fb173bb081e0efe0bd7450e0946888f89f75e443ab93ef2da293a01622cf43c\
+6dd79625d41ba8f9ef7e3086ab39134283d8e96c89249488120fd061e4a87d34af410\
+69c0b4fd3934c31b589cbe85b68b912718d5dab859fda7082511fad1d152044905005\
+546e19b14aa96585a55269bf2b831
+ Q = 8e056ec9d4b7acb580087a6ed9ba3478711bb025d5b8d9c731ef9b38bd43db2f
+ G = dc2bfb9776786ad310c8b0cdcbba3062402613c67e6959a8d8d1b05aab636528b7b1f\
+e9cd33765f853d6dbe13d09f2681f8c7b1ed7886aaed70c7bd76dbe858ffb8bd86235\
+ddf759244678f428c6519af593dc94eeadbd9852ba2b3d61664e8d58c29d2039af3c3\
+d6d16f90988f6a8c824569f3d48050e30896a9e17cd0232ef01ab8790008f6973b84c\
+763a72f4ae8b485abfb7e8efeb86808fa2b281d3e5d65d28f5992a34c077c5aa8026c\
+b2fbc34a45f7e9bd216b10e6f12ecb172e9a6eb8f2e91316905b6add1fd22e83bc2f0\
+89f1d5e6a6e6707c18ff55ddcb7954e8bceaf0efc4e8314910c03b0e51175f344faaf\
+ee476a373ac95743cec712b72cf2e
+
+ Msg = 6cd6ccfd66bcd832189c5f0c77994210e3bf2c43416f0fe77c4e92f31c5369538dc\
+2c003f146c5ac79df43194ccf3c44d470d9f1083bd15b99b5bcf88c32d8a9021f09\
+ea2288d7b3bf345a12aef3949c1e121b9fb371a67c2d1377364206ac839dd784835\
+61426bda0303f285aa12e9c45d3cdfc6beae3549703b187deeb3296
+ X = 56c897b5938ad5b3d437d7e4826da586a6b3be15e893fa1aaa946f20a028b6b3
+ Y = 38ad44489e1a5778b9689f4dcf40e2acf23840fb954e987d6e8cb629106328ac64e1f\
+3c3eba48b21176ad4afe3b733bead382ee1597e1b83e4b43424f2daaba04e5bd79e14\
+36693ac2bddb79a298f026e57e200a252efd1e848a4a2e90be6e78f5242b468b9c0c6\
+d2615047a5a40b9ae7e57a519114db55bf3bed65e580f894b094630ca9c217f6accd0\
+91e72d2f22da620044ff372d7273f9445017fad492959e59600b7494dbe766a03e401\
+25d4e6747c76f68a5b0cdc0e7d7cee12d08c6fb7d0fb049e420a33405075ed4463296\
+345ca695fb7feab7c1b5333ae519fcd4bb6a043f4555378969114743d4face96cad31\
+c0e0089da4e3f61b6d7dabc088ab7
+ R = 3b85b17be240ed658beb3652c9d93e8e9eea160d35ee2459614305802963374e
+ S = 726800a5174a53b56dce86064109c0273cd11fcfa3c92c5cd6aa910260c0e3c7
+ Result = F (1 - Message changed)
+
+ Msg = 3ad6b0884f358dea09c31a9abc40c45a6000611fc2b907b30eac00413fd2819de70\
+15488a411609d46c499b8f7afa1b78b352ac7f8535bd805b8ff2a5eae557098c668\
+f7ccd73af886d6823a6d456c29931ee864ed46d767382785728c2a83fcff5271007\
+d2a67d06fa205fd7b9d1a42ea5d6dc76e5e18a9eb148cd1e8b262ae
+ X = 2faf566a9f057960f1b50c69508f483d9966d6e35743591f3a677a9dc40e1555
+ Y = 926425d617babe87c442b03903e32ba5bbf0cd9d602b59c4df791a4d64a6d4333ca0c\
+0d370552539197d327dcd1bbf8c454f24b03fc7805f862db34c7b066ddfddbb11dbd0\
+10b27123062d028fe041cb56a2e77488348ae0ab6705d87aac4d4e9e6600e9e706326\
+d9979982cffa839beb9eacc3963bcca455a507e80c1c37ad4e765b2c9c0477a075e9b\
+c584feacdf3a35a9391d4711f14e197c54022282bfed9a191213d64127f17a9c5affe\
+c26e0c71f15d3a5b16098fec118c45bf8bb2f3b1560df0949254c1c0aeb0a16d5a95a\
+40fab8521fbe8ea77c51169b587cc3360e5733e6a23b9fded8c40724ea1f9e93614b3\
+a6c9b4f8dbbe915b794497227ba62
+ R = 343ea0a9e66277380f604d5880fca686bffab69ca97bfba015a102a7e23dce0e
+ S = 6258488c770e0f5ad7b9da8bade5023fc0d17c6ec517bd08d53e6dc01ac5c2b3
+ Result = P
+ """).splitlines()
-def test_raises_unsupported_algorithm_wrong_reason():
- # Check that it fails if the wrong reason code is raised.
- with pytest.raises(AssertionError):
- with raises_unsupported_algorithm(None):
- raise UnsupportedAlgorithm("An error.",
- _Reasons.BACKEND_MISSING_INTERFACE)
+ expected = [
+ {
+ 'p': int('dc5bf3a88b2d99e4c95cdd7a0501cc38630d425cf5c390af3429cff1'
+ 'f35147b795caea923f0d3577158f8a0c89dabd1962c2c453306b5d70'
+ 'cacfb01430aceb54e5a5fa6f9340d3bd2da612fceeb76b0ec1ebfae6'
+ '35a56ab141b108e00dc76eefe2edd0c514c21c457457c39065dba9d0'
+ 'ecb7569c247172d8438ad2827b60435b', 16),
+ 'q': int('e956602b83d195dbe945b3ac702fc61f81571f1d', 16),
+ 'g': int('d7eb9ca20a3c7a079606bafc4c9261ccaba303a5dc9fe9953f197dfe'
+ '548c234895baa77f441ee6a2d97b909cbbd26ff7b869d24cae51b5c6'
+ 'edb127a4b5d75cd8b46608bfa148249dffdb59807c5d7dde3fe3080c'
+ 'a3a2d28312142becb1fa8e24003e21c7287108174b95d5bc711e1c8d'
+ '9b1076784f5dc37a964a5e51390da713', 16),
+ 'digest_algorithm': 'SHA-1',
+ 'msg': binascii.unhexlify(
+ b'0fe1bfee500bdb76026099b1d37553f6bdfe48c82094ef98cb309dd77733'
+ b'0bedfaa2f94c823ef74ef4074b50d8706041ac0e371c7c22dcf70263b8d6'
+ b'0e17a86c7c379cfda8f22469e0df9d49d59439fc99891873628fff25dda5'
+ b'fac5ac794e948babdde968143ba05f1128f34fdad5875edc4cd71c6c24ba'
+ b'2060ffbd439ce2b3'),
+ 'x': int('1d93010c29ecfc432188942f46f19f44f0e1bb5d', 16),
+ 'y': int('6240ea0647117c38fe705106d56db578f3e10130928452d4f3587881'
+ 'b8a2bc6873a8befc3237f20914e2a91c7f07a928ee22adeed23d74ab'
+ '7f82ea11f70497e578f7a9b4cbd6f10226222b0b4da2ea1e49813d6b'
+ 'b9882fbf675c0846bb80cc891857b89b0ef1beb6cce3378a9aab5d66'
+ 'ad4cb9277cf447dfe1e64434749432fb', 16),
+ 'r': int('b5af307867fb8b54390013cc67020ddf1f2c0b81', 16),
+ 's': int('620d3b22ab5031440c3e35eab6f481298f9e9f08', 16),
+ 'result': 'P'},
+ {
+ 'p': int('dc5bf3a88b2d99e4c95cdd7a0501cc38630d425cf5c390af3429cff1'
+ 'f35147b795caea923f0d3577158f8a0c89dabd1962c2c453306b5d70'
+ 'cacfb01430aceb54e5a5fa6f9340d3bd2da612fceeb76b0ec1ebfae6'
+ '35a56ab141b108e00dc76eefe2edd0c514c21c457457c39065dba9d0'
+ 'ecb7569c247172d8438ad2827b60435b', 16),
+ 'q': int('e956602b83d195dbe945b3ac702fc61f81571f1d', 16),
+ 'g': int('d7eb9ca20a3c7a079606bafc4c9261ccaba303a5dc9fe9953f197dfe'
+ '548c234895baa77f441ee6a2d97b909cbbd26ff7b869d24cae51b5c6'
+ 'edb127a4b5d75cd8b46608bfa148249dffdb59807c5d7dde3fe3080c'
+ 'a3a2d28312142becb1fa8e24003e21c7287108174b95d5bc711e1c8d'
+ '9b1076784f5dc37a964a5e51390da713', 16),
+ 'digest_algorithm': 'SHA-1',
+ 'msg': binascii.unhexlify(
+ b'97d50898025d2f9ba633866e968ca75e969d394edba6517204cb3dd537c2'
+ b'ba38778a2dc9dbc685a915e5676fcd43bc3726bc59ce3d7a9fae35565082'
+ b'a069c139fa37c90d922b126933db3fa6c5ef6b1edf00d174a51887bb7690'
+ b'9c6a94fe994ecc7b7fc8f26113b17f30f9d01693df99a125b4f17e184331'
+ b'c6b6e8ca00f54f3a'),
+ 'x': int('350e13534692a7e0c4b7d58836046c436fbb2322', 16),
+ 'y': int('69974de550fe6bd3099150faea1623ad3fb6d9bf23a07215093f3197'
+ '25ad0877accffd291b6da18eb0cbe51676ceb0977504eb97c27c0b19'
+ '1883f72fb2710a9fbd8bcf13be0bf854410b32f42b33ec89d3cc1cf8'
+ '92bcd536c4195ca9ada302ad600c3408739935d77dc247529ca47f84'
+ '4cc86f5016a2fe962c6e20ca7c4d4e8f', 16),
+ 'r': int('b5d05faa7005764e8dae0327c5bf1972ff7681b9', 16),
+ 's': int('18ea15bd9f00475b25204cbc23f8c23e01588015', 16),
+ 'result': 'F'},
+ {
+ 'p': int('e7c1c86125db9ef417da1ced7ea0861bdad629216a3f3c745df42a4'
+ '6b989e59f4d98425ee3c932fa3c2b6f637bdb6545bec526faa037e1'
+ '1f5578a4363b9fca5eba60d6a9cbaa2befd04141d989c7356285132'
+ 'c2eaf74f2d868521cdc0a17ae9a2546ef863027d3f8cc7949631fd0'
+ 'e2971417a912c8b8c5c989730db6ea6e8baee0e667850429038093c'
+ '851ccb6fb173bb081e0efe0bd7450e0946888f89f75e443ab93ef2d'
+ 'a293a01622cf43c6dd79625d41ba8f9ef7e3086ab39134283d8e96c'
+ '89249488120fd061e4a87d34af41069c0b4fd3934c31b589cbe85b6'
+ '8b912718d5dab859fda7082511fad1d152044905005546e19b14aa9'
+ '6585a55269bf2b831', 16),
+ 'q': int('8e056ec9d4b7acb580087a6ed9ba3478711bb025d5b8d9c731ef9b3'
+ '8bd43db2f', 16),
+ 'g': int('dc2bfb9776786ad310c8b0cdcbba3062402613c67e6959a8d8d1b05'
+ 'aab636528b7b1fe9cd33765f853d6dbe13d09f2681f8c7b1ed7886a'
+ 'aed70c7bd76dbe858ffb8bd86235ddf759244678f428c6519af593d'
+ 'c94eeadbd9852ba2b3d61664e8d58c29d2039af3c3d6d16f90988f6'
+ 'a8c824569f3d48050e30896a9e17cd0232ef01ab8790008f6973b84'
+ 'c763a72f4ae8b485abfb7e8efeb86808fa2b281d3e5d65d28f5992a'
+ '34c077c5aa8026cb2fbc34a45f7e9bd216b10e6f12ecb172e9a6eb8'
+ 'f2e91316905b6add1fd22e83bc2f089f1d5e6a6e6707c18ff55ddcb'
+ '7954e8bceaf0efc4e8314910c03b0e51175f344faafee476a373ac9'
+ '5743cec712b72cf2e', 16),
+ 'digest_algorithm': 'SHA-384',
+ 'msg': binascii.unhexlify(
+ b'6cd6ccfd66bcd832189c5f0c77994210e3bf2c43416f0fe77c4e92f31c5'
+ b'369538dc2c003f146c5ac79df43194ccf3c44d470d9f1083bd15b99b5bc'
+ b'f88c32d8a9021f09ea2288d7b3bf345a12aef3949c1e121b9fb371a67c2'
+ b'd1377364206ac839dd78483561426bda0303f285aa12e9c45d3cdfc6bea'
+ b'e3549703b187deeb3296'),
+ 'x': int('56c897b5938ad5b3d437d7e4826da586a6b3be15e893fa1aaa946f2'
+ '0a028b6b3', 16),
+ 'y': int('38ad44489e1a5778b9689f4dcf40e2acf23840fb954e987d6e8cb62'
+ '9106328ac64e1f3c3eba48b21176ad4afe3b733bead382ee1597e1b'
+ '83e4b43424f2daaba04e5bd79e1436693ac2bddb79a298f026e57e2'
+ '00a252efd1e848a4a2e90be6e78f5242b468b9c0c6d2615047a5a40'
+ 'b9ae7e57a519114db55bf3bed65e580f894b094630ca9c217f6accd'
+ '091e72d2f22da620044ff372d7273f9445017fad492959e59600b74'
+ '94dbe766a03e40125d4e6747c76f68a5b0cdc0e7d7cee12d08c6fb7'
+ 'd0fb049e420a33405075ed4463296345ca695fb7feab7c1b5333ae5'
+ '19fcd4bb6a043f4555378969114743d4face96cad31c0e0089da4e3'
+ 'f61b6d7dabc088ab7', 16),
+ 'r': int('3b85b17be240ed658beb3652c9d93e8e9eea160d35ee24596143058'
+ '02963374e', 16),
+ 's': int('726800a5174a53b56dce86064109c0273cd11fcfa3c92c5cd6aa910'
+ '260c0e3c7', 16),
+ 'result': 'F'},
+ {
+ 'p': int('e7c1c86125db9ef417da1ced7ea0861bdad629216a3f3c745df42a4'
+ '6b989e59f4d98425ee3c932fa3c2b6f637bdb6545bec526faa037e1'
+ '1f5578a4363b9fca5eba60d6a9cbaa2befd04141d989c7356285132'
+ 'c2eaf74f2d868521cdc0a17ae9a2546ef863027d3f8cc7949631fd0'
+ 'e2971417a912c8b8c5c989730db6ea6e8baee0e667850429038093c'
+ '851ccb6fb173bb081e0efe0bd7450e0946888f89f75e443ab93ef2d'
+ 'a293a01622cf43c6dd79625d41ba8f9ef7e3086ab39134283d8e96c'
+ '89249488120fd061e4a87d34af41069c0b4fd3934c31b589cbe85b6'
+ '8b912718d5dab859fda7082511fad1d152044905005546e19b14aa9'
+ '6585a55269bf2b831', 16),
+ 'q': int('8e056ec9d4b7acb580087a6ed9ba3478711bb025d5b8d9c731ef9b3'
+ '8bd43db2f', 16),
+ 'g': int('dc2bfb9776786ad310c8b0cdcbba3062402613c67e6959a8d8d1b05'
+ 'aab636528b7b1fe9cd33765f853d6dbe13d09f2681f8c7b1ed7886a'
+ 'aed70c7bd76dbe858ffb8bd86235ddf759244678f428c6519af593d'
+ 'c94eeadbd9852ba2b3d61664e8d58c29d2039af3c3d6d16f90988f6'
+ 'a8c824569f3d48050e30896a9e17cd0232ef01ab8790008f6973b84'
+ 'c763a72f4ae8b485abfb7e8efeb86808fa2b281d3e5d65d28f5992a'
+ '34c077c5aa8026cb2fbc34a45f7e9bd216b10e6f12ecb172e9a6eb8'
+ 'f2e91316905b6add1fd22e83bc2f089f1d5e6a6e6707c18ff55ddcb'
+ '7954e8bceaf0efc4e8314910c03b0e51175f344faafee476a373ac9'
+ '5743cec712b72cf2e', 16),
+ 'digest_algorithm': 'SHA-384',
+ 'msg': binascii.unhexlify(
+ b'3ad6b0884f358dea09c31a9abc40c45a6000611fc2b907b30eac00413fd'
+ b'2819de7015488a411609d46c499b8f7afa1b78b352ac7f8535bd805b8ff'
+ b'2a5eae557098c668f7ccd73af886d6823a6d456c29931ee864ed46d7673'
+ b'82785728c2a83fcff5271007d2a67d06fa205fd7b9d1a42ea5d6dc76e5e'
+ b'18a9eb148cd1e8b262ae'),
+ 'x': int('2faf566a9f057960f1b50c69508f483d9966d6e35743591f3a677a9'
+ 'dc40e1555', 16),
+ 'y': int('926425d617babe87c442b03903e32ba5bbf0cd9d602b59c4df791a4d'
+ '64a6d4333ca0c0d370552539197d327dcd1bbf8c454f24b03fc7805f'
+ '862db34c7b066ddfddbb11dbd010b27123062d028fe041cb56a2e774'
+ '88348ae0ab6705d87aac4d4e9e6600e9e706326d9979982cffa839be'
+ 'b9eacc3963bcca455a507e80c1c37ad4e765b2c9c0477a075e9bc584'
+ 'feacdf3a35a9391d4711f14e197c54022282bfed9a191213d64127f1'
+ '7a9c5affec26e0c71f15d3a5b16098fec118c45bf8bb2f3b1560df09'
+ '49254c1c0aeb0a16d5a95a40fab8521fbe8ea77c51169b587cc3360e'
+ '5733e6a23b9fded8c40724ea1f9e93614b3a6c9b4f8dbbe915b79449'
+ '7227ba62', 16),
+ 'r': int('343ea0a9e66277380f604d5880fca686bffab69ca97bfba015a102a'
+ '7e23dce0e', 16),
+ 's': int('6258488c770e0f5ad7b9da8bade5023fc0d17c6ec517bd08d53e6dc'
+ '01ac5c2b3', 16),
+ 'result': 'P'}
+ ]
+ assert expected == load_fips_dsa_sig_vectors(vector_data)
-def test_raises_unsupported_no_exc():
- # Check that it fails if no exception is raised.
- with pytest.raises(pytest.fail.Exception):
- with raises_unsupported_algorithm(
- _Reasons.BACKEND_MISSING_INTERFACE
- ):
- pass
+def test_load_fips_dsa_sig_gen_vectors():
+ vector_data = textwrap.dedent("""
+ # CAVS 11.2
+ # "SigGen" information for "dsa2_values"
+ # Mod sizes selected: SHA-1 L=1024, N=160, SHA-256 L=2048, N=256
+
+ [mod = L=1024, N=160, SHA-1]
+
+ P = a8f9cd201e5e35d892f85f80e4db2599a5676a3b1d4f190330ed3256b26d0e80a0e49\
+a8fffaaad2a24f472d2573241d4d6d6c7480c80b4c67bb4479c15ada7ea8424d2502fa01472e7\
+60241713dab025ae1b02e1703a1435f62ddf4ee4c1b664066eb22f2e3bf28bb70a2a76e4fd5eb\
+e2d1229681b5b06439ac9c7e9d8bde283
+ Q = f85f0f83ac4df7ea0cdf8f469bfeeaea14156495
+ G = 2b3152ff6c62f14622b8f48e59f8af46883b38e79b8c74deeae9df131f8b856e3ad6c\
+8455dab87cc0da8ac973417ce4f7878557d6cdf40b35b4a0ca3eb310c6a95d68ce284ad4e25ea\
+28591611ee08b8444bd64b25f3f7c572410ddfb39cc728b9c936f85f419129869929cdb909a6a\
+3a99bbe089216368171bd0ba81de4fe33
+
+ Msg = 3b46736d559bd4e0c2c1b2553a33ad3c6cf23cac998d3d0c0e8fa4b19bca06f2f38\
+6db2dcff9dca4f40ad8f561ffc308b46c5f31a7735b5fa7e0f9e6cb512e63d7eea05538d66a75\
+cd0d4234b5ccf6c1715ccaaf9cdc0a2228135f716ee9bdee7fc13ec27a03a6d11c5c5b3685f51\
+900b1337153bc6c4e8f52920c33fa37f4e7
+ Y = 313fd9ebca91574e1c2eebe1517c57e0c21b0209872140c5328761bbb2450b33f1b18\
+b409ce9ab7c4cd8fda3391e8e34868357c199e16a6b2eba06d6749def791d79e95d3a4d09b24c\
+392ad89dbf100995ae19c01062056bb14bce005e8731efde175f95b975089bdcdaea562b32786\
+d96f5a31aedf75364008ad4fffebb970b
+ R = 50ed0e810e3f1c7cb6ac62332058448bd8b284c0
+ S = c6aded17216b46b7e4b6f2a97c1ad7cc3da83fde
+
+ Msg = d2bcb53b044b3e2e4b61ba2f91c0995fb83a6a97525e66441a3b489d9594238bc74\
+0bdeea0f718a769c977e2de003877b5d7dc25b182ae533db33e78f2c3ff0645f2137abc137d4e\
+7d93ccf24f60b18a820bc07c7b4b5fe08b4f9e7d21b256c18f3b9d49acc4f93e2ce6f3754c780\
+7757d2e1176042612cb32fc3f4f70700e25
+ Y = 29bdd759aaa62d4bf16b4861c81cf42eac2e1637b9ecba512bdbc13ac12a80ae8de25\
+26b899ae5e4a231aef884197c944c732693a634d7659abc6975a773f8d3cd5a361fe2492386a3\
+c09aaef12e4a7e73ad7dfc3637f7b093f2c40d6223a195c136adf2ea3fbf8704a675aa7817aa7\
+ec7f9adfb2854d4e05c3ce7f76560313b
+ R = a26c00b5750a2d27fe7435b93476b35438b4d8ab
+ S = 61c9bfcb2938755afa7dad1d1e07c6288617bf70
+
+ [mod = L=2048, N=256, SHA-256]
+
+ P = a8adb6c0b4cf9588012e5deff1a871d383e0e2a85b5e8e03d814fe13a059705e66323\
+0a377bf7323a8fa117100200bfd5adf857393b0bbd67906c081e585410e38480ead51684dac3a\
+38f7b64c9eb109f19739a4517cd7d5d6291e8af20a3fbf17336c7bf80ee718ee087e322ee4104\
+7dabefbcc34d10b66b644ddb3160a28c0639563d71993a26543eadb7718f317bf5d9577a61565\
+61b082a10029cd44012b18de6844509fe058ba87980792285f2750969fe89c2cd6498db354563\
+8d5379d125dccf64e06c1af33a6190841d223da1513333a7c9d78462abaab31b9f96d5f34445c\
+eb6309f2f6d2c8dde06441e87980d303ef9a1ff007e8be2f0be06cc15f
+ Q = e71f8567447f42e75f5ef85ca20fe557ab0343d37ed09edc3f6e68604d6b9dfb
+ G = 5ba24de9607b8998e66ce6c4f812a314c6935842f7ab54cd82b19fa104abfb5d84579\
+a623b2574b37d22ccae9b3e415e48f5c0f9bcbdff8071d63b9bb956e547af3a8df99e5d306197\
+9652ff96b765cb3ee493643544c75dbe5bb39834531952a0fb4b0378b3fcbb4c8b5800a533039\
+2a2a04e700bb6ed7e0b85795ea38b1b962741b3f33b9dde2f4ec1354f09e2eb78e95f037a5804\
+b6171659f88715ce1a9b0cc90c27f35ef2f10ff0c7c7a2bb0154d9b8ebe76a3d764aa879af372\
+f4240de8347937e5a90cec9f41ff2f26b8da9a94a225d1a913717d73f10397d2183f1ba3b7b45\
+a68f1ff1893caf69a827802f7b6a48d51da6fbefb64fd9a6c5b75c4561
+
+ Msg = 4e3a28bcf90d1d2e75f075d9fbe55b36c5529b17bc3a9ccaba6935c9e20548255b3\
+dfae0f91db030c12f2c344b3a29c4151c5b209f5e319fdf1c23b190f64f1fe5b330cb7c8fa952\
+f9d90f13aff1cb11d63181da9efc6f7e15bfed4862d1a62c7dcf3ba8bf1ff304b102b1ec3f149\
+7dddf09712cf323f5610a9d10c3d9132659
+ Y = 5a55dceddd1134ee5f11ed85deb4d634a3643f5f36dc3a70689256469a0b651ad2288\
+0f14ab85719434f9c0e407e60ea420e2a0cd29422c4899c416359dbb1e592456f2b3cce233259\
+c117542fd05f31ea25b015d9121c890b90e0bad033be1368d229985aac7226d1c8c2eab325ef3\
+b2cd59d3b9f7de7dbc94af1a9339eb430ca36c26c46ecfa6c5481711496f624e188ad7540ef5d\
+f26f8efacb820bd17a1f618acb50c9bc197d4cb7ccac45d824a3bf795c234b556b06aeb929173\
+453252084003f69fe98045fe74002ba658f93475622f76791d9b2623d1b5fff2cc16844746efd\
+2d30a6a8134bfc4c8cc80a46107901fb973c28fc553130f3286c1489da
+ R = 633055e055f237c38999d81c397848c38cce80a55b649d9e7905c298e2a51447
+ S = 2bbf68317660ec1e4b154915027b0bc00ee19cfc0bf75d01930504f2ce10a8b0
+
+ Msg = a733b3f588d5ac9b9d4fe2f804df8c256403a9f8eef6f191fc48e1267fb5b4d546b\
+a11e77b667844e489bf0d5f72990aeb061d01ccd7949a23def74a803b7d92d51abfadeb4885ff\
+d8ffd58ab87548a15c087a39b8993b2fa64c9d31a594eeb7512da16955834336a234435c5a9d0\
+dd9b15a94e116154dea63fdc8dd7a512181
+ Y = 356ed47537fbf02cb30a8cee0537f300dff1d0c467399ce70b87a8758d5ec9dd25624\
+6fccaeb9dfe109f2a984f2ddaa87aad54ce0d31f907e504521baf4207d7073b0a4a9fc67d8ddd\
+a99f87aed6e0367cec27f9c608af743bf1ee6e11d55a182d43b024ace534029b866f6422828bb\
+81a39aae9601ee81c7f81dd358e69f4e2edfa4654d8a65bc64311dc86aac4abc1fc7a3f651596\
+61a0d8e288eb8d665cb0adf5ac3d6ba8e9453facf7542393ae24fd50451d3828086558f7ec528\
+e284935a53f67a1aa8e25d8ad5c4ad55d83aef883a4d9eeb6297e6a53f65049ba9e2c6b7953a7\
+60bc1dc46f78ceaaa2c02f5375dd82e708744aa40b15799eb81d7e5b1a
+ R = bcd490568c0a89ba311bef88ea4f4b03d273e793722722327095a378dd6f3522
+ S = 74498fc43091fcdd2d1ef0775f8286945a01cd72b805256b0451f9cbd943cf82
+ """).splitlines()
-def test_raises_unsupported_algorithm():
- # Check that it doesnt assert if the right things are raised.
- with raises_unsupported_algorithm(
- _Reasons.BACKEND_MISSING_INTERFACE
- ) as exc_info:
- raise UnsupportedAlgorithm("An error.",
- _Reasons.BACKEND_MISSING_INTERFACE)
- assert exc_info.type is UnsupportedAlgorithm
+ expected = [
+ {
+ 'p': int('a8f9cd201e5e35d892f85f80e4db2599a5676a3b1d4f190330ed325'
+ '6b26d0e80a0e49a8fffaaad2a24f472d2573241d4d6d6c7480c80b4'
+ 'c67bb4479c15ada7ea8424d2502fa01472e760241713dab025ae1b0'
+ '2e1703a1435f62ddf4ee4c1b664066eb22f2e3bf28bb70a2a76e4fd'
+ '5ebe2d1229681b5b06439ac9c7e9d8bde283', 16),
+ 'q': int('f85f0f83ac4df7ea0cdf8f469bfeeaea14156495', 16),
+ 'g': int('2b3152ff6c62f14622b8f48e59f8af46883b38e79b8c74deeae9df1'
+ '31f8b856e3ad6c8455dab87cc0da8ac973417ce4f7878557d6cdf40'
+ 'b35b4a0ca3eb310c6a95d68ce284ad4e25ea28591611ee08b8444bd'
+ '64b25f3f7c572410ddfb39cc728b9c936f85f419129869929cdb909'
+ 'a6a3a99bbe089216368171bd0ba81de4fe33', 16),
+ 'digest_algorithm': 'SHA-1',
+ 'msg': binascii.unhexlify(
+ b'3b46736d559bd4e0c2c1b2553a33ad3c6cf23cac998d3d0c0e8fa4b19bc'
+ b'a06f2f386db2dcff9dca4f40ad8f561ffc308b46c5f31a7735b5fa7e0f9'
+ b'e6cb512e63d7eea05538d66a75cd0d4234b5ccf6c1715ccaaf9cdc0a222'
+ b'8135f716ee9bdee7fc13ec27a03a6d11c5c5b3685f51900b1337153bc6c'
+ b'4e8f52920c33fa37f4e7'),
+ 'y': int('313fd9ebca91574e1c2eebe1517c57e0c21b0209872140c5328761b'
+ 'bb2450b33f1b18b409ce9ab7c4cd8fda3391e8e34868357c199e16a'
+ '6b2eba06d6749def791d79e95d3a4d09b24c392ad89dbf100995ae1'
+ '9c01062056bb14bce005e8731efde175f95b975089bdcdaea562b32'
+ '786d96f5a31aedf75364008ad4fffebb970b', 16),
+ 'r': int('50ed0e810e3f1c7cb6ac62332058448bd8b284c0', 16),
+ 's': int('c6aded17216b46b7e4b6f2a97c1ad7cc3da83fde', 16)},
+ {
+ 'p': int('a8f9cd201e5e35d892f85f80e4db2599a5676a3b1d4f190330ed325'
+ '6b26d0e80a0e49a8fffaaad2a24f472d2573241d4d6d6c7480c80b4'
+ 'c67bb4479c15ada7ea8424d2502fa01472e760241713dab025ae1b0'
+ '2e1703a1435f62ddf4ee4c1b664066eb22f2e3bf28bb70a2a76e4fd'
+ '5ebe2d1229681b5b06439ac9c7e9d8bde283', 16),
+ 'q': int('f85f0f83ac4df7ea0cdf8f469bfeeaea14156495', 16),
+ 'g': int('2b3152ff6c62f14622b8f48e59f8af46883b38e79b8c74deeae9df1'
+ '31f8b856e3ad6c8455dab87cc0da8ac973417ce4f7878557d6cdf40'
+ 'b35b4a0ca3eb310c6a95d68ce284ad4e25ea28591611ee08b8444bd'
+ '64b25f3f7c572410ddfb39cc728b9c936f85f419129869929cdb909'
+ 'a6a3a99bbe089216368171bd0ba81de4fe33', 16),
+ 'digest_algorithm': 'SHA-1',
+ 'msg': binascii.unhexlify(
+ b'd2bcb53b044b3e2e4b61ba2f91c0995fb83a6a97525e66441a3b489d959'
+ b'4238bc740bdeea0f718a769c977e2de003877b5d7dc25b182ae533db33e'
+ b'78f2c3ff0645f2137abc137d4e7d93ccf24f60b18a820bc07c7b4b5fe08'
+ b'b4f9e7d21b256c18f3b9d49acc4f93e2ce6f3754c7807757d2e11760426'
+ b'12cb32fc3f4f70700e25'),
+ 'y': int('29bdd759aaa62d4bf16b4861c81cf42eac2e1637b9ecba512bdbc13'
+ 'ac12a80ae8de2526b899ae5e4a231aef884197c944c732693a634d7'
+ '659abc6975a773f8d3cd5a361fe2492386a3c09aaef12e4a7e73ad7'
+ 'dfc3637f7b093f2c40d6223a195c136adf2ea3fbf8704a675aa7817'
+ 'aa7ec7f9adfb2854d4e05c3ce7f76560313b', 16),
+ 'r': int('a26c00b5750a2d27fe7435b93476b35438b4d8ab', 16),
+ 's': int('61c9bfcb2938755afa7dad1d1e07c6288617bf70', 16)},
+ {
+ 'p': int('a8adb6c0b4cf9588012e5deff1a871d383e0e2a85b5e8e03d814fe1'
+ '3a059705e663230a377bf7323a8fa117100200bfd5adf857393b0bb'
+ 'd67906c081e585410e38480ead51684dac3a38f7b64c9eb109f1973'
+ '9a4517cd7d5d6291e8af20a3fbf17336c7bf80ee718ee087e322ee4'
+ '1047dabefbcc34d10b66b644ddb3160a28c0639563d71993a26543e'
+ 'adb7718f317bf5d9577a6156561b082a10029cd44012b18de684450'
+ '9fe058ba87980792285f2750969fe89c2cd6498db3545638d5379d1'
+ '25dccf64e06c1af33a6190841d223da1513333a7c9d78462abaab31'
+ 'b9f96d5f34445ceb6309f2f6d2c8dde06441e87980d303ef9a1ff00'
+ '7e8be2f0be06cc15f', 16),
+ 'q': int('e71f8567447f42e75f5ef85ca20fe557ab0343d37ed09edc3f6e686'
+ '04d6b9dfb', 16),
+ 'g': int('5ba24de9607b8998e66ce6c4f812a314c6935842f7ab54cd82b19fa'
+ '104abfb5d84579a623b2574b37d22ccae9b3e415e48f5c0f9bcbdff'
+ '8071d63b9bb956e547af3a8df99e5d3061979652ff96b765cb3ee49'
+ '3643544c75dbe5bb39834531952a0fb4b0378b3fcbb4c8b5800a533'
+ '0392a2a04e700bb6ed7e0b85795ea38b1b962741b3f33b9dde2f4ec'
+ '1354f09e2eb78e95f037a5804b6171659f88715ce1a9b0cc90c27f3'
+ '5ef2f10ff0c7c7a2bb0154d9b8ebe76a3d764aa879af372f4240de8'
+ '347937e5a90cec9f41ff2f26b8da9a94a225d1a913717d73f10397d'
+ '2183f1ba3b7b45a68f1ff1893caf69a827802f7b6a48d51da6fbefb'
+ '64fd9a6c5b75c4561', 16),
+ 'digest_algorithm': 'SHA-256',
+ 'msg': binascii.unhexlify(
+ b'4e3a28bcf90d1d2e75f075d9fbe55b36c5529b17bc3a9ccaba6935c9e20'
+ b'548255b3dfae0f91db030c12f2c344b3a29c4151c5b209f5e319fdf1c23'
+ b'b190f64f1fe5b330cb7c8fa952f9d90f13aff1cb11d63181da9efc6f7e1'
+ b'5bfed4862d1a62c7dcf3ba8bf1ff304b102b1ec3f1497dddf09712cf323'
+ b'f5610a9d10c3d9132659'),
+ 'y': int('5a55dceddd1134ee5f11ed85deb4d634a3643f5f36dc3a706892564'
+ '69a0b651ad22880f14ab85719434f9c0e407e60ea420e2a0cd29422'
+ 'c4899c416359dbb1e592456f2b3cce233259c117542fd05f31ea25b'
+ '015d9121c890b90e0bad033be1368d229985aac7226d1c8c2eab325'
+ 'ef3b2cd59d3b9f7de7dbc94af1a9339eb430ca36c26c46ecfa6c548'
+ '1711496f624e188ad7540ef5df26f8efacb820bd17a1f618acb50c9'
+ 'bc197d4cb7ccac45d824a3bf795c234b556b06aeb92917345325208'
+ '4003f69fe98045fe74002ba658f93475622f76791d9b2623d1b5fff'
+ '2cc16844746efd2d30a6a8134bfc4c8cc80a46107901fb973c28fc5'
+ '53130f3286c1489da', 16),
+ 'r': int('633055e055f237c38999d81c397848c38cce80a55b649d9e7905c29'
+ '8e2a51447', 16),
+ 's': int('2bbf68317660ec1e4b154915027b0bc00ee19cfc0bf75d01930504f'
+ '2ce10a8b0', 16)},
+ {
+ 'p': int('a8adb6c0b4cf9588012e5deff1a871d383e0e2a85b5e8e03d814fe1'
+ '3a059705e663230a377bf7323a8fa117100200bfd5adf857393b0bb'
+ 'd67906c081e585410e38480ead51684dac3a38f7b64c9eb109f1973'
+ '9a4517cd7d5d6291e8af20a3fbf17336c7bf80ee718ee087e322ee4'
+ '1047dabefbcc34d10b66b644ddb3160a28c0639563d71993a26543e'
+ 'adb7718f317bf5d9577a6156561b082a10029cd44012b18de684450'
+ '9fe058ba87980792285f2750969fe89c2cd6498db3545638d5379d1'
+ '25dccf64e06c1af33a6190841d223da1513333a7c9d78462abaab31'
+ 'b9f96d5f34445ceb6309f2f6d2c8dde06441e87980d303ef9a1ff00'
+ '7e8be2f0be06cc15f', 16),
+ 'q': int('e71f8567447f42e75f5ef85ca20fe557ab0343d37ed09edc3f6e686'
+ '04d6b9dfb', 16),
+ 'g': int('5ba24de9607b8998e66ce6c4f812a314c6935842f7ab54cd82b19fa'
+ '104abfb5d84579a623b2574b37d22ccae9b3e415e48f5c0f9bcbdff'
+ '8071d63b9bb956e547af3a8df99e5d3061979652ff96b765cb3ee49'
+ '3643544c75dbe5bb39834531952a0fb4b0378b3fcbb4c8b5800a533'
+ '0392a2a04e700bb6ed7e0b85795ea38b1b962741b3f33b9dde2f4ec'
+ '1354f09e2eb78e95f037a5804b6171659f88715ce1a9b0cc90c27f3'
+ '5ef2f10ff0c7c7a2bb0154d9b8ebe76a3d764aa879af372f4240de8'
+ '347937e5a90cec9f41ff2f26b8da9a94a225d1a913717d73f10397d'
+ '2183f1ba3b7b45a68f1ff1893caf69a827802f7b6a48d51da6fbefb'
+ '64fd9a6c5b75c4561', 16),
+ 'digest_algorithm': 'SHA-256',
+ 'msg': binascii.unhexlify(
+ b'a733b3f588d5ac9b9d4fe2f804df8c256403a9f8eef6f191fc48e1267fb'
+ b'5b4d546ba11e77b667844e489bf0d5f72990aeb061d01ccd7949a23def7'
+ b'4a803b7d92d51abfadeb4885ffd8ffd58ab87548a15c087a39b8993b2fa'
+ b'64c9d31a594eeb7512da16955834336a234435c5a9d0dd9b15a94e11615'
+ b'4dea63fdc8dd7a512181'),
+ 'y': int('356ed47537fbf02cb30a8cee0537f300dff1d0c467399ce70b87a87'
+ '58d5ec9dd256246fccaeb9dfe109f2a984f2ddaa87aad54ce0d31f9'
+ '07e504521baf4207d7073b0a4a9fc67d8ddda99f87aed6e0367cec2'
+ '7f9c608af743bf1ee6e11d55a182d43b024ace534029b866f642282'
+ '8bb81a39aae9601ee81c7f81dd358e69f4e2edfa4654d8a65bc6431'
+ '1dc86aac4abc1fc7a3f65159661a0d8e288eb8d665cb0adf5ac3d6b'
+ 'a8e9453facf7542393ae24fd50451d3828086558f7ec528e284935a'
+ '53f67a1aa8e25d8ad5c4ad55d83aef883a4d9eeb6297e6a53f65049'
+ 'ba9e2c6b7953a760bc1dc46f78ceaaa2c02f5375dd82e708744aa40'
+ 'b15799eb81d7e5b1a', 16),
+ 'r': int('bcd490568c0a89ba311bef88ea4f4b03d273e793722722327095a37'
+ '8dd6f3522', 16),
+ 's': int('74498fc43091fcdd2d1ef0775f8286945a01cd72b805256b0451f9c'
+ 'bd943cf82', 16)}
+ ]
+ assert expected == load_fips_dsa_sig_vectors(vector_data)
def test_load_fips_ecdsa_key_pair_vectors():
@@ -2145,3 +2604,44 @@ bdcf3035f6829ede041b745955d219dc5d30ddd8b37f6ba0f6d2857504cdc68a1ed812a10
}
]
assert expected == load_fips_ecdsa_signing_vectors(vector_data)
+
+
+def test_vector_version():
+ assert cryptography.__version__ == cryptography_vectors.__version__
+
+
+def test_raises_unsupported_algorithm_wrong_type():
+ # Check that it raises if the wrong type of exception is raised.
+ class TestException(Exception):
+ pass
+
+ with pytest.raises(TestException):
+ with raises_unsupported_algorithm(None):
+ raise TestException
+
+
+def test_raises_unsupported_algorithm_wrong_reason():
+ # Check that it fails if the wrong reason code is raised.
+ with pytest.raises(AssertionError):
+ with raises_unsupported_algorithm(None):
+ raise UnsupportedAlgorithm("An error.",
+ _Reasons.BACKEND_MISSING_INTERFACE)
+
+
+def test_raises_unsupported_no_exc():
+ # Check that it fails if no exception is raised.
+ with pytest.raises(pytest.fail.Exception):
+ with raises_unsupported_algorithm(
+ _Reasons.BACKEND_MISSING_INTERFACE
+ ):
+ pass
+
+
+def test_raises_unsupported_algorithm():
+ # Check that it doesn't assert if the right things are raised.
+ with raises_unsupported_algorithm(
+ _Reasons.BACKEND_MISSING_INTERFACE
+ ) as exc_info:
+ raise UnsupportedAlgorithm("An error.",
+ _Reasons.BACKEND_MISSING_INTERFACE)
+ assert exc_info.type is UnsupportedAlgorithm
diff --git a/tests/utils.py b/tests/utils.py
index c38ba7ff..60b6f5a2 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -15,8 +15,8 @@ from __future__ import absolute_import, division, print_function
import binascii
import collections
-from contextlib import contextmanager
import re
+from contextlib import contextmanager
import pytest
@@ -431,6 +431,73 @@ def load_fips_dsa_key_pair_vectors(vector_data):
return vectors
+def load_fips_dsa_sig_vectors(vector_data):
+ """
+ Loads data out of the FIPS DSA SigVer vector files.
+ """
+ vectors = []
+ sha_regex = re.compile(
+ r"\[mod = L=...., N=..., SHA-(?P<sha>1|224|256|384|512)\]"
+ )
+ # When reading_key_data is set to True it tells the loader to continue
+ # constructing dictionaries. We set reading_key_data to False during the
+ # blocks of the vectors of N=224 because we don't support it.
+ reading_key_data = True
+
+ for line in vector_data:
+ line = line.strip()
+
+ if not line or line.startswith("#"):
+ continue
+
+ sha_match = sha_regex.match(line)
+ if sha_match:
+ digest_algorithm = "SHA-{0}".format(sha_match.group("sha"))
+
+ if line.startswith("[mod = L=2048, N=224"):
+ reading_key_data = False
+ continue
+ elif line.startswith("[mod = L=2048, N=256"):
+ reading_key_data = True
+ continue
+
+ if not reading_key_data or line.startswith("[mod"):
+ continue
+
+ name, value = [c.strip() for c in line.split("=")]
+
+ if name == "P":
+ vectors.append({'p': int(value, 16),
+ 'digest_algorithm': digest_algorithm})
+ elif name == "Q":
+ vectors[-1]['q'] = int(value, 16)
+ elif name == "G":
+ vectors[-1]['g'] = int(value, 16)
+ elif name == "Msg" and 'msg' not in vectors[-1]:
+ hexmsg = value.strip().encode("ascii")
+ vectors[-1]['msg'] = binascii.unhexlify(hexmsg)
+ elif name == "Msg" and 'msg' in vectors[-1]:
+ hexmsg = value.strip().encode("ascii")
+ vectors.append({'p': vectors[-1]['p'],
+ 'q': vectors[-1]['q'],
+ 'g': vectors[-1]['g'],
+ 'digest_algorithm':
+ vectors[-1]['digest_algorithm'],
+ 'msg': binascii.unhexlify(hexmsg)})
+ elif name == "X":
+ vectors[-1]['x'] = int(value, 16)
+ elif name == "Y":
+ vectors[-1]['y'] = int(value, 16)
+ elif name == "R":
+ vectors[-1]['r'] = int(value, 16)
+ elif name == "S":
+ vectors[-1]['s'] = int(value, 16)
+ elif name == "Result":
+ vectors[-1]['result'] = value.split("(")[0].strip()
+
+ return vectors
+
+
# http://tools.ietf.org/html/rfc4492#appendix-A
_ECDSA_CURVE_NAMES = {
"P-192": "secp192r1",
diff --git a/tox.ini b/tox.ini
index 78b8b4c6..da959955 100644
--- a/tox.ini
+++ b/tox.ini
@@ -17,8 +17,8 @@ commands =
deps =
pyenchant
sphinx
- sphinxcontrib-spelling
sphinx_rtd_theme
+ sphinxcontrib-spelling
basepython = python2.7
commands =
sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html
@@ -42,6 +42,7 @@ commands =
[testenv:pep8]
deps =
flake8
+ flake8-import-order
pep8-naming
commands = flake8 .
@@ -49,9 +50,11 @@ commands = flake8 .
basepython = python3.3
deps =
flake8
+ flake8-import-order
pep8-naming
commands = flake8 .
[flake8]
exclude = .tox,*.egg
-select = E,W,F,N
+select = E,W,F,N,I
+application-import-names = cryptography,cryptography_vectors,tests
diff --git a/vectors/cryptography_vectors/__init__.py b/vectors/cryptography_vectors/__init__.py
index 02d748df..25df6b3a 100644
--- a/vectors/cryptography_vectors/__init__.py
+++ b/vectors/cryptography_vectors/__init__.py
@@ -16,8 +16,8 @@ from __future__ import absolute_import, division, print_function
import os
from cryptography_vectors.__about__ import (
- __title__, __summary__, __uri__, __version__, __author__, __email__,
- __license__, __copyright__
+ __author__, __copyright__, __email__, __license__, __summary__, __title__,
+ __uri__, __version__
)
diff --git a/vectors/setup.py b/vectors/setup.py
index ce01e132..66841def 100644
--- a/vectors/setup.py
+++ b/vectors/setup.py
@@ -15,7 +15,7 @@ from __future__ import absolute_import, division, print_function
import os
-from setuptools import setup, find_packages
+from setuptools import find_packages, setup
base_dir = os.path.dirname(__file__)