aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2013-12-27 08:22:07 -0800
committerAlex Gaynor <alex.gaynor@gmail.com>2013-12-27 08:22:07 -0800
commit4b31af7407ab6221712e8d83cd1bce53bd57aa95 (patch)
tree7b6774bc8559f51b47cb3510c244146ce20d00fb
parent3ac297e4c9b655b3222da1830e9677c9d03a3926 (diff)
parent37c88a0dea800b3028f95bf71a8cd6e344254d4e (diff)
downloadcryptography-4b31af7407ab6221712e8d83cd1bce53bd57aa95.tar.gz
cryptography-4b31af7407ab6221712e8d83cd1bce53bd57aa95.tar.bz2
cryptography-4b31af7407ab6221712e8d83cd1bce53bd57aa95.zip
Merge branch 'master' into fernet
-rw-r--r--cryptography/exceptions.py4
-rw-r--r--cryptography/hazmat/backends/interfaces.py7
-rw-r--r--cryptography/hazmat/backends/openssl/asn1.py6
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py75
-rw-r--r--cryptography/hazmat/backends/openssl/bignum.py2
-rw-r--r--cryptography/hazmat/backends/openssl/bio.py2
-rw-r--r--cryptography/hazmat/backends/openssl/conf.py2
-rw-r--r--cryptography/hazmat/backends/openssl/crypto.py10
-rw-r--r--cryptography/hazmat/backends/openssl/dh.py2
-rw-r--r--cryptography/hazmat/backends/openssl/dsa.py2
-rw-r--r--cryptography/hazmat/backends/openssl/engine.py2
-rw-r--r--cryptography/hazmat/backends/openssl/err.py2
-rw-r--r--cryptography/hazmat/backends/openssl/evp.py27
-rw-r--r--cryptography/hazmat/backends/openssl/hmac.py2
-rw-r--r--cryptography/hazmat/backends/openssl/nid.py2
-rw-r--r--cryptography/hazmat/backends/openssl/opensslv.py3
-rw-r--r--cryptography/hazmat/backends/openssl/pem.py2
-rw-r--r--cryptography/hazmat/backends/openssl/pkcs12.py2
-rw-r--r--cryptography/hazmat/backends/openssl/pkcs7.py2
-rw-r--r--cryptography/hazmat/backends/openssl/rand.py3
-rw-r--r--cryptography/hazmat/backends/openssl/rsa.py2
-rw-r--r--cryptography/hazmat/backends/openssl/ssl.py104
-rw-r--r--cryptography/hazmat/backends/openssl/x509.py8
-rw-r--r--cryptography/hazmat/backends/openssl/x509name.py2
-rw-r--r--cryptography/hazmat/backends/openssl/x509v3.py2
-rw-r--r--cryptography/hazmat/primitives/ciphers/algorithms.py6
-rw-r--r--cryptography/hazmat/primitives/constant_time.py11
-rw-r--r--cryptography/hazmat/primitives/hmac.py11
-rw-r--r--cryptography/hazmat/primitives/interfaces.py36
-rw-r--r--cryptography/hazmat/primitives/padding.py7
-rw-r--r--docs/api-stability.rst51
-rw-r--r--docs/contributing.rst18
-rw-r--r--docs/exceptions.rst6
-rw-r--r--docs/hazmat/backends/index.rst24
-rw-r--r--docs/hazmat/backends/interfaces.rst11
-rw-r--r--docs/hazmat/backends/openssl.rst4
-rw-r--r--docs/hazmat/primitives/cryptographic-hashes.rst3
-rw-r--r--docs/hazmat/primitives/hmac.rst10
-rw-r--r--docs/hazmat/primitives/interfaces.rst11
-rw-r--r--docs/hazmat/primitives/symmetric-encryption.rst13
-rw-r--r--docs/index.rst37
-rw-r--r--pytest.ini4
-rw-r--r--tests/conftest.py16
-rw-r--r--tests/hazmat/backends/test_openssl.py12
-rw-r--r--tests/hazmat/primitives/test_3des.py59
-rw-r--r--tests/hazmat/primitives/test_aes.py39
-rw-r--r--tests/hazmat/primitives/test_arc4.py5
-rw-r--r--tests/hazmat/primitives/test_block.py15
-rw-r--r--tests/hazmat/primitives/test_blowfish.py19
-rw-r--r--tests/hazmat/primitives/test_camellia.py19
-rw-r--r--tests/hazmat/primitives/test_cast5.py7
-rw-r--r--tests/hazmat/primitives/test_hash_vectors.py10
-rw-r--r--tests/hazmat/primitives/test_hashes.py23
-rw-r--r--tests/hazmat/primitives/test_hmac.py42
-rw-r--r--tests/hazmat/primitives/test_hmac_vectors.py23
-rw-r--r--tests/hazmat/primitives/utils.py262
-rw-r--r--tests/test_utils.py21
-rw-r--r--tests/utils.py12
-rw-r--r--tox.ini4
59 files changed, 834 insertions, 294 deletions
diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py
index e9d88199..44363c24 100644
--- a/cryptography/exceptions.py
+++ b/cryptography/exceptions.py
@@ -30,3 +30,7 @@ class NotYetFinalized(Exception):
class InvalidTag(Exception):
pass
+
+
+class InvalidSignature(Exception):
+ pass
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index 912476bb..9a570968 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -60,6 +60,13 @@ class HashBackend(six.with_metaclass(abc.ABCMeta)):
class HMACBackend(six.with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
+ def hmac_supported(self, algorithm):
+ """
+ Return True if the hash algorithm is supported for HMAC by this
+ backend.
+ """
+
+ @abc.abstractmethod
def create_hmac_ctx(self, key, algorithm):
"""
Create a HashContext for calculating a message authentication code.
diff --git a/cryptography/hazmat/backends/openssl/asn1.py b/cryptography/hazmat/backends/openssl/asn1.py
index 719a523c..a186d592 100644
--- a/cryptography/hazmat/backends/openssl/asn1.py
+++ b/cryptography/hazmat/backends/openssl/asn1.py
@@ -41,7 +41,7 @@ typedef ... ASN1_VALUE;
typedef struct {
...;
} ASN1_TIME;
-typedef const ASN1_ITEM ASN1_ITEM_EXP;
+typedef ... ASN1_ITEM_EXP;
typedef ... ASN1_UTCTIME;
@@ -102,7 +102,7 @@ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **, const unsigned char **, long,
MACROS = """
ASN1_TIME *M_ASN1_TIME_dup(void *);
-ASN1_ITEM *ASN1_ITEM_ptr(ASN1_ITEM *);
+ASN1_ITEM_EXP *ASN1_ITEM_ptr(ASN1_ITEM_EXP *);
/* These aren't macros these arguments are all const X on openssl > 1.0.x */
@@ -122,3 +122,5 @@ BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *, BIGNUM *);
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index bd092bec..7b67fb0b 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -56,7 +56,22 @@ _OSX_POST_INCLUDE = """
class Backend(object):
"""
OpenSSL API wrapper.
+
+ Modules listed in the ``_modules`` listed should have the following
+ attributes:
+
+ * ``INCLUDES``: A string containg C includes.
+ * ``TYPES``: A string containing C declarations for types.
+ * ``FUNCTIONS``: A string containing C declarations for functions.
+ * ``MACROS``: A string containing C declarations for any macros.
+ * ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this
+ can be used to do things like test for a define and provide an
+ alternate implementation based on that.
+ * ``CONDITIONAL_NAMES``: A dict mapping strings of condition names from the
+ library to a list of names which will not be present without the
+ condition.
"""
+ _module_prefix = "cryptography.hazmat.backends.openssl."
_modules = [
"asn1",
"bignum",
@@ -102,7 +117,7 @@ class Backend(object):
macros = []
customizations = []
for name in cls._modules:
- module_name = "cryptography.hazmat.backends.openssl." + name
+ module_name = cls._module_prefix + name
__import__(module_name)
module = sys.modules[module_name]
@@ -141,6 +156,14 @@ class Backend(object):
libraries=["crypto", "ssl"],
)
+ for name in cls._modules:
+ module_name = cls._module_prefix + name
+ module = sys.modules[module_name]
+ for condition, names in module.CONDITIONAL_NAMES.items():
+ if not getattr(lib, condition):
+ for name in names:
+ delattr(lib, name)
+
cls.ffi = ffi
cls.lib = lib
cls.lib.OpenSSL_add_all_algorithms()
@@ -161,6 +184,9 @@ class Backend(object):
digest = self.lib.EVP_get_digestbyname(algorithm.name.encode("ascii"))
return digest != self.ffi.NULL
+ def hmac_supported(self, algorithm):
+ return self.hash_supported(algorithm)
+
def create_hash_ctx(self, algorithm):
return _HashContext(self, algorithm)
@@ -276,6 +302,11 @@ class _CipherContext(object):
self._operation = operation
self._tag = None
+ if isinstance(self._cipher, interfaces.BlockCipherAlgorithm):
+ self._block_size = self._cipher.block_size
+ else:
+ self._block_size = 1
+
ctx = self._backend.lib.EVP_CIPHER_CTX_new()
ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_CIPHER_CTX_free)
@@ -283,11 +314,19 @@ class _CipherContext(object):
try:
adapter = registry[type(cipher), type(mode)]
except KeyError:
- raise UnsupportedAlgorithm
+ raise UnsupportedAlgorithm(
+ "cipher {0} in {1} mode is not supported "
+ "by this backend".format(
+ cipher.name, mode.name if mode else mode)
+ )
evp_cipher = adapter(self._backend, cipher, mode)
if evp_cipher == self._backend.ffi.NULL:
- raise UnsupportedAlgorithm
+ raise UnsupportedAlgorithm(
+ "cipher {0} in {1} mode is not supported "
+ "by this backend".format(
+ cipher.name, mode.name if mode else mode)
+ )
if isinstance(mode, interfaces.ModeWithInitializationVector):
iv_nonce = mode.initialization_vector
@@ -309,16 +348,16 @@ class _CipherContext(object):
assert res != 0
if isinstance(mode, GCM):
res = self._backend.lib.EVP_CIPHER_CTX_ctrl(
- ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_IVLEN,
+ ctx, self._backend.lib.EVP_CTRL_GCM_SET_IVLEN,
len(iv_nonce), self._backend.ffi.NULL
)
assert res != 0
if operation == self._DECRYPT:
- if not mode.tag:
- raise ValueError("Authentication tag must be supplied "
- "when decrypting")
+ if not mode.tag or len(mode.tag) < 4:
+ raise ValueError("Authentication tag must be provided and "
+ "be 4 bytes or longer when decrypting")
res = self._backend.lib.EVP_CIPHER_CTX_ctrl(
- ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_TAG,
+ ctx, self._backend.lib.EVP_CTRL_GCM_SET_TAG,
len(mode.tag), mode.tag
)
assert res != 0
@@ -341,7 +380,7 @@ class _CipherContext(object):
def update(self, data):
buf = self._backend.ffi.new("unsigned char[]",
- len(data) + self._cipher.block_size - 1)
+ len(data) + self._block_size - 1)
outlen = self._backend.ffi.new("int *")
res = self._backend.lib.EVP_CipherUpdate(self._ctx, buf, outlen, data,
len(data))
@@ -349,7 +388,7 @@ class _CipherContext(object):
return self._backend.ffi.buffer(buf)[:outlen[0]]
def finalize(self):
- buf = self._backend.ffi.new("unsigned char[]", self._cipher.block_size)
+ buf = self._backend.ffi.new("unsigned char[]", self._block_size)
outlen = self._backend.ffi.new("int *")
res = self._backend.lib.EVP_CipherFinal_ex(self._ctx, buf, outlen)
if res == 0:
@@ -357,10 +396,10 @@ class _CipherContext(object):
if (isinstance(self._mode, GCM) and
self._operation == self._ENCRYPT):
- block_byte_size = self._cipher.block_size // 8
+ block_byte_size = self._block_size // 8
tag_buf = self._backend.ffi.new("unsigned char[]", block_byte_size)
res = self._backend.lib.EVP_CIPHER_CTX_ctrl(
- self._ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_GET_TAG,
+ self._ctx, self._backend.lib.EVP_CTRL_GCM_GET_TAG,
block_byte_size, tag_buf
)
assert res != 0
@@ -395,7 +434,11 @@ class _HashContext(object):
self._backend.lib.EVP_MD_CTX_destroy)
evp_md = self._backend.lib.EVP_get_digestbyname(
algorithm.name.encode("ascii"))
- assert evp_md != self._backend.ffi.NULL
+ if evp_md == self._backend.ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported hash on this backend".format(
+ algorithm.name)
+ )
res = self._backend.lib.EVP_DigestInit_ex(ctx, evp_md,
self._backend.ffi.NULL)
assert res != 0
@@ -437,7 +480,11 @@ class _HMACContext(object):
ctx = self._backend.ffi.gc(ctx, self._backend.lib.HMAC_CTX_cleanup)
evp_md = self._backend.lib.EVP_get_digestbyname(
algorithm.name.encode('ascii'))
- assert evp_md != self._backend.ffi.NULL
+ if evp_md == self._backend.ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported hash on this backend".format(
+ algorithm.name)
+ )
res = self._backend.lib.Cryptography_HMAC_Init_ex(
ctx, key, len(key), evp_md, self._backend.ffi.NULL
)
diff --git a/cryptography/hazmat/backends/openssl/bignum.py b/cryptography/hazmat/backends/openssl/bignum.py
index 1b0fe5ab..68d0c3a2 100644
--- a/cryptography/hazmat/backends/openssl/bignum.py
+++ b/cryptography/hazmat/backends/openssl/bignum.py
@@ -38,3 +38,5 @@ MACROS = """
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/bio.py b/cryptography/hazmat/backends/openssl/bio.py
index c23dd0d8..d164804f 100644
--- a/cryptography/hazmat/backends/openssl/bio.py
+++ b/cryptography/hazmat/backends/openssl/bio.py
@@ -171,3 +171,5 @@ long BIO_set_buffer_read_data(BIO *, void *, long);
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/conf.py b/cryptography/hazmat/backends/openssl/conf.py
index 4846252c..6d818cf1 100644
--- a/cryptography/hazmat/backends/openssl/conf.py
+++ b/cryptography/hazmat/backends/openssl/conf.py
@@ -27,3 +27,5 @@ MACROS = """
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/crypto.py b/cryptography/hazmat/backends/openssl/crypto.py
index 773d9b14..71d32c52 100644
--- a/cryptography/hazmat/backends/openssl/crypto.py
+++ b/cryptography/hazmat/backends/openssl/crypto.py
@@ -16,6 +16,11 @@ INCLUDES = """
"""
TYPES = """
+static const int SSLEAY_VERSION;
+static const int SSLEAY_CFLAGS;
+static const int SSLEAY_PLATFORM;
+static const int SSLEAY_DIR;
+static const int SSLEAY_BUILT_ON;
"""
FUNCTIONS = """
@@ -24,12 +29,15 @@ int CRYPTO_mem_ctrl(int);
int CRYPTO_is_mem_check_on();
void CRYPTO_mem_leaks(struct bio_st *);
void CRYPTO_cleanup_all_ex_data();
+
+void OPENSSL_free(void *);
"""
MACROS = """
void CRYPTO_add(int *, int, int);
void CRYPTO_malloc_init();
void CRYPTO_malloc_debug_init();
+
#define CRYPTO_MEM_CHECK_ON ...
#define CRYPTO_MEM_CHECK_OFF ...
#define CRYPTO_MEM_CHECK_ENABLE ...
@@ -38,3 +46,5 @@ void CRYPTO_malloc_debug_init();
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/dh.py b/cryptography/hazmat/backends/openssl/dh.py
index b8fbf368..56fa8b46 100644
--- a/cryptography/hazmat/backends/openssl/dh.py
+++ b/cryptography/hazmat/backends/openssl/dh.py
@@ -29,3 +29,5 @@ MACROS = """
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/dsa.py b/cryptography/hazmat/backends/openssl/dsa.py
index e6c369a6..3b77d7ae 100644
--- a/cryptography/hazmat/backends/openssl/dsa.py
+++ b/cryptography/hazmat/backends/openssl/dsa.py
@@ -31,3 +31,5 @@ MACROS = """
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/engine.py b/cryptography/hazmat/backends/openssl/engine.py
index 1f377665..cc214f84 100644
--- a/cryptography/hazmat/backends/openssl/engine.py
+++ b/cryptography/hazmat/backends/openssl/engine.py
@@ -63,3 +63,5 @@ MACROS = """
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/err.py b/cryptography/hazmat/backends/openssl/err.py
index f31c2405..2fb8bbe1 100644
--- a/cryptography/hazmat/backends/openssl/err.py
+++ b/cryptography/hazmat/backends/openssl/err.py
@@ -74,3 +74,5 @@ int ERR_FATAL_ERROR(unsigned long);
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/evp.py b/cryptography/hazmat/backends/openssl/evp.py
index 8cb44610..0662b1ef 100644
--- a/cryptography/hazmat/backends/openssl/evp.py
+++ b/cryptography/hazmat/backends/openssl/evp.py
@@ -32,9 +32,11 @@ typedef struct evp_pkey_st {
} EVP_PKEY;
static const int EVP_PKEY_RSA;
static const int EVP_PKEY_DSA;
-static const int Cryptography_EVP_CTRL_GCM_SET_IVLEN;
-static const int Cryptography_EVP_CTRL_GCM_GET_TAG;
-static const int Cryptography_EVP_CTRL_GCM_SET_TAG;
+static const int EVP_CTRL_GCM_SET_IVLEN;
+static const int EVP_CTRL_GCM_GET_TAG;
+static const int EVP_CTRL_GCM_SET_TAG;
+
+static const int Cryptography_HAS_GCM;
"""
FUNCTIONS = """
@@ -101,12 +103,19 @@ int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *);
CUSTOMIZATIONS = """
#ifdef EVP_CTRL_GCM_SET_TAG
-const int Cryptography_EVP_CTRL_GCM_GET_TAG = EVP_CTRL_GCM_GET_TAG;
-const int Cryptography_EVP_CTRL_GCM_SET_TAG = EVP_CTRL_GCM_SET_TAG;
-const int Cryptography_EVP_CTRL_GCM_SET_IVLEN = EVP_CTRL_GCM_SET_IVLEN;
+const long Cryptography_HAS_GCM = 1;
#else
-const int Cryptography_EVP_CTRL_GCM_GET_TAG = -1;
-const int Cryptography_EVP_CTRL_GCM_SET_TAG = -1;
-const int Cryptography_EVP_CTRL_GCM_SET_IVLEN = -1;
+const long Cryptography_HAS_GCM = 0;
+const long EVP_CTRL_GCM_GET_TAG = -1;
+const long EVP_CTRL_GCM_SET_TAG = -1;
+const long EVP_CTRL_GCM_SET_IVLEN = -1;
#endif
"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_GCM": [
+ "EVP_CTRL_GCM_GET_TAG",
+ "EVP_CTRL_GCM_SET_TAG",
+ "EVP_CTRL_GCM_SET_IVLEN",
+ ]
+}
diff --git a/cryptography/hazmat/backends/openssl/hmac.py b/cryptography/hazmat/backends/openssl/hmac.py
index 10e67141..5f9e0945 100644
--- a/cryptography/hazmat/backends/openssl/hmac.py
+++ b/cryptography/hazmat/backends/openssl/hmac.py
@@ -88,3 +88,5 @@ int Cryptography_HMAC_CTX_copy(HMAC_CTX *dst_ctx, HMAC_CTX *src_ctx) {
#endif
}
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/nid.py b/cryptography/hazmat/backends/openssl/nid.py
index 9816dde4..111f82f9 100644
--- a/cryptography/hazmat/backends/openssl/nid.py
+++ b/cryptography/hazmat/backends/openssl/nid.py
@@ -47,3 +47,5 @@ MACROS = """
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/opensslv.py b/cryptography/hazmat/backends/openssl/opensslv.py
index d463776c..4e110327 100644
--- a/cryptography/hazmat/backends/openssl/opensslv.py
+++ b/cryptography/hazmat/backends/openssl/opensslv.py
@@ -16,6 +16,7 @@ INCLUDES = """
"""
TYPES = """
+static const int OPENSSL_VERSION_NUMBER;
static char *const OPENSSL_VERSION_TEXT;
"""
@@ -27,3 +28,5 @@ MACROS = """
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/pem.py b/cryptography/hazmat/backends/openssl/pem.py
index cef7839f..ee5552c5 100644
--- a/cryptography/hazmat/backends/openssl/pem.py
+++ b/cryptography/hazmat/backends/openssl/pem.py
@@ -55,3 +55,5 @@ MACROS = """
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/pkcs12.py b/cryptography/hazmat/backends/openssl/pkcs12.py
index d91d100f..b3ecd0aa 100644
--- a/cryptography/hazmat/backends/openssl/pkcs12.py
+++ b/cryptography/hazmat/backends/openssl/pkcs12.py
@@ -35,3 +35,5 @@ PKCS12 *PKCS12_create(char *, char *, EVP_PKEY *, X509 *,
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/pkcs7.py b/cryptography/hazmat/backends/openssl/pkcs7.py
index 60ea3c52..43f9540b 100644
--- a/cryptography/hazmat/backends/openssl/pkcs7.py
+++ b/cryptography/hazmat/backends/openssl/pkcs7.py
@@ -35,3 +35,5 @@ int PKCS7_type_is_data(PKCS7 *);
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/rand.py b/cryptography/hazmat/backends/openssl/rand.py
index 848ee05a..5ac36cac 100644
--- a/cryptography/hazmat/backends/openssl/rand.py
+++ b/cryptography/hazmat/backends/openssl/rand.py
@@ -19,6 +19,7 @@ TYPES = """
"""
FUNCTIONS = """
+void ERR_load_RAND_strings();
void RAND_seed(const void *, int);
void RAND_add(const void *, int, double);
int RAND_status();
@@ -38,3 +39,5 @@ MACROS = """
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/rsa.py b/cryptography/hazmat/backends/openssl/rsa.py
index ad0d37b4..e3a24d0f 100644
--- a/cryptography/hazmat/backends/openssl/rsa.py
+++ b/cryptography/hazmat/backends/openssl/rsa.py
@@ -57,3 +57,5 @@ MACROS = """
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/ssl.py b/cryptography/hazmat/backends/openssl/ssl.py
index 04611309..f99c2636 100644
--- a/cryptography/hazmat/backends/openssl/ssl.py
+++ b/cryptography/hazmat/backends/openssl/ssl.py
@@ -16,6 +16,22 @@ INCLUDES = """
"""
TYPES = """
+/* Internally invented symbol to tell us if SSLv2 is supported */
+static const int Cryptography_HAS_SSL2;
+
+/* Internally invented symbol to tell us if SNI is supported */
+static const int Cryptography_HAS_TLSEXT_HOSTNAME;
+
+/* Internally invented symbol to tell us if SSL_MODE_RELEASE_BUFFERS is
+ * supported
+ */
+static const int Cryptography_HAS_RELEASE_BUFFERS;
+
+/* Internally invented symbol to tell us if SSL_OP_NO_COMPRESSION is
+ * supported
+ */
+static const int Cryptography_HAS_OP_NO_COMPRESSION;
+
static const int SSL_FILETYPE_PEM;
static const int SSL_FILETYPE_ASN1;
static const int SSL_ERROR_NONE;
@@ -30,6 +46,7 @@ static const int SSL_RECEIVED_SHUTDOWN;
static const int SSL_OP_NO_SSLv2;
static const int SSL_OP_NO_SSLv3;
static const int SSL_OP_NO_TLSv1;
+static const int SSL_OP_NO_COMPRESSION;
static const int SSL_OP_SINGLE_DH_USE;
static const int SSL_OP_EPHEMERAL_RSA;
static const int SSL_OP_MICROSOFT_SESS_ID_BUG;
@@ -37,7 +54,6 @@ static const int SSL_OP_NETSCAPE_CHALLENGE_BUG;
static const int SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
static const int SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG;
static const int SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER;
-static const int SSL_OP_MSIE_SSLV2_RSA_PADDING;
static const int SSL_OP_SSLEAY_080_CLIENT_DH_BUG;
static const int SSL_OP_TLS_D5_BUG;
static const int SSL_OP_TLS_BLOCK_PADDING_BUG;
@@ -84,6 +100,7 @@ static const int SSL_CB_CONNECT_LOOP;
static const int SSL_CB_CONNECT_EXIT;
static const int SSL_CB_HANDSHAKE_START;
static const int SSL_CB_HANDSHAKE_DONE;
+static const int SSL_MODE_RELEASE_BUFFERS;
static const int SSL_MODE_ENABLE_PARTIAL_WRITE;
static const int SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
static const int SSL_MODE_AUTO_RETRY;
@@ -116,7 +133,6 @@ static const int TLSEXT_NAMETYPE_host_name;
FUNCTIONS = """
void SSL_load_error_strings();
-
int SSL_library_init();
/* SSL */
@@ -126,6 +142,9 @@ int SSL_set_session(SSL *, SSL_SESSION *);
int SSL_get_verify_mode(const SSL *);
void SSL_set_verify_depth(SSL *, int);
int SSL_get_verify_depth(const SSL *);
+int (*SSL_get_verify_callback(const SSL *))(int, X509_STORE_CTX *);
+void SSL_set_info_callback(SSL *ssl, void (*)(const SSL *, int, int));
+void (*SSL_get_info_callback(const SSL *))(const SSL *, int, int);
SSL *SSL_new(SSL_CTX *);
void SSL_free(SSL *);
int SSL_set_fd(SSL *, int);
@@ -147,7 +166,11 @@ const char *SSL_get_cipher_list(const SSL *, int);
void SSL_CTX_free(SSL_CTX *);
long SSL_CTX_set_timeout(SSL_CTX *, long);
int SSL_CTX_set_default_verify_paths(SSL_CTX *);
+void SSL_CTX_set_verify(SSL_CTX *, int, int (*)(int, X509_STORE_CTX *));
void SSL_CTX_set_verify_depth(SSL_CTX *, int);
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *))(int, X509_STORE_CTX *);
+void SSL_CTX_set_info_callback(SSL_CTX *, void (*)(const SSL *, int, int));
+void (*SSL_CTX_get_info_callback(SSL_CTX *))(const SSL *, int, int);
int SSL_CTX_get_verify_mode(const SSL_CTX *);
int SSL_CTX_get_verify_depth(const SSL_CTX *);
int SSL_CTX_set_cipher_list(SSL_CTX *, const char *);
@@ -173,7 +196,7 @@ X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *);
void SSL_SESSION_free(SSL_SESSION *);
"""
-MACROS = MACROS = """
+MACROS = """
long SSL_set_mode(SSL *, long);
long SSL_get_mode(SSL *);
@@ -183,7 +206,7 @@ long SSL_get_options(SSL *);
int SSL_want_read(const SSL *);
int SSL_want_write(const SSL *);
-int SSL_total_renegotiations(const SSL *);
+int SSL_total_renegotiations(SSL *);
long SSL_CTX_set_options(SSL_CTX *, long);
long SSL_CTX_get_options(SSL_CTX *);
@@ -196,6 +219,15 @@ 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 -*/
+/* SSLv2 support is compiled out of some versions of OpenSSL. These will
+ * get special support when we generate the bindings so that if they are
+ * available they will be wrapped, but if they are not they won't cause
+ * problems (like link errors).
+ */
+const SSL_METHOD *SSLv2_method();
+const SSL_METHOD *SSLv2_server_method();
+const SSL_METHOD *SSLv2_client_method();
+
/* methods */
const SSL_METHOD *SSLv3_method();
const SSL_METHOD *SSLv3_server_method();
@@ -210,7 +242,71 @@ const SSL_METHOD *SSLv23_client_method();
/*- These aren't macros these arguments are all const X on openssl > 1.0.x -*/
SSL_CTX *SSL_CTX_new(const SSL_METHOD *);
long SSL_CTX_get_timeout(const SSL_CTX *);
+
+/* SNI APIs were introduced in OpenSSL 1.0.0. To continue to support
+ * earlier versions some special handling of these is necessary.
+ */
+void SSL_set_tlsext_host_name(SSL *, char *);
+void SSL_CTX_set_tlsext_servername_callback(
+ SSL_CTX *,
+ int (*)(const SSL *, int *, void *));
"""
CUSTOMIZATIONS = """
+#ifdef OPENSSL_NO_SSL2
+static const long Cryptography_HAS_SSL2 = 0;
+SSL_METHOD* (*SSLv2_method)() = NULL;
+SSL_METHOD* (*SSLv2_client_method)() = NULL;
+SSL_METHOD* (*SSLv2_server_method)() = NULL;
+#else
+static const long Cryptography_HAS_SSL2 = 1;
+#endif
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+static const long Cryptography_HAS_TLSEXT_HOSTNAME = 1;
+#else
+static const long Cryptography_HAS_TLSEXT_HOSTNAME = 0;
+void (*SSL_set_tlsext_host_name)(SSL *, char *) = NULL;
+const char* (*SSL_get_servername)(const SSL *, const int) = NULL;
+void (*SSL_CTX_set_tlsext_servername_callback)(
+ SSL_CTX *,
+ int (*)(const SSL *, int *, void *)) = NULL;
+#endif
+
+#ifdef SSL_MODE_RELEASE_BUFFERS
+static const long Cryptography_HAS_RELEASE_BUFFERS = 1;
+#else
+static const long Cryptography_HAS_RELEASE_BUFFERS = 0;
+const long SSL_MODE_RELEASE_BUFFERS = 0;
+#endif
+
+#ifdef SSL_OP_NO_COMPRESSION
+static const long Cryptography_HAS_OP_NO_COMPRESSION = 1;
+#else
+static const long Cryptography_HAS_OP_NO_COMPRESSION = 0;
+const long SSL_OP_NO_COMPRESSION = 0;
+#endif
"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_SSL2": [
+ "SSLv2_method",
+ "SSLv2_client_method",
+ "SSLv2_server_method",
+ ],
+
+ "Cryptography_HAS_TLSEXT_HOSTNAME": [
+ "SSL_set_tlsext_host_name",
+ "SSL_get_servername",
+ "SSL_CTX_set_tlsext_servername_callback",
+ ],
+
+ "Cryptography_HAS_RELEASE_BUFFERS": [
+ "SSL_MODE_RELEASE_BUFFERS",
+ ],
+
+ "Cryptography_HAS_OP_NO_COMPRESSION": [
+ "SSL_OP_NO_COMPRESSION",
+ ],
+
+}
diff --git a/cryptography/hazmat/backends/openssl/x509.py b/cryptography/hazmat/backends/openssl/x509.py
index b2ee672e..5cba476e 100644
--- a/cryptography/hazmat/backends/openssl/x509.py
+++ b/cryptography/hazmat/backends/openssl/x509.py
@@ -47,7 +47,7 @@ typedef struct {
} X509_REVOKED;
typedef struct {
- struct x509_revoked_st *revoked;
+ struct stack_st_X509_REVOKED *revoked;
...;
} X509_CRL_INFO;
@@ -178,8 +178,8 @@ int sk_X509_EXTENSION_push(X509_EXTENSIONS *, X509_EXTENSION *);
void sk_X509_EXTENSION_delete(X509_EXTENSIONS *, int);
void sk_X509_EXTENSION_free(X509_EXTENSIONS *);
-int sk_X509_REVOKED_num(struct x509_revoked_st *);
-X509_REVOKED *sk_X509_REVOKED_value(struct x509_revoked_st *, int);
+int sk_X509_REVOKED_num(struct stack_st_X509_REVOKED *);
+X509_REVOKED *sk_X509_REVOKED_value(struct stack_st_X509_REVOKED *, int);
/* These aren't macros these arguments are all const X on openssl > 1.0.x */
int X509_CRL_set_lastUpdate(X509_CRL *, const ASN1_TIME *);
@@ -188,3 +188,5 @@ int X509_CRL_set_nextUpdate(X509_CRL *, const ASN1_TIME *);
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/x509name.py b/cryptography/hazmat/backends/openssl/x509name.py
index 896f0ae4..4be39b53 100644
--- a/cryptography/hazmat/backends/openssl/x509name.py
+++ b/cryptography/hazmat/backends/openssl/x509name.py
@@ -49,3 +49,5 @@ void sk_X509_NAME_free(struct stack_st_X509_NAME *);
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/backends/openssl/x509v3.py b/cryptography/hazmat/backends/openssl/x509v3.py
index bc26236c..6d2d2361 100644
--- a/cryptography/hazmat/backends/openssl/x509v3.py
+++ b/cryptography/hazmat/backends/openssl/x509v3.py
@@ -95,3 +95,5 @@ const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int);
CUSTOMIZATIONS = """
"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/primitives/ciphers/algorithms.py b/cryptography/hazmat/primitives/ciphers/algorithms.py
index a206b273..a5cfce92 100644
--- a/cryptography/hazmat/primitives/ciphers/algorithms.py
+++ b/cryptography/hazmat/primitives/ciphers/algorithms.py
@@ -26,6 +26,7 @@ def _verify_key_size(algorithm, key):
return key
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
@utils.register_interface(interfaces.CipherAlgorithm)
class AES(object):
name = "AES"
@@ -40,6 +41,7 @@ class AES(object):
return len(self.key) * 8
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
@utils.register_interface(interfaces.CipherAlgorithm)
class Camellia(object):
name = "camellia"
@@ -54,6 +56,7 @@ class Camellia(object):
return len(self.key) * 8
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
@utils.register_interface(interfaces.CipherAlgorithm)
class TripleDES(object):
name = "3DES"
@@ -72,6 +75,7 @@ class TripleDES(object):
return len(self.key) * 8
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
@utils.register_interface(interfaces.CipherAlgorithm)
class Blowfish(object):
name = "Blowfish"
@@ -86,6 +90,7 @@ class Blowfish(object):
return len(self.key) * 8
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
@utils.register_interface(interfaces.CipherAlgorithm)
class CAST5(object):
name = "CAST5"
@@ -103,7 +108,6 @@ class CAST5(object):
@utils.register_interface(interfaces.CipherAlgorithm)
class ARC4(object):
name = "RC4"
- block_size = 1
key_sizes = frozenset([40, 56, 64, 80, 128, 192, 256])
def __init__(self, key):
diff --git a/cryptography/hazmat/primitives/constant_time.py b/cryptography/hazmat/primitives/constant_time.py
index a8351504..6502803e 100644
--- a/cryptography/hazmat/primitives/constant_time.py
+++ b/cryptography/hazmat/primitives/constant_time.py
@@ -20,17 +20,16 @@ import six
_ffi = cffi.FFI()
_ffi.cdef("""
-bool Cryptography_constant_time_bytes_eq(uint8_t *, size_t, uint8_t *, size_t);
+uint8_t Cryptography_constant_time_bytes_eq(uint8_t *, size_t, uint8_t *,
+ size_t);
""")
_lib = _ffi.verify("""
-#include <stdbool.h>
-
-bool Cryptography_constant_time_bytes_eq(uint8_t *a, size_t len_a, uint8_t *b,
- size_t len_b) {
+uint8_t Cryptography_constant_time_bytes_eq(uint8_t *a, size_t len_a,
+ uint8_t *b, size_t len_b) {
size_t i = 0;
uint8_t mismatch = 0;
if (len_a != len_b) {
- return false;
+ return 0;
}
for (i = 0; i < len_a; i++) {
mismatch |= a[i] ^ b[i];
diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py
index 618bccc5..76d658aa 100644
--- a/cryptography/hazmat/primitives/hmac.py
+++ b/cryptography/hazmat/primitives/hmac.py
@@ -16,8 +16,8 @@ from __future__ import absolute_import, division, print_function
import six
from cryptography import utils
-from cryptography.exceptions import AlreadyFinalized
-from cryptography.hazmat.primitives import interfaces
+from cryptography.exceptions import AlreadyFinalized, InvalidSignature
+from cryptography.hazmat.primitives import constant_time, interfaces
@utils.register_interface(interfaces.HashContext)
@@ -57,3 +57,10 @@ class HMAC(object):
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.")
diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py
index e3f4f586..e87c9ca9 100644
--- a/cryptography/hazmat/primitives/interfaces.py
+++ b/cryptography/hazmat/primitives/interfaces.py
@@ -22,13 +22,21 @@ class CipherAlgorithm(six.with_metaclass(abc.ABCMeta)):
@abc.abstractproperty
def name(self):
"""
- A string naming this mode. (e.g. AES, Camellia)
+ A string naming this mode (e.g. "AES", "Camellia").
"""
@abc.abstractproperty
def key_size(self):
"""
- The size of the key being used as an integer in bits. (e.g. 128, 256)
+ The size of the key being used as an integer in bits (e.g. 128, 256).
+ """
+
+
+class BlockCipherAlgorithm(six.with_metaclass(abc.ABCMeta)):
+ @abc.abstractproperty
+ def block_size(self):
+ """
+ The size of a block as an integer in bits (e.g. 64, 128).
"""
@@ -36,7 +44,7 @@ class Mode(six.with_metaclass(abc.ABCMeta)):
@abc.abstractproperty
def name(self):
"""
- A string naming this mode. (e.g. ECB, CBC)
+ A string naming this mode (e.g. "ECB", "CBC").
"""
@@ -68,13 +76,14 @@ class CipherContext(six.with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
def update(self, data):
"""
- update takes bytes and return bytes
+ Processes the provided bytes through the cipher and returns the results
+ as bytes.
"""
@abc.abstractmethod
def finalize(self):
"""
- finalize return bytes
+ Returns the results of processing the final block as bytes.
"""
@@ -82,7 +91,7 @@ class AEADCipherContext(six.with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
def authenticate_additional_data(self, data):
"""
- authenticate_additional_data takes bytes and returns nothing.
+ Authenticates the provided bytes.
"""
@@ -90,7 +99,8 @@ class AEADEncryptionContext(six.with_metaclass(abc.ABCMeta)):
@abc.abstractproperty
def tag(self):
"""
- Returns tag bytes after finalizing encryption.
+ Returns tag bytes. This is only available after encryption is
+ finalized.
"""
@@ -98,13 +108,13 @@ class PaddingContext(six.with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
def update(self, data):
"""
- update takes bytes and return bytes
+ Pads the provided bytes and returns any available data as bytes.
"""
@abc.abstractmethod
def finalize(self):
"""
- finalize return bytes
+ Finalize the padding, returns bytes.
"""
@@ -112,7 +122,7 @@ class HashAlgorithm(six.with_metaclass(abc.ABCMeta)):
@abc.abstractproperty
def name(self):
"""
- A string naming this algorithm. (e.g. sha256, md5)
+ A string naming this algorithm (e.g. "sha256", "md5").
"""
@abc.abstractproperty
@@ -138,17 +148,17 @@ class HashContext(six.with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
def update(self, data):
"""
- hash data as bytes
+ Processes the provided bytes through the hash.
"""
@abc.abstractmethod
def finalize(self):
"""
- finalize this copy of the hash and return the digest as bytes.
+ Finalizes the hash context and returns the hash digest as bytes.
"""
@abc.abstractmethod
def copy(self):
"""
- return a HashContext that is a copy of the current context.
+ Return a HashContext that is a copy of the current context.
"""
diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py
index cfa90db9..e517dee0 100644
--- a/cryptography/hazmat/primitives/padding.py
+++ b/cryptography/hazmat/primitives/padding.py
@@ -21,11 +21,9 @@ from cryptography.hazmat.primitives import interfaces
_ffi = cffi.FFI()
_ffi.cdef("""
-bool Cryptography_check_pkcs7_padding(const uint8_t *, uint8_t);
+uint8_t Cryptography_check_pkcs7_padding(const uint8_t *, uint8_t);
""")
_lib = _ffi.verify("""
-#include <stdbool.h>
-
/* Returns the value of the input with the most-significant-bit copied to all
of the bits. */
static uint8_t Cryptography_DUPLICATE_MSB_TO_ALL(uint8_t a) {
@@ -39,7 +37,8 @@ static uint8_t Cryptography_constant_time_lt(uint8_t a, uint8_t b) {
return Cryptography_DUPLICATE_MSB_TO_ALL(a);
}
-bool Cryptography_check_pkcs7_padding(const uint8_t *data, uint8_t block_len) {
+uint8_t Cryptography_check_pkcs7_padding(const uint8_t *data,
+ uint8_t block_len) {
uint8_t i;
uint8_t pad_size = data[block_len - 1];
uint8_t mismatch = 0;
diff --git a/docs/api-stability.rst b/docs/api-stability.rst
new file mode 100644
index 00000000..e87cc140
--- /dev/null
+++ b/docs/api-stability.rst
@@ -0,0 +1,51 @@
+API Stability
+=============
+
+From its first release, ``cryptography`` will have a strong API stability
+policy.
+
+What does this policy cover?
+----------------------------
+
+This policy includes any API or behavior which is documented in this
+documentation.
+
+What does "stable" mean?
+------------------------
+
+* Public APIs will not be removed or renamed without providing a compatibility
+ alias.
+* The behavior of existing APIs will not change.
+
+What doesn't this policy cover?
+-------------------------------
+
+* We may add new features, things like the result of ``dir(obj))`` or the
+ contents of ``obj.__dict__`` may change.
+* Objects are not guaranteed to be pickleable, and pickled objects from one
+ version of ``cryptography`` may not be loadable in future versions.
+* Development versions of ``cryptography``. Before a feature is in a release,
+ it is not covered by this policy and may change.
+
+Security
+~~~~~~~~
+
+One exception to our API stability policy is for security. We will violate this
+policy as necessary in order to resolve a security issue or harden
+``cryptography`` against a possible attack.
+
+Deprecation
+-----------
+
+From time to time we will want to change the behavior of an API or remove it
+entirely. In that case, here's how the process will work:
+
+* In ``cryptography X.Y`` the feature exists.
+* In ``cryptography X.Y+1`` using that feature will emit a
+ ``PendingDeprecationWarning``.
+* In ``cryptography X.Y+2`` using that feature will emit a
+ ``DeprecationWarning``.
+* In ``cryptography X.Y+3`` the feature will be removed or changed.
+
+In short, code which runs without warnings will always continue to work for a
+period of two releases.
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 036043f5..620e1b6a 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -53,11 +53,10 @@ API Considerations
Most projects' APIs are designed with a philosophy of "make easy things easy,
and make hard things possible". One of the perils of writing cryptographic code
-is that code that is secure looks just like code that isn't, and produces
-results that are also difficult to distinguish. As a result ``cryptography``
-has, as a design philosophy: "make it hard to do insecure things". Here are a
-few strategies for API design which should be both followed, and should inspire
-other API choices:
+is that secure code looks just like insecure code, and its results are almost
+always indistinguishable. As a result ``cryptography`` has, as a design
+philosophy: "make it hard to do insecure things". Here are a few strategies for
+API design which should be both followed, and should inspire other API choices:
If it is incorrect to ignore the result of a method, it should raise an
exception, and not return a boolean ``True``/``False`` flag. For example, a
@@ -77,6 +76,10 @@ whether the signature was valid.
if not is_valid:
raise InvalidSignature
+Every recipe should include a version or algorithmic marker of some sort in its
+output in order to allow transparent upgrading of the algorithms in use, as
+the algorithms or parameters needed to achieve a given security margin evolve.
+
APIs at the :doc:`/hazmat/primitives/index` layer should always take an
explicit backend, APIs at the recipes layer should automatically use the
:func:`~cryptography.hazmat.backends.default_backend`, but optionally allow
@@ -133,7 +136,6 @@ Include a space after commas between parameters:
// Bad
long f(int,char *)
-
Documentation
-------------
@@ -163,7 +165,7 @@ as much as possible. To that end:
* When documenting a generic interface, use a strong algorithm in examples.
(e.g. when showing a hashing example, don't use
- :class:`cryptography.hazmat.primitives.hashes.MD5`)
+ :class:`~cryptography.hazmat.primitives.hashes.MD5`)
* When giving prescriptive advice, always provide references and supporting
material.
* When there is real disagreement between cryptographic experts, represent both
@@ -206,7 +208,7 @@ automatically, so all you have to do is:
$ py.test
...
- 4294 passed in 15.24 seconds
+ 62746 passed in 220.43 seconds
This runs the tests with the default Python interpreter.
diff --git a/docs/exceptions.rst b/docs/exceptions.rst
index 087066b8..1fbd3267 100644
--- a/docs/exceptions.rst
+++ b/docs/exceptions.rst
@@ -8,6 +8,12 @@ Exceptions
This is raised when a context is used after being finalized.
+.. class:: InvalidSignature
+
+ This is raised when the verify method of a hash context does not
+ compare equal.
+
+
.. class:: NotYetFinalized
This is raised when the AEAD tag property is accessed on a context
diff --git a/docs/hazmat/backends/index.rst b/docs/hazmat/backends/index.rst
index a89cf0d5..06951281 100644
--- a/docs/hazmat/backends/index.rst
+++ b/docs/hazmat/backends/index.rst
@@ -1,17 +1,10 @@
.. hazmat::
-Bindings
+Backends
========
-.. toctree::
- :maxdepth: 1
-
- openssl
- interfaces
-
-
-Getting a Backend Provider
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+Getting a Backend
+-----------------
.. currentmodule:: cryptography.hazmat.backends
@@ -19,8 +12,7 @@ Getting a Backend Provider
the widest number of supported cryptographic algorithms as well as supporting
platform specific implementations.
-You can get the default backend by calling
-:func:`~default_backend`.
+You can get the default backend by calling :func:`~default_backend`.
The default backend will change over time as we implement new backends and
the libraries we use in those backends changes.
@@ -32,3 +24,11 @@ the libraries we use in those backends changes.
:class:`~interfaces.CipherBackend`, :class:`~interfaces.HashBackend`, and
:class:`~interfaces.HMACBackend`.
+Individual Backends
+-------------------
+
+.. toctree::
+ :maxdepth: 1
+
+ openssl
+ interfaces
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index b524943d..5b6cd64d 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -126,6 +126,17 @@ A specific ``backend`` may provide one or more of these interfaces.
A backend with methods for using cryptographic hash functions as message
authentication codes.
+ .. method:: hmac_supported(algorithm)
+
+ Check if the specified ``algorithm`` is supported by this backend.
+
+ :param algorithm: An instance of a
+ :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
+ provider.
+
+ :returns: ``True`` if the specified ``algorithm`` is supported for HMAC
+ by this backend, otherwise ``False``.
+
.. method:: create_hmac_ctx(algorithm)
Create a
diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst
index 12fbff04..5e51c75e 100644
--- a/docs/hazmat/backends/openssl.rst
+++ b/docs/hazmat/backends/openssl.rst
@@ -1,7 +1,7 @@
.. hazmat::
-OpenSSL
-=======
+OpenSSL Backend
+===============
These are `CFFI`_ bindings to the `OpenSSL`_ C library.
diff --git a/docs/hazmat/primitives/cryptographic-hashes.rst b/docs/hazmat/primitives/cryptographic-hashes.rst
index 90ca198a..38347378 100644
--- a/docs/hazmat/primitives/cryptographic-hashes.rst
+++ b/docs/hazmat/primitives/cryptographic-hashes.rst
@@ -28,6 +28,9 @@ Message Digests
>>> digest.finalize()
'l\xa1=R\xcap\xc8\x83\xe0\xf0\xbb\x10\x1eBZ\x89\xe8bM\xe5\x1d\xb2\xd29%\x93\xafj\x84\x11\x80\x90'
+ If the backend doesn't support the requested ``algorithm`` an
+ :class:`~cryptography.exceptions.UnsupportedAlgorithm` will be raised.
+
Keep in mind that attacks against cryptographic hashes only get stronger
with time, and that often algorithms that were once thought to be strong,
become broken. Because of this it's important to include a plan for
diff --git a/docs/hazmat/primitives/hmac.rst b/docs/hazmat/primitives/hmac.rst
index 0c0d0220..b8f94fd2 100644
--- a/docs/hazmat/primitives/hmac.rst
+++ b/docs/hazmat/primitives/hmac.rst
@@ -34,6 +34,8 @@ message.
>>> h.finalize()
'#F\xdaI\x8b"e\xc4\xf1\xbb\x9a\x8fc\xff\xf5\xdex.\xbc\xcd/+\x8a\x86\x1d\x84\'\xc3\xa6\x1d\xd8J'
+ If the backend doesn't support the requested ``algorithm`` an
+ :class:`~cryptography.exceptions.UnsupportedAlgorithm` will be raised.
:param key: Secret key as ``bytes``.
:param algorithm: A
@@ -69,3 +71,11 @@ message.
:return bytes: The message digest as bytes.
:raises cryptography.exceptions.AlreadyFinalized:
+
+ .. method:: verify(signature)
+
+ Finalize the current context and securely compare digest to ``signature``.
+
+ :param bytes signature: The bytes of the HMAC signature recieved.
+ :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
+ :raises cryptography.exceptions.InvalidSignature: If signature does not match digest
diff --git a/docs/hazmat/primitives/interfaces.rst b/docs/hazmat/primitives/interfaces.rst
index 11cff51a..361b723e 100644
--- a/docs/hazmat/primitives/interfaces.rst
+++ b/docs/hazmat/primitives/interfaces.rst
@@ -36,6 +36,17 @@ Symmetric Ciphers
The number of bits in the key being used.
+.. class:: BlockCipherAlgorithm
+
+ A block cipher algorithm.
+
+ .. attribute:: block_size
+
+ :type: int
+
+ The number of bits in a block.
+
+
Cipher Modes
------------
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index 7b012975..e05248ff 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -61,7 +61,7 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_.
provider.
If the backend doesn't support the requested combination of ``cipher``
- and ``mode`` an :class:`cryptography.exceptions.UnsupportedAlgorithm`
+ and ``mode`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm`
will be raised.
.. method:: decryptor()
@@ -352,6 +352,16 @@ Modes
Do not reuse an ``initialization_vector``
with a given ``key``.
+ .. note::
+
+ Cryptography will emit a 128-bit tag when finalizing encryption.
+ You can shorten a tag by truncating it to the desired length, but this
+ is **not recommended** as it lowers the security margins of the
+ authentication (`NIST SP-800-38D`_ recommends 96-bits or greater).
+ If you must shorten the tag the minimum allowed length is 4 bytes
+ (32-bits). Applications **must** verify the tag is the expected length
+ to guarantee the expected security margin.
+
:param bytes tag: The tag bytes to verify during decryption. When encrypting
this must be None.
@@ -390,3 +400,4 @@ Insecure Modes
.. _`described by Colin Percival`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html
.. _`recommends 96-bit IV length`: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
+.. _`NIST SP-800-38D`: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
diff --git a/docs/index.rst b/docs/index.rst
index ab5d1593..72711174 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -32,9 +32,24 @@ existing libraries:
* Poor introspectability, and thus poor testability.
* Extremely error prone APIs, and bad defaults.
+Layout
+------
-Contents
---------
+``cryptography`` is broadly divided into two levels. One with safe
+cryptographic recipes, "cryptography for humans" if you will. These are safe
+and easy to use and don't require developers to make many decisions.
+
+The other level is low-level cryptographic primitives. These are often
+dangerous and can be used incorrectly. They require making decisions and having
+an in-depth knowledge of the cryptographic concepts at work. Because of the
+potential danger in working at this level, this is referred to as the
+"hazardous materials" or "hazmat" layer.
+
+We recommend using the recipes layer whenever possible, and falling back to the
+hazmat layer only when necessary.
+
+The recipes layer
+~~~~~~~~~~~~~~~~~
.. toctree::
:maxdepth: 2
@@ -43,15 +58,23 @@ Contents
architecture
exceptions
glossary
- contributing
- security
- community
-Hazardous Materials
--------------------
+The hazardous materials layer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. toctree::
:maxdepth: 2
hazmat/primitives/index
hazmat/backends/index
+
+The ``cryptography`` open source project
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. toctree::
+ :maxdepth: 2
+
+ contributing
+ security
+ api-stability
+ community
diff --git a/pytest.ini b/pytest.ini
index 723735ac..1aeb23fc 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,2 +1,6 @@
[pytest]
addopts = -r s
+markers =
+ hmac: this test requires a backend providing HMACBackend
+ cipher: this test requires a backend providing CipherBackend
+ hash: this test requires a backend providing HashBackend
diff --git a/tests/conftest.py b/tests/conftest.py
index 71662802..e059b630 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,5 +1,21 @@
+import pytest
+
+from cryptography.hazmat.backends.interfaces import (
+ HMACBackend, CipherBackend, HashBackend
+)
+
+from .utils import check_for_iface
+
+
def pytest_generate_tests(metafunc):
from cryptography.hazmat.backends import _ALL_BACKENDS
if "backend" in metafunc.fixturenames:
metafunc.parametrize("backend", _ALL_BACKENDS)
+
+
+@pytest.mark.trylast
+def pytest_runtest_setup(item):
+ check_for_iface("hmac", HMACBackend, item)
+ check_for_iface("cipher", CipherBackend, item)
+ check_for_iface("hash", HashBackend, item)
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 962959b9..543a05fe 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -23,13 +23,14 @@ from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import CBC
+@utils.register_interface(interfaces.Mode)
class DummyMode(object):
- pass
+ name = "dummy-mode"
@utils.register_interface(interfaces.CipherAlgorithm)
class DummyCipher(object):
- pass
+ name = "dummy-cipher"
class TestOpenSSL(object):
@@ -62,15 +63,16 @@ class TestOpenSSL(object):
assert b.ffi is backend.ffi
assert b.lib is backend.lib
- def test_nonexistent_cipher(self):
+ @pytest.mark.parametrize("mode", [DummyMode(), None])
+ def test_nonexistent_cipher(self, mode):
b = Backend()
b.register_cipher_adapter(
DummyCipher,
- DummyMode,
+ type(mode),
lambda backend, cipher, mode: backend.ffi.NULL
)
cipher = Cipher(
- DummyCipher(), DummyMode(), backend=b,
+ DummyCipher(), mode, backend=b,
)
with pytest.raises(UnsupportedAlgorithm):
cipher.encryptor()
diff --git a/tests/hazmat/primitives/test_3des.py b/tests/hazmat/primitives/test_3des.py
index 69ec9c9a..439ca258 100644
--- a/tests/hazmat/primitives/test_3des.py
+++ b/tests/hazmat/primitives/test_3des.py
@@ -20,12 +20,15 @@ from __future__ import absolute_import, division, print_function
import binascii
import os
+import pytest
+
from cryptography.hazmat.primitives.ciphers import algorithms, modes
from .utils import generate_encrypt_test
from ...utils import load_nist_vectors
+@pytest.mark.cipher
class TestTripleDES_CBC(object):
test_KAT = generate_encrypt_test(
load_nist_vectors,
@@ -37,8 +40,12 @@ class TestTripleDES_CBC(object):
"TCBCvarkey.rsp",
"TCBCvartext.rsp",
],
- lambda keys, iv: algorithms.TripleDES(binascii.unhexlify(keys)),
- lambda keys, iv: modes.CBC(binascii.unhexlify(iv)),
+ lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
+ lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)),
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.TripleDES("\x00" * 8), modes.CBC("\x00" * 8)
+ ),
+ skip_message="Does not support TripleDES CBC",
)
test_MMT = generate_encrypt_test(
@@ -49,13 +56,18 @@ class TestTripleDES_CBC(object):
"TCBCMMT2.rsp",
"TCBCMMT3.rsp",
],
- lambda key1, key2, key3, iv: (
- algorithms.TripleDES(binascii.unhexlify(key1 + key2 + key3))
+ lambda key1, key2, key3, **kwargs: algorithms.TripleDES(
+ binascii.unhexlify(key1 + key2 + key3)
),
- lambda key1, key2, key3, iv: modes.CBC(binascii.unhexlify(iv)),
+ lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)),
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.TripleDES("\x00" * 8), modes.CBC("\x00" * 8)
+ ),
+ skip_message="Does not support TripleDES CBC",
)
+@pytest.mark.cipher
class TestTripleDES_OFB(object):
test_KAT = generate_encrypt_test(
load_nist_vectors,
@@ -67,8 +79,12 @@ class TestTripleDES_OFB(object):
"TOFBvartext.rsp",
"TOFBinvperm.rsp",
],
- lambda keys, iv: algorithms.TripleDES(binascii.unhexlify(keys)),
- lambda keys, iv: modes.OFB(binascii.unhexlify(iv)),
+ lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
+ lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)),
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.TripleDES("\x00" * 8), modes.OFB("\x00" * 8)
+ ),
+ skip_message="Does not support TripleDES OFB",
)
test_MMT = generate_encrypt_test(
@@ -79,13 +95,18 @@ class TestTripleDES_OFB(object):
"TOFBMMT2.rsp",
"TOFBMMT3.rsp",
],
- lambda key1, key2, key3, iv: (
- algorithms.TripleDES(binascii.unhexlify(key1 + key2 + key3))
+ lambda key1, key2, key3, **kwargs: algorithms.TripleDES(
+ binascii.unhexlify(key1 + key2 + key3)
),
- lambda key1, key2, key3, iv: modes.OFB(binascii.unhexlify(iv)),
+ lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)),
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.TripleDES("\x00" * 8), modes.OFB("\x00" * 8)
+ ),
+ skip_message="Does not support TripleDES OFB",
)
+@pytest.mark.cipher
class TestTripleDES_CFB(object):
test_KAT = generate_encrypt_test(
load_nist_vectors,
@@ -97,8 +118,12 @@ class TestTripleDES_CFB(object):
"TCFB64varkey.rsp",
"TCFB64vartext.rsp",
],
- lambda keys, iv: algorithms.TripleDES(binascii.unhexlify(keys)),
- lambda keys, iv: modes.CFB(binascii.unhexlify(iv)),
+ lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
+ lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)),
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.TripleDES("\x00" * 8), modes.CFB("\x00" * 8)
+ ),
+ skip_message="Does not support TripleDES CFB",
)
test_MMT = generate_encrypt_test(
@@ -109,8 +134,12 @@ class TestTripleDES_CFB(object):
"TCFB64MMT2.rsp",
"TCFB64MMT3.rsp",
],
- lambda key1, key2, key3, iv: (
- algorithms.TripleDES(binascii.unhexlify(key1 + key2 + key3))
+ lambda key1, key2, key3, **kwargs: algorithms.TripleDES(
+ binascii.unhexlify(key1 + key2 + key3)
+ ),
+ lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)),
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.TripleDES("\x00" * 8), modes.CFB("\x00" * 8)
),
- lambda key1, key2, key3, iv: modes.CFB(binascii.unhexlify(iv)),
+ skip_message="Does not support TripleDES CFB",
)
diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py
index f7b0b9a0..e9ef3853 100644
--- a/tests/hazmat/primitives/test_aes.py
+++ b/tests/hazmat/primitives/test_aes.py
@@ -16,6 +16,8 @@ from __future__ import absolute_import, division, print_function
import binascii
import os
+import pytest
+
from cryptography.hazmat.primitives.ciphers import algorithms, modes
from .utils import generate_encrypt_test, generate_aead_test
@@ -24,6 +26,7 @@ from ...utils import (
)
+@pytest.mark.cipher
class TestAES(object):
test_CBC = generate_encrypt_test(
load_nist_vectors,
@@ -45,8 +48,12 @@ class TestAES(object):
"CBCMMT192.rsp",
"CBCMMT256.rsp",
],
- lambda key, iv: algorithms.AES(binascii.unhexlify(key)),
- lambda key, iv: modes.CBC(binascii.unhexlify(iv)),
+ lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)),
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.AES("\x00" * 16), modes.CBC("\x00" * 16)
+ ),
+ skip_message="Does not support AES CBC",
)
test_ECB = generate_encrypt_test(
@@ -69,8 +76,12 @@ class TestAES(object):
"ECBMMT192.rsp",
"ECBMMT256.rsp",
],
- lambda key: algorithms.AES(binascii.unhexlify(key)),
- lambda key: modes.ECB(),
+ lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)),
+ lambda **kwargs: modes.ECB(),
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.AES("\x00" * 16), modes.ECB()
+ ),
+ skip_message="Does not support AES ECB",
)
test_OFB = generate_encrypt_test(
@@ -93,8 +104,12 @@ class TestAES(object):
"OFBMMT192.rsp",
"OFBMMT256.rsp",
],
- lambda key, iv: algorithms.AES(binascii.unhexlify(key)),
- lambda key, iv: modes.OFB(binascii.unhexlify(iv)),
+ lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)),
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.AES("\x00" * 16), modes.OFB("\x00" * 16)
+ ),
+ skip_message="Does not support AES OFB",
)
test_CFB = generate_encrypt_test(
@@ -117,16 +132,20 @@ class TestAES(object):
"CFB128MMT192.rsp",
"CFB128MMT256.rsp",
],
- lambda key, iv: algorithms.AES(binascii.unhexlify(key)),
- lambda key, iv: modes.CFB(binascii.unhexlify(iv)),
+ lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)),
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.AES("\x00" * 16), modes.CFB("\x00" * 16)
+ ),
+ skip_message="Does not support AES CFB",
)
test_CTR = generate_encrypt_test(
load_openssl_vectors,
os.path.join("ciphers", "AES", "CTR"),
["aes-128-ctr.txt", "aes-192-ctr.txt", "aes-256-ctr.txt"],
- lambda key, iv: algorithms.AES(binascii.unhexlify(key)),
- lambda key, iv: modes.CTR(binascii.unhexlify(iv)),
+ lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.CTR(binascii.unhexlify(iv)),
only_if=lambda backend: backend.cipher_supported(
algorithms.AES("\x00" * 16), modes.CTR("\x00" * 16)
),
diff --git a/tests/hazmat/primitives/test_arc4.py b/tests/hazmat/primitives/test_arc4.py
index d233bec2..f2e2452c 100644
--- a/tests/hazmat/primitives/test_arc4.py
+++ b/tests/hazmat/primitives/test_arc4.py
@@ -16,12 +16,15 @@ from __future__ import absolute_import, division, print_function
import binascii
import os
+import pytest
+
from cryptography.hazmat.primitives.ciphers import algorithms
from .utils import generate_stream_encryption_test
from ...utils import load_nist_vectors
+@pytest.mark.cipher
class TestARC4(object):
test_rfc = generate_stream_encryption_test(
load_nist_vectors,
@@ -35,7 +38,7 @@ class TestARC4(object):
"rfc-6229-192.txt",
"rfc-6229-256.txt",
],
- lambda key: algorithms.ARC4(binascii.unhexlify((key))),
+ lambda key, **kwargs: algorithms.ARC4(binascii.unhexlify(key)),
only_if=lambda backend: backend.cipher_supported(
algorithms.ARC4("\x00" * 16), None
),
diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py
index 02de3861..22a7c02f 100644
--- a/tests/hazmat/primitives/test_block.py
+++ b/tests/hazmat/primitives/test_block.py
@@ -31,11 +31,17 @@ from .utils import (
)
+@utils.register_interface(interfaces.Mode)
+class DummyMode(object):
+ name = "dummy-mode"
+
+
@utils.register_interface(interfaces.CipherAlgorithm)
class DummyCipher(object):
- pass
+ name = "dummy-cipher"
+@pytest.mark.cipher
class TestCipher(object):
def test_creates_encryptor(self, backend):
cipher = Cipher(
@@ -59,6 +65,7 @@ class TestCipher(object):
Cipher(algorithm, mode=None, backend=backend)
+@pytest.mark.cipher
class TestCipherContext(object):
def test_use_after_finalize(self, backend):
cipher = Cipher(
@@ -101,9 +108,10 @@ class TestCipherContext(object):
assert pt == b"a" * 80
decryptor.finalize()
- def test_nonexistent_cipher(self, backend):
+ @pytest.mark.parametrize("mode", [DummyMode(), None])
+ def test_nonexistent_cipher(self, backend, mode):
cipher = Cipher(
- DummyCipher(), object(), backend
+ DummyCipher(), mode, backend
)
with pytest.raises(UnsupportedAlgorithm):
cipher.encryptor()
@@ -128,6 +136,7 @@ class TestCipherContext(object):
decryptor.finalize()
+@pytest.mark.cipher
class TestAEADCipherContext(object):
test_aead_exceptions = generate_aead_exception_test(
algorithms.AES,
diff --git a/tests/hazmat/primitives/test_blowfish.py b/tests/hazmat/primitives/test_blowfish.py
index d5fbed6f..79ceabe7 100644
--- a/tests/hazmat/primitives/test_blowfish.py
+++ b/tests/hazmat/primitives/test_blowfish.py
@@ -16,19 +16,22 @@ from __future__ import absolute_import, division, print_function
import binascii
import os
+import pytest
+
from cryptography.hazmat.primitives.ciphers import algorithms, modes
from .utils import generate_encrypt_test
from ...utils import load_nist_vectors
+@pytest.mark.cipher
class TestBlowfish(object):
test_ECB = generate_encrypt_test(
load_nist_vectors,
os.path.join("ciphers", "Blowfish"),
["bf-ecb.txt"],
- lambda key: algorithms.Blowfish(binascii.unhexlify(key)),
- lambda key: modes.ECB(),
+ lambda key, **kwargs: algorithms.Blowfish(binascii.unhexlify(key)),
+ lambda **kwargs: modes.ECB(),
only_if=lambda backend: backend.cipher_supported(
algorithms.Blowfish("\x00" * 56), modes.ECB()
),
@@ -39,8 +42,8 @@ class TestBlowfish(object):
load_nist_vectors,
os.path.join("ciphers", "Blowfish"),
["bf-cbc.txt"],
- lambda key, iv: algorithms.Blowfish(binascii.unhexlify(key)),
- lambda key, iv: modes.CBC(binascii.unhexlify(iv)),
+ lambda key, **kwargs: algorithms.Blowfish(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)),
only_if=lambda backend: backend.cipher_supported(
algorithms.Blowfish("\x00" * 56), modes.CBC("\x00" * 8)
),
@@ -51,8 +54,8 @@ class TestBlowfish(object):
load_nist_vectors,
os.path.join("ciphers", "Blowfish"),
["bf-ofb.txt"],
- lambda key, iv: algorithms.Blowfish(binascii.unhexlify(key)),
- lambda key, iv: modes.OFB(binascii.unhexlify(iv)),
+ lambda key, **kwargs: algorithms.Blowfish(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)),
only_if=lambda backend: backend.cipher_supported(
algorithms.Blowfish("\x00" * 56), modes.OFB("\x00" * 8)
),
@@ -63,8 +66,8 @@ class TestBlowfish(object):
load_nist_vectors,
os.path.join("ciphers", "Blowfish"),
["bf-cfb.txt"],
- lambda key, iv: algorithms.Blowfish(binascii.unhexlify(key)),
- lambda key, iv: modes.CFB(binascii.unhexlify(iv)),
+ lambda key, **kwargs: algorithms.Blowfish(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)),
only_if=lambda backend: backend.cipher_supported(
algorithms.Blowfish("\x00" * 56), modes.CFB("\x00" * 8)
),
diff --git a/tests/hazmat/primitives/test_camellia.py b/tests/hazmat/primitives/test_camellia.py
index a2c935d9..c376220e 100644
--- a/tests/hazmat/primitives/test_camellia.py
+++ b/tests/hazmat/primitives/test_camellia.py
@@ -16,6 +16,8 @@ from __future__ import absolute_import, division, print_function
import binascii
import os
+import pytest
+
from cryptography.hazmat.primitives.ciphers import algorithms, modes
from .utils import generate_encrypt_test
@@ -24,6 +26,7 @@ from ...utils import (
)
+@pytest.mark.cipher
class TestCamellia(object):
test_ECB = generate_encrypt_test(
load_cryptrec_vectors,
@@ -33,8 +36,8 @@ class TestCamellia(object):
"camellia-192-ecb.txt",
"camellia-256-ecb.txt"
],
- lambda key: algorithms.Camellia(binascii.unhexlify((key))),
- lambda key: modes.ECB(),
+ lambda key, **kwargs: algorithms.Camellia(binascii.unhexlify(key)),
+ lambda **kwargs: modes.ECB(),
only_if=lambda backend: backend.cipher_supported(
algorithms.Camellia("\x00" * 16), modes.ECB()
),
@@ -45,8 +48,8 @@ class TestCamellia(object):
load_openssl_vectors,
os.path.join("ciphers", "Camellia"),
["camellia-cbc.txt"],
- lambda key, iv: algorithms.Camellia(binascii.unhexlify(key)),
- lambda key, iv: modes.CBC(binascii.unhexlify(iv)),
+ lambda key, **kwargs: algorithms.Camellia(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)),
only_if=lambda backend: backend.cipher_supported(
algorithms.Camellia("\x00" * 16), modes.CBC("\x00" * 16)
),
@@ -57,8 +60,8 @@ class TestCamellia(object):
load_openssl_vectors,
os.path.join("ciphers", "Camellia"),
["camellia-ofb.txt"],
- lambda key, iv: algorithms.Camellia(binascii.unhexlify(key)),
- lambda key, iv: modes.OFB(binascii.unhexlify(iv)),
+ lambda key, **kwargs: algorithms.Camellia(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)),
only_if=lambda backend: backend.cipher_supported(
algorithms.Camellia("\x00" * 16), modes.OFB("\x00" * 16)
),
@@ -69,8 +72,8 @@ class TestCamellia(object):
load_openssl_vectors,
os.path.join("ciphers", "Camellia"),
["camellia-cfb.txt"],
- lambda key, iv: algorithms.Camellia(binascii.unhexlify(key)),
- lambda key, iv: modes.CFB(binascii.unhexlify(iv)),
+ lambda key, **kwargs: algorithms.Camellia(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)),
only_if=lambda backend: backend.cipher_supported(
algorithms.Camellia("\x00" * 16), modes.CFB("\x00" * 16)
),
diff --git a/tests/hazmat/primitives/test_cast5.py b/tests/hazmat/primitives/test_cast5.py
index a283dafc..a4789c65 100644
--- a/tests/hazmat/primitives/test_cast5.py
+++ b/tests/hazmat/primitives/test_cast5.py
@@ -16,19 +16,22 @@ from __future__ import absolute_import, division, print_function
import binascii
import os
+import pytest
+
from cryptography.hazmat.primitives.ciphers import algorithms, modes
from .utils import generate_encrypt_test
from ...utils import load_nist_vectors
+@pytest.mark.cipher
class TestCAST5(object):
test_ECB = generate_encrypt_test(
load_nist_vectors,
os.path.join("ciphers", "CAST5"),
["cast5-ecb.txt"],
- lambda key: algorithms.CAST5(binascii.unhexlify((key))),
- lambda key: modes.ECB(),
+ lambda key, **kwargs: algorithms.CAST5(binascii.unhexlify((key))),
+ lambda **kwargs: modes.ECB(),
only_if=lambda backend: backend.cipher_supported(
algorithms.CAST5("\x00" * 16), modes.ECB()
),
diff --git a/tests/hazmat/primitives/test_hash_vectors.py b/tests/hazmat/primitives/test_hash_vectors.py
index a8655812..d9febea9 100644
--- a/tests/hazmat/primitives/test_hash_vectors.py
+++ b/tests/hazmat/primitives/test_hash_vectors.py
@@ -15,12 +15,15 @@ from __future__ import absolute_import, division, print_function
import os
+import pytest
+
from cryptography.hazmat.primitives import hashes
from .utils import generate_hash_test, generate_long_string_hash_test
from ...utils import load_hash_vectors
+@pytest.mark.hash
class TestSHA1(object):
test_SHA1 = generate_hash_test(
load_hash_vectors,
@@ -35,6 +38,7 @@ class TestSHA1(object):
)
+@pytest.mark.hash
class TestSHA224(object):
test_SHA224 = generate_hash_test(
load_hash_vectors,
@@ -49,6 +53,7 @@ class TestSHA224(object):
)
+@pytest.mark.hash
class TestSHA256(object):
test_SHA256 = generate_hash_test(
load_hash_vectors,
@@ -63,6 +68,7 @@ class TestSHA256(object):
)
+@pytest.mark.hash
class TestSHA384(object):
test_SHA384 = generate_hash_test(
load_hash_vectors,
@@ -77,6 +83,7 @@ class TestSHA384(object):
)
+@pytest.mark.hash
class TestSHA512(object):
test_SHA512 = generate_hash_test(
load_hash_vectors,
@@ -91,6 +98,7 @@ class TestSHA512(object):
)
+@pytest.mark.hash
class TestRIPEMD160(object):
test_RIPEMD160 = generate_hash_test(
load_hash_vectors,
@@ -111,6 +119,7 @@ class TestRIPEMD160(object):
)
+@pytest.mark.hash
class TestWhirlpool(object):
test_whirlpool = generate_hash_test(
load_hash_vectors,
@@ -133,6 +142,7 @@ class TestWhirlpool(object):
)
+@pytest.mark.hash
class TestMD5(object):
test_md5 = generate_hash_test(
load_hash_vectors,
diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py
index ff42e8f4..45faaab2 100644
--- a/tests/hazmat/primitives/test_hashes.py
+++ b/tests/hazmat/primitives/test_hashes.py
@@ -19,12 +19,19 @@ import pytest
import six
-from cryptography.exceptions import AlreadyFinalized
-from cryptography.hazmat.primitives import hashes
+from cryptography import utils
+from cryptography.exceptions import AlreadyFinalized, UnsupportedAlgorithm
+from cryptography.hazmat.primitives import hashes, interfaces
from .utils import generate_base_hash_test
+@utils.register_interface(interfaces.HashAlgorithm)
+class UnsupportedDummyHash(object):
+ name = "unsupported-dummy-hash"
+
+
+@pytest.mark.hash
class TestHashContext(object):
def test_hash_reject_unicode(self, backend):
m = hashes.Hash(hashes.SHA1(), backend=backend)
@@ -57,7 +64,12 @@ class TestHashContext(object):
with pytest.raises(AlreadyFinalized):
h.finalize()
+ def test_unsupported_hash(self, backend):
+ with pytest.raises(UnsupportedAlgorithm):
+ hashes.Hash(UnsupportedDummyHash(), backend)
+
+@pytest.mark.hash
class TestSHA1(object):
test_SHA1 = generate_base_hash_test(
hashes.SHA1(),
@@ -68,6 +80,7 @@ class TestSHA1(object):
)
+@pytest.mark.hash
class TestSHA224(object):
test_SHA224 = generate_base_hash_test(
hashes.SHA224(),
@@ -78,6 +91,7 @@ class TestSHA224(object):
)
+@pytest.mark.hash
class TestSHA256(object):
test_SHA256 = generate_base_hash_test(
hashes.SHA256(),
@@ -88,6 +102,7 @@ class TestSHA256(object):
)
+@pytest.mark.hash
class TestSHA384(object):
test_SHA384 = generate_base_hash_test(
hashes.SHA384(),
@@ -98,6 +113,7 @@ class TestSHA384(object):
)
+@pytest.mark.hash
class TestSHA512(object):
test_SHA512 = generate_base_hash_test(
hashes.SHA512(),
@@ -108,6 +124,7 @@ class TestSHA512(object):
)
+@pytest.mark.hash
class TestRIPEMD160(object):
test_RIPEMD160 = generate_base_hash_test(
hashes.RIPEMD160(),
@@ -118,6 +135,7 @@ class TestRIPEMD160(object):
)
+@pytest.mark.hash
class TestWhirlpool(object):
test_Whirlpool = generate_base_hash_test(
hashes.Whirlpool(),
@@ -128,6 +146,7 @@ class TestWhirlpool(object):
)
+@pytest.mark.hash
class TestMD5(object):
test_MD5 = generate_base_hash_test(
hashes.MD5(),
diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py
index 992bcb1a..7acb78b7 100644
--- a/tests/hazmat/primitives/test_hmac.py
+++ b/tests/hazmat/primitives/test_hmac.py
@@ -19,16 +19,25 @@ import pytest
import six
-from cryptography.exceptions import AlreadyFinalized
-from cryptography.hazmat.primitives import hashes, hmac
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, UnsupportedAlgorithm, InvalidSignature
+)
+from cryptography.hazmat.primitives import hashes, hmac, interfaces
from .utils import generate_base_hmac_test
+@utils.register_interface(interfaces.HashAlgorithm)
+class UnsupportedDummyHash(object):
+ name = "unsupported-dummy-hash"
+
+
+@pytest.mark.hmac
class TestHMAC(object):
test_copy = generate_base_hmac_test(
hashes.MD5(),
- only_if=lambda backend: backend.hash_supported(hashes.MD5),
+ only_if=lambda backend: backend.hmac_supported(hashes.MD5),
skip_message="Does not support MD5",
)
@@ -63,3 +72,30 @@ class TestHMAC(object):
with pytest.raises(AlreadyFinalized):
h.finalize()
+
+ def test_verify(self, backend):
+ h = hmac.HMAC(b'', hashes.SHA1(), backend=backend)
+ digest = h.finalize()
+
+ h = hmac.HMAC(b'', hashes.SHA1(), backend=backend)
+ h.verify(digest)
+
+ with pytest.raises(AlreadyFinalized):
+ h.verify(b'')
+
+ def test_invalid_verify(self, backend):
+ h = hmac.HMAC(b'', hashes.SHA1(), backend=backend)
+ with pytest.raises(InvalidSignature):
+ h.verify(b'')
+
+ with pytest.raises(AlreadyFinalized):
+ h.verify(b'')
+
+ def test_verify_reject_unicode(self, backend):
+ h = hmac.HMAC(b'', hashes.SHA1(), backend=backend)
+ with pytest.raises(TypeError):
+ h.verify(six.u(''))
+
+ def test_unsupported_hash(self, backend):
+ with pytest.raises(UnsupportedAlgorithm):
+ hmac.HMAC(b"key", UnsupportedDummyHash(), backend)
diff --git a/tests/hazmat/primitives/test_hmac_vectors.py b/tests/hazmat/primitives/test_hmac_vectors.py
index 7d0f156a..9bc06a2e 100644
--- a/tests/hazmat/primitives/test_hmac_vectors.py
+++ b/tests/hazmat/primitives/test_hmac_vectors.py
@@ -13,12 +13,15 @@
from __future__ import absolute_import, division, print_function
+import pytest
+
from cryptography.hazmat.primitives import hashes
from .utils import generate_hmac_test
from ...utils import load_hash_vectors
+@pytest.mark.hmac
class TestHMAC_MD5(object):
test_hmac_md5 = generate_hmac_test(
load_hash_vectors,
@@ -27,11 +30,12 @@ class TestHMAC_MD5(object):
"rfc-2202-md5.txt",
],
hashes.MD5(),
- only_if=lambda backend: backend.hash_supported(hashes.MD5),
+ only_if=lambda backend: backend.hmac_supported(hashes.MD5),
skip_message="Does not support MD5",
)
+@pytest.mark.hmac
class TestHMAC_SHA1(object):
test_hmac_sha1 = generate_hmac_test(
load_hash_vectors,
@@ -40,11 +44,12 @@ class TestHMAC_SHA1(object):
"rfc-2202-sha1.txt",
],
hashes.SHA1(),
- only_if=lambda backend: backend.hash_supported(hashes.SHA1),
+ only_if=lambda backend: backend.hmac_supported(hashes.SHA1),
skip_message="Does not support SHA1",
)
+@pytest.mark.hmac
class TestHMAC_SHA224(object):
test_hmac_sha224 = generate_hmac_test(
load_hash_vectors,
@@ -53,11 +58,12 @@ class TestHMAC_SHA224(object):
"rfc-4231-sha224.txt",
],
hashes.SHA224(),
- only_if=lambda backend: backend.hash_supported(hashes.SHA224),
+ only_if=lambda backend: backend.hmac_supported(hashes.SHA224),
skip_message="Does not support SHA224",
)
+@pytest.mark.hmac
class TestHMAC_SHA256(object):
test_hmac_sha256 = generate_hmac_test(
load_hash_vectors,
@@ -66,11 +72,12 @@ class TestHMAC_SHA256(object):
"rfc-4231-sha256.txt",
],
hashes.SHA256(),
- only_if=lambda backend: backend.hash_supported(hashes.SHA256),
+ only_if=lambda backend: backend.hmac_supported(hashes.SHA256),
skip_message="Does not support SHA256",
)
+@pytest.mark.hmac
class TestHMAC_SHA384(object):
test_hmac_sha384 = generate_hmac_test(
load_hash_vectors,
@@ -79,11 +86,12 @@ class TestHMAC_SHA384(object):
"rfc-4231-sha384.txt",
],
hashes.SHA384(),
- only_if=lambda backend: backend.hash_supported(hashes.SHA384),
+ only_if=lambda backend: backend.hmac_supported(hashes.SHA384),
skip_message="Does not support SHA384",
)
+@pytest.mark.hmac
class TestHMAC_SHA512(object):
test_hmac_sha512 = generate_hmac_test(
load_hash_vectors,
@@ -92,11 +100,12 @@ class TestHMAC_SHA512(object):
"rfc-4231-sha512.txt",
],
hashes.SHA512(),
- only_if=lambda backend: backend.hash_supported(hashes.SHA512),
+ only_if=lambda backend: backend.hmac_supported(hashes.SHA512),
skip_message="Does not support SHA512",
)
+@pytest.mark.hmac
class TestHMAC_RIPEMD160(object):
test_hmac_ripemd160 = generate_hmac_test(
load_hash_vectors,
@@ -105,6 +114,6 @@ class TestHMAC_RIPEMD160(object):
"rfc-2286-ripemd160.txt",
],
hashes.RIPEMD160(),
- only_if=lambda backend: backend.hash_supported(hashes.RIPEMD160),
+ only_if=lambda backend: backend.hmac_supported(hashes.RIPEMD160),
skip_message="Does not support RIPEMD160",
)
diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py
index b06f9b29..e0184777 100644
--- a/tests/hazmat/primitives/utils.py
+++ b/tests/hazmat/primitives/utils.py
@@ -3,7 +3,6 @@ import os
import pytest
-from cryptography.hazmat.backends import _ALL_BACKENDS
from cryptography.hazmat.primitives import hashes, hmac
from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.exceptions import (
@@ -13,25 +12,30 @@ from cryptography.exceptions import (
from ...utils import load_vectors_from_file
+def _load_all_params(path, file_names, param_loader):
+ all_params = []
+ for file_name in file_names:
+ all_params.extend(
+ load_vectors_from_file(os.path.join(path, file_name), param_loader)
+ )
+ return all_params
+
+
def generate_encrypt_test(param_loader, path, file_names, cipher_factory,
- mode_factory, only_if=lambda backend: True,
- skip_message=None):
- def test_encryption(self):
- for backend in _ALL_BACKENDS:
- for file_name in file_names:
- for params in load_vectors_from_file(
- os.path.join(path, file_name),
- param_loader
- ):
- yield (
- encrypt_test,
- backend,
- cipher_factory,
- mode_factory,
- params,
- only_if,
- skip_message
- )
+ mode_factory, only_if, skip_message=None):
+ all_params = _load_all_params(path, file_names, param_loader)
+
+ @pytest.mark.parametrize("params", all_params)
+ def test_encryption(self, backend, params):
+ encrypt_test(
+ backend,
+ cipher_factory,
+ mode_factory,
+ params,
+ only_if,
+ skip_message
+ )
+
return test_encryption
@@ -39,8 +43,8 @@ def encrypt_test(backend, cipher_factory, mode_factory, params, only_if,
skip_message):
if not only_if(backend):
pytest.skip(skip_message)
- plaintext = params.pop("plaintext")
- ciphertext = params.pop("ciphertext")
+ plaintext = params["plaintext"]
+ ciphertext = params["ciphertext"]
cipher = Cipher(
cipher_factory(**params),
mode_factory(**params),
@@ -58,22 +62,19 @@ def encrypt_test(backend, cipher_factory, mode_factory, params, only_if,
def generate_aead_test(param_loader, path, file_names, cipher_factory,
mode_factory, only_if, skip_message):
- def test_aead(self):
- for backend in _ALL_BACKENDS:
- for file_name in file_names:
- for params in load_vectors_from_file(
- os.path.join(path, file_name),
- param_loader
- ):
- yield (
- aead_test,
- backend,
- cipher_factory,
- mode_factory,
- params,
- only_if,
- skip_message
- )
+ all_params = _load_all_params(path, file_names, param_loader)
+
+ @pytest.mark.parametrize("params", all_params)
+ def test_aead(self, backend, params):
+ aead_test(
+ backend,
+ cipher_factory,
+ mode_factory,
+ params,
+ only_if,
+ skip_message
+ )
+
return test_aead
@@ -82,9 +83,9 @@ def aead_test(backend, cipher_factory, mode_factory, params, only_if,
if not only_if(backend):
pytest.skip(skip_message)
if params.get("pt") is not None:
- plaintext = params.pop("pt")
- ciphertext = params.pop("ct")
- aad = params.pop("aad")
+ plaintext = params["pt"]
+ ciphertext = params["ct"]
+ aad = params["aad"]
if params.get("fail") is True:
cipher = Cipher(
cipher_factory(binascii.unhexlify(params["key"])),
@@ -125,21 +126,17 @@ def aead_test(backend, cipher_factory, mode_factory, params, only_if,
def generate_stream_encryption_test(param_loader, path, file_names,
cipher_factory, only_if=None,
skip_message=None):
- def test_stream_encryption(self):
- for backend in _ALL_BACKENDS:
- for file_name in file_names:
- for params in load_vectors_from_file(
- os.path.join(path, file_name),
- param_loader
- ):
- yield (
- stream_encryption_test,
- backend,
- cipher_factory,
- params,
- only_if,
- skip_message
- )
+ all_params = _load_all_params(path, file_names, param_loader)
+
+ @pytest.mark.parametrize("params", all_params)
+ def test_stream_encryption(self, backend, params):
+ stream_encryption_test(
+ backend,
+ cipher_factory,
+ params,
+ only_if,
+ skip_message
+ )
return test_stream_encryption
@@ -147,9 +144,9 @@ def stream_encryption_test(backend, cipher_factory, params, only_if,
skip_message):
if not only_if(backend):
pytest.skip(skip_message)
- plaintext = params.pop("plaintext")
- ciphertext = params.pop("ciphertext")
- offset = params.pop("offset")
+ plaintext = params["plaintext"]
+ ciphertext = params["ciphertext"]
+ offset = params["offset"]
cipher = Cipher(cipher_factory(**params), None, backend=backend)
encryptor = cipher.encryptor()
# throw away offset bytes
@@ -166,21 +163,17 @@ def stream_encryption_test(backend, cipher_factory, params, only_if,
def generate_hash_test(param_loader, path, file_names, hash_cls,
only_if=None, skip_message=None):
- def test_hash(self):
- for backend in _ALL_BACKENDS:
- for file_name in file_names:
- for params in load_vectors_from_file(
- os.path.join(path, file_name),
- param_loader
- ):
- yield (
- hash_test,
- backend,
- hash_cls,
- params,
- only_if,
- skip_message
- )
+ all_params = _load_all_params(path, file_names, param_loader)
+
+ @pytest.mark.parametrize("params", all_params)
+ def test_hash(self, backend, params):
+ hash_test(
+ backend,
+ hash_cls,
+ params,
+ only_if,
+ skip_message
+ )
return test_hash
@@ -197,17 +190,15 @@ def hash_test(backend, algorithm, params, only_if, skip_message):
def generate_base_hash_test(algorithm, digest_size, block_size,
only_if=None, skip_message=None):
- def test_base_hash(self):
- for backend in _ALL_BACKENDS:
- yield (
- base_hash_test,
- backend,
- algorithm,
- digest_size,
- block_size,
- only_if,
- skip_message,
- )
+ def test_base_hash(self, backend):
+ base_hash_test(
+ backend,
+ algorithm,
+ digest_size,
+ block_size,
+ only_if,
+ skip_message,
+ )
return test_base_hash
@@ -232,16 +223,14 @@ def base_hash_test(backend, algorithm, digest_size, block_size, only_if,
def generate_long_string_hash_test(hash_factory, md, only_if=None,
skip_message=None):
- def test_long_string_hash(self):
- for backend in _ALL_BACKENDS:
- yield(
- long_string_hash_test,
- backend,
- hash_factory,
- md,
- only_if,
- skip_message
- )
+ def test_long_string_hash(self, backend):
+ long_string_hash_test(
+ backend,
+ hash_factory,
+ md,
+ only_if,
+ skip_message
+ )
return test_long_string_hash
@@ -255,21 +244,17 @@ def long_string_hash_test(backend, algorithm, md, only_if, skip_message):
def generate_hmac_test(param_loader, path, file_names, algorithm,
only_if=None, skip_message=None):
- def test_hmac(self):
- for backend in _ALL_BACKENDS:
- for file_name in file_names:
- for params in load_vectors_from_file(
- os.path.join(path, file_name),
- param_loader
- ):
- yield (
- hmac_test,
- backend,
- algorithm,
- params,
- only_if,
- skip_message
- )
+ all_params = _load_all_params(path, file_names, param_loader)
+
+ @pytest.mark.parametrize("params", all_params)
+ def test_hmac(self, backend, params):
+ hmac_test(
+ backend,
+ algorithm,
+ params,
+ only_if,
+ skip_message
+ )
return test_hmac
@@ -285,15 +270,13 @@ def hmac_test(backend, algorithm, params, only_if, skip_message):
def generate_base_hmac_test(hash_cls, only_if=None, skip_message=None):
- def test_base_hmac(self):
- for backend in _ALL_BACKENDS:
- yield (
- base_hmac_test,
- backend,
- hash_cls,
- only_if,
- skip_message,
- )
+ def test_base_hmac(self, backend):
+ base_hmac_test(
+ backend,
+ hash_cls,
+ only_if,
+ skip_message,
+ )
return test_base_hmac
@@ -309,16 +292,14 @@ def base_hmac_test(backend, algorithm, only_if, skip_message):
def generate_aead_exception_test(cipher_factory, mode_factory,
only_if, skip_message):
- def test_aead_exception(self):
- for backend in _ALL_BACKENDS:
- yield (
- aead_exception_test,
- backend,
- cipher_factory,
- mode_factory,
- only_if,
- skip_message
- )
+ def test_aead_exception(self, backend):
+ aead_exception_test(
+ backend,
+ cipher_factory,
+ mode_factory,
+ only_if,
+ skip_message
+ )
return test_aead_exception
@@ -357,16 +338,14 @@ def aead_exception_test(backend, cipher_factory, mode_factory,
def generate_aead_tag_exception_test(cipher_factory, mode_factory,
only_if, skip_message):
- def test_aead_tag_exception(self):
- for backend in _ALL_BACKENDS:
- yield (
- aead_tag_exception_test,
- backend,
- cipher_factory,
- mode_factory,
- only_if,
- skip_message
- )
+ def test_aead_tag_exception(self, backend):
+ aead_tag_exception_test(
+ backend,
+ cipher_factory,
+ mode_factory,
+ only_if,
+ skip_message
+ )
return test_aead_tag_exception
@@ -383,6 +362,13 @@ def aead_tag_exception_test(backend, cipher_factory, mode_factory,
cipher.decryptor()
cipher = Cipher(
cipher_factory(binascii.unhexlify(b"0" * 32)),
+ mode_factory(binascii.unhexlify(b"0" * 24), b"000"),
+ backend
+ )
+ with pytest.raises(ValueError):
+ cipher.decryptor()
+ cipher = Cipher(
+ cipher_factory(binascii.unhexlify(b"0" * 32)),
mode_factory(binascii.unhexlify(b"0" * 24), b"0" * 16),
backend
)
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 5c58fd76..a65091ff 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -14,14 +14,33 @@
import os
import textwrap
+import pretend
+
import pytest
from .utils import (
load_nist_vectors, load_vectors_from_file, load_cryptrec_vectors,
- load_openssl_vectors, load_hash_vectors,
+ load_openssl_vectors, load_hash_vectors, check_for_iface
)
+class FakeInterface(object):
+ pass
+
+
+def test_check_for_iface():
+ item = pretend.stub(keywords=["fake_name"], funcargs={"backend": True})
+ with pytest.raises(pytest.skip.Exception) as exc_info:
+ check_for_iface("fake_name", FakeInterface, item)
+ assert exc_info.value.args[0] == "True backend does not support fake_name"
+
+ item = pretend.stub(
+ keywords=["fake_name"],
+ funcargs={"backend": FakeInterface()}
+ )
+ check_for_iface("fake_name", FakeInterface, item)
+
+
def test_load_nist_vectors():
vector_data = textwrap.dedent("""
# CAVS 11.1
diff --git a/tests/utils.py b/tests/utils.py
index 94f97d59..82021a5f 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -11,7 +11,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os.path
+import os
+
+import pytest
+
+
+def check_for_iface(name, iface, item):
+ if name in item.keywords and "backend" in item.funcargs:
+ if not isinstance(item.funcargs["backend"], iface):
+ pytest.skip("{0} backend does not support {1}".format(
+ item.funcargs["backend"], name
+ ))
def load_vectors_from_file(filename, loader):
diff --git a/tox.ini b/tox.ini
index 547d90d9..1174a6f8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -8,7 +8,7 @@ deps =
pretend
pytest
commands =
- coverage run --source=cryptography/,tests/ -m pytest --strict
+ coverage run --source=cryptography/,tests/ -m pytest --capture=no --strict
coverage report -m
[testenv:docs]
@@ -25,7 +25,7 @@ commands =
# Temporarily disable coverage on pypy because of performance problems with
# coverage.py on pypy.
[testenv:pypy]
-commands = py.test
+commands = py.test --capture=no
[testenv:pep8]
deps = flake8