aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.coveragerc2
-rw-r--r--.gitignore1
-rw-r--r--AUTHORS.rst4
-rw-r--r--README.rst17
-rw-r--r--cryptography/__about__.py2
-rw-r--r--cryptography/bindings/__init__.py20
-rw-r--r--cryptography/bindings/openssl/api.py46
-rw-r--r--cryptography/bindings/openssl/bignum.py34
-rw-r--r--cryptography/bindings/openssl/bio.py170
-rw-r--r--cryptography/bindings/openssl/conf.py26
-rw-r--r--cryptography/bindings/openssl/crypto.py37
-rw-r--r--cryptography/bindings/openssl/dh.py28
-rw-r--r--cryptography/bindings/openssl/dsa.py30
-rw-r--r--cryptography/bindings/openssl/engine.py52
-rw-r--r--cryptography/bindings/openssl/err.py54
-rw-r--r--cryptography/bindings/openssl/evp.py8
-rw-r--r--cryptography/bindings/openssl/opensslv.py3
-rw-r--r--cryptography/bindings/openssl/rand.py37
-rw-r--r--cryptography/bindings/openssl/rsa.py31
-rw-r--r--cryptography/bindings/openssl/ssl.py26
-rw-r--r--cryptography/primitives/block/base.py20
-rw-r--r--cryptography/primitives/block/ciphers.py22
-rw-r--r--cryptography/primitives/block/modes.py20
-rw-r--r--cryptography/primitives/interfaces.py4
-rw-r--r--dev-requirements.txt5
-rw-r--r--docs/bindings/openssl.rst2
-rw-r--r--docs/community.rst4
-rw-r--r--docs/contributing.rst75
-rw-r--r--docs/primitives/symmetric-encryption.rst28
-rw-r--r--pytest.ini2
-rw-r--r--tests/bindings/test_openssl.py3
-rw-r--r--tests/conftest.py5
-rw-r--r--tests/primitives/test_block.py20
-rw-r--r--tests/primitives/test_ciphers.py17
-rw-r--r--tests/primitives/test_cryptrec.py42
-rw-r--r--tests/primitives/test_nist.py171
-rw-r--r--tests/primitives/test_openssl_vectors.py73
-rw-r--r--tests/primitives/test_utils.py14
-rw-r--r--tests/primitives/utils.py42
-rw-r--r--tests/primitives/vectors/OpenSSL/AES/aes-128-ctr.txt4
-rw-r--r--tests/primitives/vectors/OpenSSL/AES/aes-192-ctr.txt4
-rw-r--r--tests/primitives/vectors/OpenSSL/AES/aes-256-ctr.txt5
-rw-r--r--tests/test_utils.py364
-rw-r--r--tests/utils.py39
-rw-r--r--tox.ini7
45 files changed, 1253 insertions, 367 deletions
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 00000000..398ff08a
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,2 @@
+[run]
+branch = True
diff --git a/.gitignore b/.gitignore
index ecf07a08..5d187cfe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ cffi-*.egg/
pycparser-*.egg/
pytest-*.egg/
dist/
+htmlcov/
diff --git a/AUTHORS.rst b/AUTHORS.rst
index 1aa37e48..b3b7f35d 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -1,7 +1,9 @@
AUTHORS
=======
-* Alex Gaynor <alex.gaynor@gmail.com>
+PGP key fingerprints are enclosed in parentheses.
+
+* Alex Gaynor <alex.gaynor@gmail.com> (E27D 4AA0 1651 72CB C5D2 AF2B 125F 5C67 DFE9 4084)
* Hynek Schlawack <hs@ox.cx>
* Donald Stufft <donald@stufft.io>
* Laurens Van Houtven <_@lvh.io>
diff --git a/README.rst b/README.rst
index 9188106e..01f3eadd 100644
--- a/README.rst
+++ b/README.rst
@@ -1,11 +1,11 @@
Cryptography
============
-.. image:: https://travis-ci.org/alex/cryptography.png?branch=master
- :target: https://travis-ci.org/alex/cryptography
+.. image:: https://travis-ci.org/pyca/cryptography.png?branch=master
+ :target: https://travis-ci.org/pyca/cryptography
-.. image:: https://coveralls.io/repos/alex/cryptography/badge.png?branch=master
- :target: https://coveralls.io/r/alex/cryptography?branch=master
+.. image:: https://coveralls.io/repos/pyca/cryptography/badge.png?branch=master
+ :target: https://coveralls.io/r/pyca/cryptography?branch=master
``cryptography`` is a package designed to expose cryptographic primitives and
recipes to Python developers.
@@ -16,3 +16,12 @@ yet. It targets Python 2.6-2.7, Python 3.2+, as well as PyPy.
You can find more documentation at `Read The Docs`_.
.. _`Read The Docs`: https://cryptography.readthedocs.org/
+
+Discussion
+~~~~~~~~~~
+
+We maintain a `cryptography-dev`_ mailing list for development discussion.
+
+You can also join #cryptography-dev on Freenode to ask questions or get involved.
+
+.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev
diff --git a/cryptography/__about__.py b/cryptography/__about__.py
index 6499ff2b..e5eca6c6 100644
--- a/cryptography/__about__.py
+++ b/cryptography/__about__.py
@@ -20,7 +20,7 @@ __all__ = [
__title__ = "cryptography"
__summary__ = ("cryptography is a package designed to expose cryptographic "
"primitives and recipes to Python developers.")
-__uri__ = "https://github.com/alex/cryptography"
+__uri__ = "https://github.com/pyca/cryptography"
__version__ = "0.1.dev1"
diff --git a/cryptography/bindings/__init__.py b/cryptography/bindings/__init__.py
index e69de29b..215f17c7 100644
--- a/cryptography/bindings/__init__.py
+++ b/cryptography/bindings/__init__.py
@@ -0,0 +1,20 @@
+# 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 cryptography.bindings import openssl
+
+
+_default_api = openssl.api
+_ALL_APIS = [
+ openssl.api
+]
diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py
index 28437576..79ec5eea 100644
--- a/cryptography/bindings/openssl/api.py
+++ b/cryptography/bindings/openssl/api.py
@@ -25,26 +25,58 @@ class API(object):
OpenSSL API wrapper.
"""
_modules = [
+ "bignum",
+ "bio",
+ "conf",
+ "crypto",
+ "dh",
+ "dsa",
+ "engine",
+ "err",
"evp",
"opensslv",
+ "rand",
+ "rsa",
+ "ssl",
]
def __init__(self):
self.ffi = cffi.FFI()
includes = []
+ functions = []
+ macros = []
for name in self._modules:
__import__("cryptography.bindings.openssl." + name)
module = sys.modules["cryptography.bindings.openssl." + name]
self.ffi.cdef(module.TYPES)
- self.ffi.cdef(module.FUNCTIONS)
+
+ macros.append(module.MACROS)
+ functions.append(module.FUNCTIONS)
includes.append(module.INCLUDES)
+ # loop over the functions & macros after declaring all the types
+ # so we can set interdependent types in different files and still
+ # have them all defined before we parse the funcs & macros
+ for func in functions:
+ self.ffi.cdef(func)
+ for macro in macros:
+ self.ffi.cdef(macro)
+
+ # We include functions here so that if we got any of their definitions
+ # wrong, the underlying C compiler will explode. In C you are allowed
+ # to re-declare a function if it has the same signature. That is:
+ # int foo(int);
+ # int foo(int);
+ # is legal, but the following will fail to compile:
+ # int foo(int);
+ # int foo(short);
self.lib = self.ffi.verify(
- source="\n".join(includes),
- libraries=["crypto"]
+ source="\n".join(includes + functions),
+ libraries=["crypto", "ssl"],
)
self.lib.OpenSSL_add_all_algorithms()
+ self.lib.SSL_load_error_strings()
def openssl_version_text(self):
"""
@@ -54,6 +86,10 @@ class API(object):
"""
return self.ffi.string(self.lib.OPENSSL_VERSION_TEXT).decode("ascii")
+ def supports_cipher(self, ciphername):
+ return (self.ffi.NULL !=
+ self.lib.EVP_get_cipherbyname(ciphername.encode("ascii")))
+
def create_block_cipher_context(self, cipher, mode):
ctx = self.ffi.new("EVP_CIPHER_CTX *")
res = self.lib.EVP_CIPHER_CTX_init(ctx)
@@ -62,11 +98,13 @@ class API(object):
# TODO: compute name using a better algorithm
ciphername = "{0}-{1}-{2}".format(
cipher.name, cipher.key_size, mode.name
- )
+ ).lower()
evp_cipher = self.lib.EVP_get_cipherbyname(ciphername.encode("ascii"))
assert evp_cipher != self.ffi.NULL
if isinstance(mode, interfaces.ModeWithInitializationVector):
iv_nonce = mode.initialization_vector
+ elif isinstance(mode, interfaces.ModeWithNonce):
+ iv_nonce = mode.nonce
else:
iv_nonce = self.ffi.NULL
diff --git a/cryptography/bindings/openssl/bignum.py b/cryptography/bindings/openssl/bignum.py
new file mode 100644
index 00000000..72d467c3
--- /dev/null
+++ b/cryptography/bindings/openssl/bignum.py
@@ -0,0 +1,34 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/bn.h>
+"""
+
+TYPES = """
+typedef ... BIGNUM;
+typedef ... BN_ULONG;
+"""
+
+FUNCTIONS = """
+BIGNUM *BN_new();
+void BN_free(BIGNUM *);
+
+int BN_set_word(BIGNUM *, BN_ULONG);
+
+char *BN_bn2hex(const BIGNUM *);
+int BN_hex2bn(BIGNUM **, const char *);
+"""
+
+MACROS = """
+"""
diff --git a/cryptography/bindings/openssl/bio.py b/cryptography/bindings/openssl/bio.py
new file mode 100644
index 00000000..88be788f
--- /dev/null
+++ b/cryptography/bindings/openssl/bio.py
@@ -0,0 +1,170 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/bio.h>
+"""
+
+TYPES = """
+typedef struct bio_st BIO;
+typedef void bio_info_cb(BIO *, int, const char *, int, long, long);
+struct bio_method_st {
+ int type;
+ const char *name;
+ int (*bwrite)(BIO *, const char *, int);
+ int (*bread)(BIO *, char *, int);
+ int (*bputs)(BIO *, const char *);
+ int (*bgets)(BIO *, char*, int);
+ long (*ctrl)(BIO *, int, long, void *);
+ int (*create)(BIO *);
+ int (*destroy)(BIO *);
+ long (*callback_ctrl)(BIO *, int, bio_info_cb *);
+ ...;
+};
+typedef struct bio_method_st BIO_METHOD;
+struct bio_st {
+ BIO_METHOD *method;
+ long (*callback)(struct bio_st*, int, const char*, int, long, long);
+ char *cb_arg;
+ int init;
+ int shutdown;
+ int flags;
+ int retry_reason;
+ int num;
+ void *ptr;
+ struct bio_st *next_bio;
+ struct bio_st *prev_bio;
+ int references;
+ unsigned long num_read;
+ unsigned long num_write;
+ ...;
+};
+typedef ... BUF_MEM;
+"""
+
+FUNCTIONS = """
+BIO* BIO_new(BIO_METHOD *);
+int BIO_set(BIO *, BIO_METHOD *);
+int BIO_free(BIO *);
+void BIO_vfree(BIO *);
+void BIO_free_all(BIO *);
+BIO *BIO_push(BIO *, BIO *);
+BIO *BIO_pop(BIO *);
+BIO *BIO_next(BIO *);
+BIO *BIO_find_type(BIO *, int);
+int BIO_method_type(const BIO *);
+BIO_METHOD *BIO_s_mem();
+BIO *BIO_new_mem_buf(void *, int);
+BIO_METHOD *BIO_s_file();
+BIO *BIO_new_file(const char *, const char *);
+BIO *BIO_new_fp(FILE *, int);
+BIO_METHOD *BIO_s_fd();
+BIO *BIO_new_fd(int, int);
+BIO_METHOD *BIO_s_socket();
+BIO *BIO_new_socket(int, int);
+BIO_METHOD *BIO_s_null();
+long BIO_ctrl(BIO *, int, long, void *);
+long BIO_callback_ctrl(
+ BIO *,
+ int,
+ void (*)(struct bio_st *, int, const char *, int, long, long)
+);
+char* BIO_ptr_ctrl(BIO *bp, int cmd, long larg);
+long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg);
+size_t BIO_ctrl_pending(BIO *b);
+size_t BIO_ctrl_wpending(BIO *b);
+int BIO_read(BIO *, void *, int);
+int BIO_gets(BIO *, char *, int);
+int BIO_write(BIO *, const void *, int);
+int BIO_puts(BIO *, const char *);
+BIO_METHOD *BIO_f_null();
+BIO_METHOD *BIO_f_buffer();
+"""
+
+MACROS = """
+long BIO_set_fd(BIO *, long, int);
+long BIO_get_fd(BIO *, char *);
+long BIO_set_mem_eof_return(BIO *, int);
+long BIO_get_mem_data(BIO *, char **);
+long BIO_set_mem_buf(BIO *, BUF_MEM *, int);
+long BIO_get_mem_ptr(BIO *, BUF_MEM **);
+long BIO_set_fp(BIO *, FILE *, int);
+long BIO_get_fp(BIO *, FILE **);
+int BIO_read_filename(BIO *, char *);
+int BIO_write_filename(BIO *, char *);
+int BIO_append_filename(BIO *, char *);
+int BIO_rw_filename(BIO *, char *);
+int BIO_should_read(BIO *);
+int BIO_should_write(BIO *);
+int BIO_should_io_special(BIO *);
+int BIO_retry_type(BIO *);
+int BIO_should_retry(BIO *);
+int BIO_reset(BIO *);
+int BIO_seek(BIO *, int);
+int BIO_tell(BIO *);
+int BIO_flush(BIO *);
+int BIO_eof(BIO *);
+int BIO_set_close(BIO *,long);
+int BIO_get_close(BIO *);
+int BIO_pending(BIO *);
+int BIO_wpending(BIO *);
+int BIO_get_info_callback(BIO *, bio_info_cb **);
+int BIO_set_info_callback(BIO *, bio_info_cb *);
+long BIO_get_buffer_num_lines(BIO *);
+long BIO_set_read_buffer_size(BIO *, long);
+long BIO_set_write_buffer_size(BIO *, long);
+long BIO_set_buffer_size(BIO *, long);
+long BIO_set_buffer_read_data(BIO *, void *, long);
+#define BIO_TYPE_MEM ...
+#define BIO_TYPE_FILE ...
+#define BIO_TYPE_FD ...
+#define BIO_TYPE_SOCKET ...
+#define BIO_TYPE_CONNECT ...
+#define BIO_TYPE_ACCEPT ...
+#define BIO_TYPE_NULL ...
+#define BIO_CLOSE ...
+#define BIO_NOCLOSE ...
+#define BIO_TYPE_SOURCE_SINK ...
+#define BIO_CTRL_RESET ...
+#define BIO_CTRL_EOF ...
+#define BIO_CTRL_SET ...
+#define BIO_CTRL_SET_CLOSE ...
+#define BIO_CTRL_FLUSH ...
+#define BIO_CTRL_DUP ...
+#define BIO_CTRL_GET_CLOSE ...
+#define BIO_CTRL_INFO ...
+#define BIO_CTRL_GET ...
+#define BIO_CTRL_PENDING ...
+#define BIO_CTRL_WPENDING ...
+#define BIO_C_FILE_SEEK ...
+#define BIO_C_FILE_TELL ...
+#define BIO_TYPE_NONE ...
+#define BIO_TYPE_PROXY_CLIENT ...
+#define BIO_TYPE_PROXY_SERVER ...
+#define BIO_TYPE_NBIO_TEST ...
+#define BIO_TYPE_BER ...
+#define BIO_TYPE_BIO ...
+#define BIO_TYPE_DESCRIPTOR ...
+#define BIO_FLAGS_READ ...
+#define BIO_FLAGS_WRITE ...
+#define BIO_FLAGS_IO_SPECIAL ...
+#define BIO_FLAGS_RWS ...
+#define BIO_FLAGS_SHOULD_RETRY ...
+#define BIO_TYPE_NULL_FILTER ...
+#define BIO_TYPE_SSL ...
+#define BIO_TYPE_MD ...
+#define BIO_TYPE_BUFFER ...
+#define BIO_TYPE_CIPHER ...
+#define BIO_TYPE_BASE64 ...
+#define BIO_TYPE_FILTER ...
+"""
diff --git a/cryptography/bindings/openssl/conf.py b/cryptography/bindings/openssl/conf.py
new file mode 100644
index 00000000..85c7a210
--- /dev/null
+++ b/cryptography/bindings/openssl/conf.py
@@ -0,0 +1,26 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/conf.h>
+"""
+
+TYPES = """
+typedef ... CONF;
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+"""
diff --git a/cryptography/bindings/openssl/crypto.py b/cryptography/bindings/openssl/crypto.py
new file mode 100644
index 00000000..501fb5a1
--- /dev/null
+++ b/cryptography/bindings/openssl/crypto.py
@@ -0,0 +1,37 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/crypto.h>
+"""
+
+TYPES = """
+"""
+
+FUNCTIONS = """
+void CRYPTO_free(void *);
+int CRYPTO_mem_ctrl(int);
+int CRYPTO_is_mem_check_on();
+void CRYPTO_mem_leaks(struct bio_st *);
+void CRYPTO_cleanup_all_ex_data();
+"""
+
+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 ...
+#define CRYPTO_MEM_CHECK_DISABLE ...
+"""
diff --git a/cryptography/bindings/openssl/dh.py b/cryptography/bindings/openssl/dh.py
new file mode 100644
index 00000000..ac130054
--- /dev/null
+++ b/cryptography/bindings/openssl/dh.py
@@ -0,0 +1,28 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/dh.h>
+"""
+
+TYPES = """
+typedef ... DH;
+"""
+
+FUNCTIONS = """
+DH *DH_new();
+void DH_free(DH *);
+"""
+
+MACROS = """
+"""
diff --git a/cryptography/bindings/openssl/dsa.py b/cryptography/bindings/openssl/dsa.py
new file mode 100644
index 00000000..2fa67b87
--- /dev/null
+++ b/cryptography/bindings/openssl/dsa.py
@@ -0,0 +1,30 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/dsa.h>
+"""
+
+TYPES = """
+typedef ... DSA;
+"""
+
+FUNCTIONS = """
+DSA *DSA_generate_parameters(int, unsigned char *, int, int *, unsigned long *,
+ void (*)(int, int, void *), void *);
+int DSA_generate_key(DSA *);
+void DSA_free(DSA *);
+"""
+
+MACROS = """
+"""
diff --git a/cryptography/bindings/openssl/engine.py b/cryptography/bindings/openssl/engine.py
new file mode 100644
index 00000000..b3ec3125
--- /dev/null
+++ b/cryptography/bindings/openssl/engine.py
@@ -0,0 +1,52 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/engine.h>
+"""
+
+TYPES = """
+typedef ... ENGINE;
+"""
+
+FUNCTIONS = """
+ENGINE *ENGINE_get_first();
+ENGINE *ENGINE_get_last();
+ENGINE *ENGINE_get_next(ENGINE *);
+ENGINE *ENGINE_get_prev(ENGINE *);
+int ENGINE_add(ENGINE *);
+int ENGINE_remove(ENGINE *);
+ENGINE *ENGINE_by_id(const char *);
+int ENGINE_init(ENGINE *);
+int ENGINE_finish(ENGINE *);
+int ENGINE_free(ENGINE *);
+void ENGINE_cleanup();
+void ENGINE_load_dynamic();
+void ENGINE_load_builtin_engines();
+int ENGINE_ctrl_cmd_string(ENGINE *, const char *, const char *, int);
+int ENGINE_set_default(ENGINE *, unsigned int);
+int ENGINE_register_complete(ENGINE *);
+"""
+
+MACROS = """
+#define ENGINE_METHOD_RSA ...
+#define ENGINE_METHOD_DSA ...
+#define ENGINE_METHOD_RAND ...
+#define ENGINE_METHOD_ECDH ...
+#define ENGINE_METHOD_ECDSA ...
+#define ENGINE_METHOD_CIPHERS ...
+#define ENGINE_METHOD_DIGESTS ...
+#define ENGINE_METHOD_STORE ...
+#define ENGINE_METHOD_ALL ...
+#define ENGINE_METHOD_NONE ...
+"""
diff --git a/cryptography/bindings/openssl/err.py b/cryptography/bindings/openssl/err.py
new file mode 100644
index 00000000..76c34a03
--- /dev/null
+++ b/cryptography/bindings/openssl/err.py
@@ -0,0 +1,54 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/err.h>
+"""
+
+TYPES = """
+struct ERR_string_data_st {
+ unsigned long error;
+ const char *string;
+};
+typedef struct ERR_string_data_st ERR_STRING_DATA;
+"""
+
+FUNCTIONS = """
+void ERR_load_crypto_strings();
+void ERR_free_strings();
+char* ERR_error_string(unsigned long, char *);
+void ERR_error_string_n(unsigned long, char *, size_t);
+const char* ERR_lib_error_string(unsigned long);
+const char* ERR_func_error_string(unsigned long);
+const char* ERR_reason_error_string(unsigned long);
+void ERR_print_errors(BIO *);
+void ERR_print_errors_fp(FILE *);
+unsigned long ERR_get_error();
+unsigned long ERR_peek_error();
+unsigned long ERR_peek_last_error();
+unsigned long ERR_get_error_line(const char **, int *);
+unsigned long ERR_peek_error_line(const char **, int *);
+unsigned long ERR_peek_last_error_line(const char **, int *);
+unsigned long ERR_get_error_line_data(const char **, int *,
+ const char **, int *);
+unsigned long ERR_peek_error_line_data(const char **,
+ int *, const char **, int *);
+unsigned long ERR_peek_last_error_line_data(const char **,
+ int *, const char **, int *);
+void ERR_put_error(int, int, int, const char *, int);
+void ERR_add_error_data(int, ...);
+int ERR_get_next_error_library();
+"""
+
+MACROS = """
+"""
diff --git a/cryptography/bindings/openssl/evp.py b/cryptography/bindings/openssl/evp.py
index 0bc5cffc..63364374 100644
--- a/cryptography/bindings/openssl/evp.py
+++ b/cryptography/bindings/openssl/evp.py
@@ -20,20 +20,22 @@ typedef struct {
...;
} EVP_CIPHER_CTX;
typedef ... EVP_CIPHER;
-typedef ... ENGINE;
"""
FUNCTIONS = """
void OpenSSL_add_all_algorithms();
const EVP_CIPHER *EVP_get_cipherbyname(const char *);
int EVP_EncryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *,
- unsigned char *, unsigned char *);
+ const unsigned char *, const unsigned char *);
int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int);
int EVP_EncryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *,
- unsigned char *, int);
+ const unsigned char *, int);
int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *);
int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *);
const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *);
int EVP_CIPHER_block_size(const EVP_CIPHER *);
void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *);
"""
+
+MACROS = """
+"""
diff --git a/cryptography/bindings/openssl/opensslv.py b/cryptography/bindings/openssl/opensslv.py
index 9b2db270..d1a1b3e6 100644
--- a/cryptography/bindings/openssl/opensslv.py
+++ b/cryptography/bindings/openssl/opensslv.py
@@ -21,3 +21,6 @@ static char *const OPENSSL_VERSION_TEXT;
FUNCTIONS = """
"""
+
+MACROS = """
+"""
diff --git a/cryptography/bindings/openssl/rand.py b/cryptography/bindings/openssl/rand.py
new file mode 100644
index 00000000..e4f6be23
--- /dev/null
+++ b/cryptography/bindings/openssl/rand.py
@@ -0,0 +1,37 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/rand.h>
+"""
+
+TYPES = """
+"""
+
+FUNCTIONS = """
+void RAND_seed(const void *, int);
+void RAND_add(const void *, int, double);
+int RAND_status();
+int RAND_egd(const char *);
+int RAND_egd_bytes(const char *, int);
+int RAND_query_egd_bytes(const char *, unsigned char *, int);
+const char *RAND_file_name(char *, size_t);
+int RAND_load_file(const char *, long);
+int RAND_write_file(const char *);
+void RAND_cleanup();
+int RAND_bytes(unsigned char *, int);
+int RAND_pseudo_bytes(unsigned char *, int);
+"""
+
+MACROS = """
+"""
diff --git a/cryptography/bindings/openssl/rsa.py b/cryptography/bindings/openssl/rsa.py
new file mode 100644
index 00000000..c8bf1cc0
--- /dev/null
+++ b/cryptography/bindings/openssl/rsa.py
@@ -0,0 +1,31 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/rsa.h>
+"""
+
+TYPES = """
+typedef ... RSA;
+typedef ... BN_GENCB;
+"""
+
+FUNCTIONS = """
+RSA *RSA_new();
+void RSA_free(RSA *);
+int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *);
+int RSA_check_key(const RSA *);
+"""
+
+MACROS = """
+"""
diff --git a/cryptography/bindings/openssl/ssl.py b/cryptography/bindings/openssl/ssl.py
new file mode 100644
index 00000000..8aca86e4
--- /dev/null
+++ b/cryptography/bindings/openssl/ssl.py
@@ -0,0 +1,26 @@
+# 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.
+
+INCLUDES = """
+#include <openssl/ssl.h>
+"""
+
+TYPES = """
+"""
+
+FUNCTIONS = """
+void SSL_load_error_strings();
+"""
+
+MACROS = """
+"""
diff --git a/cryptography/primitives/block/base.py b/cryptography/primitives/block/base.py
index b4137fd4..50e9e9e5 100644
--- a/cryptography/primitives/block/base.py
+++ b/cryptography/primitives/block/base.py
@@ -15,8 +15,7 @@ from __future__ import absolute_import, division, print_function
from enum import Enum
-# TODO: which binding is used should be an option somewhere
-from cryptography.bindings.openssl import api
+from cryptography.bindings import _default_api
class _Operation(Enum):
@@ -25,19 +24,18 @@ class _Operation(Enum):
class BlockCipher(object):
- def __init__(self, cipher, mode):
+ def __init__(self, cipher, mode, api=None):
super(BlockCipher, self).__init__()
+
+ if api is None:
+ api = _default_api
+
self.cipher = cipher
self.mode = mode
+ self._api = api
self._ctx = api.create_block_cipher_context(cipher, mode)
self._operation = None
- @property
- def name(self):
- return "{0}-{1}-{2}".format(
- self.cipher.name, self.cipher.key_size, self.mode.name,
- )
-
def encrypt(self, plaintext):
if self._ctx is None:
raise ValueError("BlockCipher was already finalized")
@@ -48,14 +46,14 @@ class BlockCipher(object):
raise ValueError("BlockCipher cannot encrypt when the operation is"
" set to %s" % self._operation.name)
- return api.update_encrypt_context(self._ctx, plaintext)
+ return self._api.update_encrypt_context(self._ctx, plaintext)
def finalize(self):
if self._ctx is None:
raise ValueError("BlockCipher was already finalized")
if self._operation is _Operation.encrypt:
- result = api.finalize_encrypt_context(self._ctx)
+ result = self._api.finalize_encrypt_context(self._ctx)
else:
raise ValueError("BlockCipher cannot finalize the unknown "
"operation %s" % self._operation.name)
diff --git a/cryptography/primitives/block/ciphers.py b/cryptography/primitives/block/ciphers.py
index cf54aa35..4ac150a4 100644
--- a/cryptography/primitives/block/ciphers.py
+++ b/cryptography/primitives/block/ciphers.py
@@ -17,7 +17,7 @@ from __future__ import absolute_import, division, print_function
class AES(object):
name = "AES"
block_size = 128
- key_sizes = set([128, 192, 256])
+ key_sizes = frozenset([128, 192, 256])
def __init__(self, key):
super(AES, self).__init__()
@@ -32,3 +32,23 @@ class AES(object):
@property
def key_size(self):
return len(self.key) * 8
+
+
+class Camellia(object):
+ name = "camellia"
+ block_size = 128
+ key_sizes = frozenset([128, 192, 256])
+
+ def __init__(self, key):
+ super(Camellia, self).__init__()
+ self.key = key
+
+ # Verify that the key size matches the expected key size
+ if self.key_size not in self.key_sizes:
+ raise ValueError("Invalid key size ({0}) for {1}".format(
+ self.key_size, self.name
+ ))
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
diff --git a/cryptography/primitives/block/modes.py b/cryptography/primitives/block/modes.py
index 9cfbca64..43631801 100644
--- a/cryptography/primitives/block/modes.py
+++ b/cryptography/primitives/block/modes.py
@@ -16,6 +16,14 @@ from __future__ import absolute_import, division, print_function
from cryptography.primitives import interfaces
+def register(iface):
+ def register_decorator(klass):
+ iface.register(klass)
+ return klass
+ return register_decorator
+
+
+@register(interfaces.ModeWithInitializationVector)
class CBC(object):
name = "CBC"
@@ -28,6 +36,7 @@ class ECB(object):
name = "ECB"
+@register(interfaces.ModeWithInitializationVector)
class OFB(object):
name = "OFB"
@@ -36,6 +45,7 @@ class OFB(object):
self.initialization_vector = initialization_vector
+@register(interfaces.ModeWithInitializationVector)
class CFB(object):
name = "CFB"
@@ -44,6 +54,10 @@ class CFB(object):
self.initialization_vector = initialization_vector
-interfaces.ModeWithInitializationVector.register(CBC)
-interfaces.ModeWithInitializationVector.register(OFB)
-interfaces.ModeWithInitializationVector.register(CFB)
+@register(interfaces.ModeWithNonce)
+class CTR(object):
+ name = "CTR"
+
+ def __init__(self, nonce):
+ super(CTR, self).__init__()
+ self.nonce = nonce
diff --git a/cryptography/primitives/interfaces.py b/cryptography/primitives/interfaces.py
index 6f74ccf7..c1fc9910 100644
--- a/cryptography/primitives/interfaces.py
+++ b/cryptography/primitives/interfaces.py
@@ -20,3 +20,7 @@ import six
class ModeWithInitializationVector(six.with_metaclass(abc.ABCMeta)):
pass
+
+
+class ModeWithNonce(six.with_metaclass(abc.ABCMeta)):
+ pass
diff --git a/dev-requirements.txt b/dev-requirements.txt
new file mode 100644
index 00000000..01030e87
--- /dev/null
+++ b/dev-requirements.txt
@@ -0,0 +1,5 @@
+flake8
+pretend
+pytest-cov
+sphinx
+tox
diff --git a/docs/bindings/openssl.rst b/docs/bindings/openssl.rst
index 79468cb4..241cc4d6 100644
--- a/docs/bindings/openssl.rst
+++ b/docs/bindings/openssl.rst
@@ -4,7 +4,7 @@ OpenSSL
.. warning::
The OpenSSL API is not easy to use, small mistakes can lead to significant
- security vulnerabilities. We strongly reccomend not using this directly,
+ security vulnerabilities. We strongly recommend not using this directly,
and instead using one of the higher level APIs exposed by ``cryptography``.
diff --git a/docs/community.rst b/docs/community.rst
index 809ffd12..86ba5055 100644
--- a/docs/community.rst
+++ b/docs/community.rst
@@ -10,6 +10,6 @@ You can find ``cryptography`` all over the web:
* IRC: ``#cryptography-dev`` on ``irc.freenode.net``
.. _`Mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev
-.. _`Source code`: https://github.com/alex/cryptography
-.. _`Issue tracker`: https://github.com/alex/cryptography/issues
+.. _`Source code`: https://github.com/pyca/cryptography
+.. _`Issue tracker`: https://github.com/pyca/cryptography/issues
.. _`Documentation`: https://cryptography.readthedocs.org/
diff --git a/docs/contributing.rst b/docs/contributing.rst
index b4c72ba4..2d8fceeb 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -73,8 +73,81 @@ So, specifically:
- No blank line at the end.
- Use Sphinx parameter/attribute documentation `syntax`_.
+Development Environment
+-----------------------
-.. _`GitHub`: https://github.com/alex/cryptography
+Working on ``cryptography`` requires the installation of a small number of
+development dependencies. These are listed in ``dev-requirements.txt`` and they
+can be installed in a `virtualenv`_ using `pip`_. Once you've installed the
+dependencies, install ``cryptography`` in ``editable`` mode. For example:
+
+.. code-block:: console
+
+ $ # Create a virtualenv and activate it
+ $ pip install --requirement dev-requirements.txt
+ $ pip install --editable .
+
+You are now ready to run the tests and build the documentation.
+
+Running Tests
+-------------
+
+``cryptography`` unit tests are found in the ``tests/`` directory and are
+designed to be run using `pytest`_. `pytest`_ will discover the tests
+automatically, so all you have to do is:
+
+.. code-block:: console
+
+ $ py.test
+ ...
+ 4294 passed in 15.24 seconds
+
+This runs the tests with the default Python interpreter.
+
+You can also verify that the tests pass on other supported Python interpreters.
+For this we use `tox`_, which will automatically create a `virtualenv`_ for
+each supported Python version and run the tests. For example:
+
+.. code-block:: console
+
+ $ tox
+ ...
+ ERROR: py26: InterpreterNotFound: python2.6
+ py27: commands succeeded
+ ERROR: pypy: InterpreterNotFound: pypy
+ ERROR: py32: InterpreterNotFound: python3.2
+ py33: commands succeeded
+ docs: commands succeeded
+ pep8: commands succeeded
+
+You may not have all the required Python versions installed, in which case you
+will see one or more ``InterpreterNotFound`` errors.
+
+Building Documentation
+----------------------
+
+``cryptography`` documentation is stored in the ``docs/`` directory. It is
+written in `reStructured Text`_ and rendered using `Sphinx`_.
+
+Use `tox`_ to build the documentation. For example:
+
+.. code-block:: console
+
+ $ tox -e docs
+ ...
+ docs: commands succeeded
+ congratulations :)
+
+The HTML documentation index can now be found at ``docs/_build/html/index.html``
+
+
+.. _`GitHub`: https://github.com/pyca/cryptography
.. _`our mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev
.. _`PEP 8`: http://www.peps.io/8/
.. _`syntax`: http://sphinx-doc.org/domains.html#info-field-lists
+.. _`pytest`: https://pypi.python.org/pypi/pytest
+.. _`tox`: https://pypi.python.org/pypi/tox
+.. _`virtualenv`: https://pypi.python.org/pypi/virtualenv
+.. _`pip`: https://pypi.python.org/pypi/pip
+.. _`sphinx`: https://pypi.python.org/pypi/sphinx
+.. _`reStructured Text`: http://docutils.sourceforge.net/rst.html
diff --git a/docs/primitives/symmetric-encryption.rst b/docs/primitives/symmetric-encryption.rst
index 46d7c07c..7899e67d 100644
--- a/docs/primitives/symmetric-encryption.rst
+++ b/docs/primitives/symmetric-encryption.rst
@@ -51,6 +51,15 @@ Ciphers
:param bytes key: The secret key, either ``128``, ``192``, or ``256`` bits.
This must be kept secret.
+.. class:: cryptography.primitives.block.ciphers.Camellia(key)
+
+ Camellia is a block cipher approved for use by CRYPTREC and ISO/IEC.
+ It is considered to have comparable security and performance to AES, but
+ is not as widely studied or deployed.
+
+ :param bytes key: The secret key, either ``128``, ``192``, or ``256`` bits.
+ This must be kept secret.
+
Modes
~~~~~
@@ -68,6 +77,25 @@ Modes
reuse an ``initialization_vector`` with
a given ``key``.
+
+.. class:: cryptography.primitives.block.modes.CTR(nonce)
+
+ .. warning::
+
+ Counter mode is not recommended for use with block ciphers that have a
+ block size of less than 128-bits.
+
+ CTR (Counter) is a mode of operation for block ciphers. It is considered
+ cryptographically strong.
+
+ :param bytes nonce: Should be random bytes. It is critical to never reuse a
+ ``nonce`` with a given key. Any reuse of a nonce
+ with the same key compromises the security of every
+ message encrypted with that key. Must be the same
+ number of bytes as the ``block_size`` of the cipher
+ with a given key. The nonce does not need to be kept
+ secret and may be included alongside the ciphertext.
+
.. class:: cryptography.primitives.block.modes.OFB(initialization_vector)
OFB (Output Feedback) is a mode of operation for block ciphers. It
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 00000000..723735ac
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+addopts = -r s
diff --git a/tests/bindings/test_openssl.py b/tests/bindings/test_openssl.py
index b23c4ccc..e5b78d18 100644
--- a/tests/bindings/test_openssl.py
+++ b/tests/bindings/test_openssl.py
@@ -28,3 +28,6 @@ class TestOpenSSL(object):
for every OpenSSL.
"""
assert api.openssl_version_text().startswith("OpenSSL")
+
+ def test_supports_cipher(self):
+ assert api.supports_cipher("not-a-real-cipher") is False
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 00000000..b526f2bf
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,5 @@
+def pytest_generate_tests(metafunc):
+ from cryptography.bindings import _ALL_APIS
+
+ if "api" in metafunc.fixturenames:
+ metafunc.parametrize("api", _ALL_APIS)
diff --git a/tests/primitives/test_block.py b/tests/primitives/test_block.py
index 774409ca..f4d3f467 100644
--- a/tests/primitives/test_block.py
+++ b/tests/primitives/test_block.py
@@ -23,17 +23,17 @@ from cryptography.primitives.block.base import _Operation
class TestBlockCipher(object):
- def test_cipher_name(self):
- cipher = BlockCipher(
+ def test_instantiate_without_api(self):
+ BlockCipher(
ciphers.AES(binascii.unhexlify(b"0" * 32)),
modes.CBC(binascii.unhexlify(b"0" * 32))
)
- assert cipher.name == "AES-128-CBC"
- def test_use_after_finalize(self):
+ def test_use_after_finalize(self, api):
cipher = BlockCipher(
ciphers.AES(binascii.unhexlify(b"0" * 32)),
- modes.CBC(binascii.unhexlify(b"0" * 32))
+ modes.CBC(binascii.unhexlify(b"0" * 32)),
+ api
)
cipher.encrypt(b"a" * 16)
cipher.finalize()
@@ -42,20 +42,22 @@ class TestBlockCipher(object):
with pytest.raises(ValueError):
cipher.finalize()
- def test_encrypt_with_invalid_operation(self):
+ def test_encrypt_with_invalid_operation(self, api):
cipher = BlockCipher(
ciphers.AES(binascii.unhexlify(b"0" * 32)),
- modes.CBC(binascii.unhexlify(b"0" * 32))
+ modes.CBC(binascii.unhexlify(b"0" * 32)),
+ api
)
cipher._operation = _Operation.decrypt
with pytest.raises(ValueError):
cipher.encrypt(b"b" * 16)
- def test_finalize_with_invalid_operation(self):
+ def test_finalize_with_invalid_operation(self, api):
cipher = BlockCipher(
ciphers.AES(binascii.unhexlify(b"0" * 32)),
- modes.CBC(binascii.unhexlify(b"0" * 32))
+ modes.CBC(binascii.unhexlify(b"0" * 32)),
+ api
)
cipher._operation = pretend.stub(name="wat")
diff --git a/tests/primitives/test_ciphers.py b/tests/primitives/test_ciphers.py
index 5ee9f223..27d35850 100644
--- a/tests/primitives/test_ciphers.py
+++ b/tests/primitives/test_ciphers.py
@@ -17,7 +17,7 @@ import binascii
import pytest
-from cryptography.primitives.block.ciphers import AES
+from cryptography.primitives.block.ciphers import AES, Camellia
class TestAES(object):
@@ -33,3 +33,18 @@ class TestAES(object):
def test_invalid_key_size(self):
with pytest.raises(ValueError):
AES(binascii.unhexlify(b"0" * 12))
+
+
+class TestCamellia(object):
+ @pytest.mark.parametrize(("key", "keysize"), [
+ (b"0" * 32, 128),
+ (b"0" * 48, 192),
+ (b"0" * 64, 256),
+ ])
+ def test_key_size(self, key, keysize):
+ cipher = Camellia(binascii.unhexlify(key))
+ assert cipher.key_size == keysize
+
+ def test_invalid_key_size(self):
+ with pytest.raises(ValueError):
+ Camellia(binascii.unhexlify(b"0" * 12))
diff --git a/tests/primitives/test_cryptrec.py b/tests/primitives/test_cryptrec.py
new file mode 100644
index 00000000..edf97652
--- /dev/null
+++ b/tests/primitives/test_cryptrec.py
@@ -0,0 +1,42 @@
+# 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.
+
+"""
+Tests using the CRYPTREC (Camellia) Test Vectors
+"""
+
+from __future__ import absolute_import, division, print_function
+
+import binascii
+import os
+
+from cryptography.primitives.block import ciphers, modes
+
+from .utils import generate_encrypt_test
+from ..utils import load_cryptrec_vectors_from_file
+
+
+class TestCamelliaECB(object):
+ test_NTT = generate_encrypt_test(
+ load_cryptrec_vectors_from_file,
+ os.path.join("Camellia", "NTT"),
+ [
+ "camellia-128-ecb.txt",
+ "camellia-192-ecb.txt",
+ "camellia-256-ecb.txt"
+ ],
+ lambda key: ciphers.Camellia(binascii.unhexlify((key))),
+ lambda key: modes.ECB(),
+ only_if=lambda api: api.supports_cipher("camellia-128-ecb"),
+ skip_message="Does not support Camellia ECB",
+ )
diff --git a/tests/primitives/test_nist.py b/tests/primitives/test_nist.py
index 1e5d2396..d97b207b 100644
--- a/tests/primitives/test_nist.py
+++ b/tests/primitives/test_nist.py
@@ -18,33 +18,18 @@ Test using the NIST Test Vectors
from __future__ import absolute_import, division, print_function
import binascii
-import itertools
import os
-import pytest
-
-from cryptography.primitives.block import BlockCipher, ciphers, modes
+from cryptography.primitives.block import ciphers, modes
+from .utils import generate_encrypt_test
from ..utils import load_nist_vectors_from_file
-def parameterize_encrypt_test(cipher, vector_type, params, fnames):
- return pytest.mark.parametrize(params,
- list(itertools.chain.from_iterable(
- load_nist_vectors_from_file(
- os.path.join(cipher, vector_type, fname),
- "ENCRYPT",
- params
- )
- for fname in fnames
- ))
- )
-
-
class TestAES_CBC(object):
- @parameterize_encrypt_test(
- "AES", "KAT",
- ("key", "iv", "plaintext", "ciphertext"),
+ test_KAT = generate_encrypt_test(
+ lambda path: load_nist_vectors_from_file(path, "ENCRYPT"),
+ os.path.join("AES", "KAT"),
[
"CBCGFSbox128.rsp",
"CBCGFSbox192.rsp",
@@ -58,40 +43,28 @@ class TestAES_CBC(object):
"CBCVarTxt128.rsp",
"CBCVarTxt192.rsp",
"CBCVarTxt256.rsp",
- ]
+ ],
+ lambda key, iv: ciphers.AES(binascii.unhexlify(key)),
+ lambda key, iv: modes.CBC(binascii.unhexlify(iv)),
)
- def test_KAT(self, key, iv, plaintext, ciphertext):
- cipher = BlockCipher(
- ciphers.AES(binascii.unhexlify(key)),
- modes.CBC(binascii.unhexlify(iv)),
- )
- actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext))
- actual_ciphertext += cipher.finalize()
- assert binascii.hexlify(actual_ciphertext) == ciphertext
-
- @parameterize_encrypt_test(
- "AES", "MMT",
- ("key", "iv", "plaintext", "ciphertext"),
+
+ test_MMT = generate_encrypt_test(
+ lambda path: load_nist_vectors_from_file(path, "ENCRYPT"),
+ os.path.join("AES", "MMT"),
[
"CBCMMT128.rsp",
"CBCMMT192.rsp",
"CBCMMT256.rsp",
- ]
+ ],
+ lambda key, iv: ciphers.AES(binascii.unhexlify(key)),
+ lambda key, iv: modes.CBC(binascii.unhexlify(iv)),
)
- def test_MMT(self, key, iv, plaintext, ciphertext):
- cipher = BlockCipher(
- ciphers.AES(binascii.unhexlify(key)),
- modes.CBC(binascii.unhexlify(iv)),
- )
- actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext))
- actual_ciphertext += cipher.finalize()
- assert binascii.hexlify(actual_ciphertext) == ciphertext
class TestAES_ECB(object):
- @parameterize_encrypt_test(
- "AES", "KAT",
- ("key", "plaintext", "ciphertext"),
+ test_KAT = generate_encrypt_test(
+ lambda path: load_nist_vectors_from_file(path, "ENCRYPT"),
+ os.path.join("AES", "KAT"),
[
"ECBGFSbox128.rsp",
"ECBGFSbox192.rsp",
@@ -105,40 +78,28 @@ class TestAES_ECB(object):
"ECBVarTxt128.rsp",
"ECBVarTxt192.rsp",
"ECBVarTxt256.rsp",
- ]
+ ],
+ lambda key: ciphers.AES(binascii.unhexlify(key)),
+ lambda key: modes.ECB(),
)
- def test_KAT(self, key, plaintext, ciphertext):
- cipher = BlockCipher(
- ciphers.AES(binascii.unhexlify(key)),
- modes.ECB()
- )
- actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext))
- actual_ciphertext += cipher.finalize()
- assert binascii.hexlify(actual_ciphertext) == ciphertext
-
- @parameterize_encrypt_test(
- "AES", "MMT",
- ("key", "plaintext", "ciphertext"),
+
+ test_MMT = generate_encrypt_test(
+ lambda path: load_nist_vectors_from_file(path, "ENCRYPT"),
+ os.path.join("AES", "MMT"),
[
"ECBMMT128.rsp",
"ECBMMT192.rsp",
"ECBMMT256.rsp",
- ]
+ ],
+ lambda key: ciphers.AES(binascii.unhexlify(key)),
+ lambda key: modes.ECB(),
)
- def test_MMT(self, key, plaintext, ciphertext):
- cipher = BlockCipher(
- ciphers.AES(binascii.unhexlify(key)),
- modes.ECB()
- )
- actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext))
- actual_ciphertext += cipher.finalize()
- assert binascii.hexlify(actual_ciphertext) == ciphertext
class TestAES_OFB(object):
- @parameterize_encrypt_test(
- "AES", "KAT",
- ("key", "iv", "plaintext", "ciphertext"),
+ test_KAT = generate_encrypt_test(
+ lambda path: load_nist_vectors_from_file(path, "ENCRYPT"),
+ os.path.join("AES", "KAT"),
[
"OFBGFSbox128.rsp",
"OFBGFSbox192.rsp",
@@ -152,40 +113,28 @@ class TestAES_OFB(object):
"OFBVarTxt128.rsp",
"OFBVarTxt192.rsp",
"OFBVarTxt256.rsp",
- ]
+ ],
+ lambda key, iv: ciphers.AES(binascii.unhexlify(key)),
+ lambda key, iv: modes.OFB(binascii.unhexlify(iv)),
)
- def test_KAT(self, key, iv, plaintext, ciphertext):
- cipher = BlockCipher(
- ciphers.AES(binascii.unhexlify(key)),
- modes.OFB(binascii.unhexlify(iv))
- )
- actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext))
- actual_ciphertext += cipher.finalize()
- assert binascii.hexlify(actual_ciphertext) == ciphertext
-
- @parameterize_encrypt_test(
- "AES", "MMT",
- ("key", "iv", "plaintext", "ciphertext"),
+
+ test_MMT = generate_encrypt_test(
+ lambda path: load_nist_vectors_from_file(path, "ENCRYPT"),
+ os.path.join("AES", "MMT"),
[
"OFBMMT128.rsp",
"OFBMMT192.rsp",
"OFBMMT256.rsp",
- ]
+ ],
+ lambda key, iv: ciphers.AES(binascii.unhexlify(key)),
+ lambda key, iv: modes.OFB(binascii.unhexlify(iv)),
)
- def test_MMT(self, key, iv, plaintext, ciphertext):
- cipher = BlockCipher(
- ciphers.AES(binascii.unhexlify(key)),
- modes.OFB(binascii.unhexlify(iv))
- )
- actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext))
- actual_ciphertext += cipher.finalize()
- assert binascii.hexlify(actual_ciphertext) == ciphertext
class TestAES_CFB(object):
- @parameterize_encrypt_test(
- "AES", "KAT",
- ("key", "iv", "plaintext", "ciphertext"),
+ test_KAT = generate_encrypt_test(
+ lambda path: load_nist_vectors_from_file(path, "ENCRYPT"),
+ os.path.join("AES", "KAT"),
[
"CFB128GFSbox128.rsp",
"CFB128GFSbox192.rsp",
@@ -199,31 +148,19 @@ class TestAES_CFB(object):
"CFB128VarTxt128.rsp",
"CFB128VarTxt192.rsp",
"CFB128VarTxt256.rsp",
- ]
+ ],
+ lambda key, iv: ciphers.AES(binascii.unhexlify(key)),
+ lambda key, iv: modes.CFB(binascii.unhexlify(iv)),
)
- def test_KAT(self, key, iv, plaintext, ciphertext):
- cipher = BlockCipher(
- ciphers.AES(binascii.unhexlify(key)),
- modes.CFB(binascii.unhexlify(iv))
- )
- actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext))
- actual_ciphertext += cipher.finalize()
- assert binascii.hexlify(actual_ciphertext) == ciphertext
-
- @parameterize_encrypt_test(
- "AES", "MMT",
- ("key", "iv", "plaintext", "ciphertext"),
+
+ test_MMT = generate_encrypt_test(
+ lambda path: load_nist_vectors_from_file(path, "ENCRYPT"),
+ os.path.join("AES", "MMT"),
[
"CFB128MMT128.rsp",
"CFB128MMT192.rsp",
"CFB128MMT256.rsp",
- ]
+ ],
+ lambda key, iv: ciphers.AES(binascii.unhexlify(key)),
+ lambda key, iv: modes.CFB(binascii.unhexlify(iv)),
)
- def test_MMT(self, key, iv, plaintext, ciphertext):
- cipher = BlockCipher(
- ciphers.AES(binascii.unhexlify(key)),
- modes.CFB(binascii.unhexlify(iv))
- )
- actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext))
- actual_ciphertext += cipher.finalize()
- assert binascii.hexlify(actual_ciphertext) == ciphertext
diff --git a/tests/primitives/test_openssl_vectors.py b/tests/primitives/test_openssl_vectors.py
new file mode 100644
index 00000000..5b2be784
--- /dev/null
+++ b/tests/primitives/test_openssl_vectors.py
@@ -0,0 +1,73 @@
+# 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.
+
+"""
+Test using the OpenSSL Test Vectors
+"""
+
+from __future__ import absolute_import, division, print_function
+
+import binascii
+
+from cryptography.primitives.block import ciphers, modes
+
+from .utils import generate_encrypt_test
+from ..utils import load_openssl_vectors_from_file
+
+
+class TestCamelliaCBC(object):
+ test_OpenSSL = generate_encrypt_test(
+ load_openssl_vectors_from_file,
+ "Camellia",
+ ["camellia-cbc.txt"],
+ lambda key, iv: ciphers.Camellia(binascii.unhexlify(key)),
+ lambda key, iv: modes.CBC(binascii.unhexlify(iv)),
+ only_if=lambda api: api.supports_cipher("camellia-128-cbc"),
+ skip_message="Does not support Camellia CBC",
+ )
+
+
+class TestCamelliaOFB(object):
+ test_OpenSSL = generate_encrypt_test(
+ load_openssl_vectors_from_file,
+ "Camellia",
+ ["camellia-ofb.txt"],
+ lambda key, iv: ciphers.Camellia(binascii.unhexlify(key)),
+ lambda key, iv: modes.OFB(binascii.unhexlify(iv)),
+ only_if=lambda api: api.supports_cipher("camellia-128-ofb"),
+ skip_message="Does not support Camellia OFB",
+ )
+
+
+class TestCamelliaCFB(object):
+ test_OpenSSL = generate_encrypt_test(
+ load_openssl_vectors_from_file,
+ "Camellia",
+ ["camellia-cfb.txt"],
+ lambda key, iv: ciphers.Camellia(binascii.unhexlify(key)),
+ lambda key, iv: modes.CFB(binascii.unhexlify(iv)),
+ only_if=lambda api: api.supports_cipher("camellia-128-cfb"),
+ skip_message="Does not support Camellia CFB",
+ )
+
+
+class TestAESCTR(object):
+ test_OpenSSL = generate_encrypt_test(
+ load_openssl_vectors_from_file,
+ "AES",
+ ["aes-128-ctr.txt", "aes-192-ctr.txt", "aes-256-ctr.txt"],
+ lambda key, iv: ciphers.AES(binascii.unhexlify(key)),
+ lambda key, iv: modes.CTR(binascii.unhexlify(iv)),
+ only_if=lambda api: api.supports_cipher("aes-128-ctr"),
+ skip_message="Does not support AES CTR",
+ )
diff --git a/tests/primitives/test_utils.py b/tests/primitives/test_utils.py
new file mode 100644
index 00000000..4666ece7
--- /dev/null
+++ b/tests/primitives/test_utils.py
@@ -0,0 +1,14 @@
+import pytest
+
+from .utils import encrypt_test
+
+
+class TestEncryptTest(object):
+ def test_skips_if_only_if_returns_false(self):
+ with pytest.raises(pytest.skip.Exception) as exc_info:
+ encrypt_test(
+ None, None, None, None,
+ only_if=lambda api: False,
+ skip_message="message!"
+ )
+ assert exc_info.value.args[0] == "message!"
diff --git a/tests/primitives/utils.py b/tests/primitives/utils.py
new file mode 100644
index 00000000..3cf08c28
--- /dev/null
+++ b/tests/primitives/utils.py
@@ -0,0 +1,42 @@
+import binascii
+import os
+
+import pytest
+
+from cryptography.bindings import _ALL_APIS
+from cryptography.primitives.block import BlockCipher
+
+
+def generate_encrypt_test(param_loader, path, file_names, cipher_factory,
+ mode_factory, only_if=lambda api: True,
+ skip_message=None):
+ def test_encryption(self):
+ for api in _ALL_APIS:
+ for file_name in file_names:
+ for params in param_loader(os.path.join(path, file_name)):
+ yield (
+ encrypt_test,
+ api,
+ cipher_factory,
+ mode_factory,
+ params,
+ only_if,
+ skip_message
+ )
+ return test_encryption
+
+
+def encrypt_test(api, cipher_factory, mode_factory, params, only_if,
+ skip_message):
+ if not only_if(api):
+ pytest.skip(skip_message)
+ plaintext = params.pop("plaintext")
+ ciphertext = params.pop("ciphertext")
+ cipher = BlockCipher(
+ cipher_factory(**params),
+ mode_factory(**params),
+ api
+ )
+ actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext))
+ actual_ciphertext += cipher.finalize()
+ assert actual_ciphertext == binascii.unhexlify(ciphertext)
diff --git a/tests/primitives/vectors/OpenSSL/AES/aes-128-ctr.txt b/tests/primitives/vectors/OpenSSL/AES/aes-128-ctr.txt
new file mode 100644
index 00000000..f4ce15eb
--- /dev/null
+++ b/tests/primitives/vectors/OpenSSL/AES/aes-128-ctr.txt
@@ -0,0 +1,4 @@
+# AES Counter test vectors from RFC3686
+aes-128-ctr:AE6852F8121067CC4BF7A5765577F39E:00000030000000000000000000000001:53696E676C6520626C6F636B206D7367:E4095D4FB7A7B3792D6175A3261311B8:1
+aes-128-ctr:7E24067817FAE0D743D6CE1F32539163:006CB6DBC0543B59DA48D90B00000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:5104A106168A72D9790D41EE8EDAD388EB2E1EFC46DA57C8FCE630DF9141BE28:1
+aes-128-ctr:7691BE035E5020A8AC6E618529F9A0DC:00E0017B27777F3F4A1786F000000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:C1CF48A89F2FFDD9CF4652E9EFDB72D74540A42BDE6D7836D59A5CEAAEF3105325B2072F:1
diff --git a/tests/primitives/vectors/OpenSSL/AES/aes-192-ctr.txt b/tests/primitives/vectors/OpenSSL/AES/aes-192-ctr.txt
new file mode 100644
index 00000000..9e166fc4
--- /dev/null
+++ b/tests/primitives/vectors/OpenSSL/AES/aes-192-ctr.txt
@@ -0,0 +1,4 @@
+# AES Counter test vectors from RFC3686
+aes-192-ctr:16AF5B145FC9F579C175F93E3BFB0EED863D06CCFDB78515:0000004836733C147D6D93CB00000001:53696E676C6520626C6F636B206D7367:4B55384FE259C9C84E7935A003CBE928:1
+aes-192-ctr:7C5CB2401B3DC33C19E7340819E0F69C678C3DB8E6F6A91A:0096B03B020C6EADC2CB500D00000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:453243FC609B23327EDFAAFA7131CD9F8490701C5AD4A79CFC1FE0FF42F4FB00:1
+aes-192-ctr:02BF391EE8ECB159B959617B0965279BF59B60A786D3E0FE:0007BDFD5CBD60278DCC091200000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:96893FC55E5C722F540B7DD1DDF7E758D288BC95C69165884536C811662F2188ABEE0935:1
diff --git a/tests/primitives/vectors/OpenSSL/AES/aes-256-ctr.txt b/tests/primitives/vectors/OpenSSL/AES/aes-256-ctr.txt
new file mode 100644
index 00000000..d4998750
--- /dev/null
+++ b/tests/primitives/vectors/OpenSSL/AES/aes-256-ctr.txt
@@ -0,0 +1,5 @@
+# AES Counter test vectors from RFC3686
+aes-256-ctr:776BEFF2851DB06F4C8A0542C8696F6C6A81AF1EEC96B4D37FC1D689E6C1C104:00000060DB5672C97AA8F0B200000001:53696E676C6520626C6F636B206D7367:145AD01DBF824EC7560863DC71E3E0C0:1
+aes-256-ctr:F6D66D6BD52D59BB0796365879EFF886C66DD51A5B6A99744B50590C87A23884:00FAAC24C1585EF15A43D87500000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:F05E231B3894612C49EE000B804EB2A9B8306B508F839D6A5530831D9344AF1C:1
+aes-256-ctr:FF7A617CE69148E4F1726E2F43581DE2AA62D9F805532EDFF1EED687FB54153D:001CC5B751A51D70A1C1114800000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:EB6C52821D0BBBF7CE7594462ACA4FAAB407DF866569FD07F48CC0B583D6071F1EC0E6B8:1
+
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 73394a51..28e7407b 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -56,21 +56,19 @@ def test_load_nist_vectors_encrypt():
PLAINTEXT = 9798c4640bad75c7c3227db910174e72
""").splitlines()
- assert load_nist_vectors(vector_data, "ENCRYPT",
- ["key", "iv", "plaintext", "ciphertext"],
- ) == [
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"f34481ec3cc627bacd5dc3fb08f273e6",
- b"0336763e966d92595a567cc9ce537f5e",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"9798c4640bad75c7c3227db910174e72",
- b"a9a1631bf4996954ebc093957b234589",
- ),
+ assert load_nist_vectors(vector_data, "ENCRYPT") == [
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"f34481ec3cc627bacd5dc3fb08f273e6",
+ "ciphertext": b"0336763e966d92595a567cc9ce537f5e",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"9798c4640bad75c7c3227db910174e72",
+ "ciphertext": b"a9a1631bf4996954ebc093957b234589",
+ },
]
@@ -112,72 +110,69 @@ def test_load_nist_vectors_decrypt():
PLAINTEXT = 9798c4640bad75c7c3227db910174e72
""").splitlines()
- assert load_nist_vectors(vector_data, "DECRYPT",
- ["key", "iv", "ciphertext", "plaintext"],
- ) == [
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"0336763e966d92595a567cc9ce537f5e",
- b"f34481ec3cc627bacd5dc3fb08f273e6",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"a9a1631bf4996954ebc093957b234589",
- b"9798c4640bad75c7c3227db910174e72",
- ),
+ assert load_nist_vectors(vector_data, "DECRYPT") == [
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"f34481ec3cc627bacd5dc3fb08f273e6",
+ "ciphertext": b"0336763e966d92595a567cc9ce537f5e",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"9798c4640bad75c7c3227db910174e72",
+ "ciphertext": b"a9a1631bf4996954ebc093957b234589",
+ },
]
def test_load_nist_vectors_from_file_encrypt():
assert load_nist_vectors_from_file(
"AES/KAT/CBCGFSbox128.rsp",
- "ENCRYPT",
- ["key", "iv", "plaintext", "ciphertext"],
+ "ENCRYPT"
) == [
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"f34481ec3cc627bacd5dc3fb08f273e6",
- b"0336763e966d92595a567cc9ce537f5e",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"9798c4640bad75c7c3227db910174e72",
- b"a9a1631bf4996954ebc093957b234589",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"96ab5c2ff612d9dfaae8c31f30c42168",
- b"ff4f8391a6a40ca5b25d23bedd44a597",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"6a118a874519e64e9963798a503f1d35",
- b"dc43be40be0e53712f7e2bf5ca707209",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"cb9fceec81286ca3e989bd979b0cb284",
- b"92beedab1895a94faa69b632e5cc47ce",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"b26aeb1874e47ca8358ff22378f09144",
- b"459264f4798f6a78bacb89c15ed3d601",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"58c8e00b2631686d54eab84b91f0aca1",
- b"08a4e2efec8a8e3312ca7460b9040bbf",
- ),
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"f34481ec3cc627bacd5dc3fb08f273e6",
+ "ciphertext": b"0336763e966d92595a567cc9ce537f5e",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"9798c4640bad75c7c3227db910174e72",
+ "ciphertext": b"a9a1631bf4996954ebc093957b234589",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"96ab5c2ff612d9dfaae8c31f30c42168",
+ "ciphertext": b"ff4f8391a6a40ca5b25d23bedd44a597",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"6a118a874519e64e9963798a503f1d35",
+ "ciphertext": b"dc43be40be0e53712f7e2bf5ca707209",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"cb9fceec81286ca3e989bd979b0cb284",
+ "ciphertext": b"92beedab1895a94faa69b632e5cc47ce",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"b26aeb1874e47ca8358ff22378f09144",
+ "ciphertext": b"459264f4798f6a78bacb89c15ed3d601",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"58c8e00b2631686d54eab84b91f0aca1",
+ "ciphertext": b"08a4e2efec8a8e3312ca7460b9040bbf",
+ },
]
@@ -185,50 +180,49 @@ def test_load_nist_vectors_from_file_decrypt():
assert load_nist_vectors_from_file(
"AES/KAT/CBCGFSbox128.rsp",
"DECRYPT",
- ["key", "iv", "ciphertext", "plaintext"],
) == [
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"0336763e966d92595a567cc9ce537f5e",
- b"f34481ec3cc627bacd5dc3fb08f273e6",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"a9a1631bf4996954ebc093957b234589",
- b"9798c4640bad75c7c3227db910174e72",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"ff4f8391a6a40ca5b25d23bedd44a597",
- b"96ab5c2ff612d9dfaae8c31f30c42168",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"dc43be40be0e53712f7e2bf5ca707209",
- b"6a118a874519e64e9963798a503f1d35",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"92beedab1895a94faa69b632e5cc47ce",
- b"cb9fceec81286ca3e989bd979b0cb284",
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"459264f4798f6a78bacb89c15ed3d601",
- b"b26aeb1874e47ca8358ff22378f09144"
- ),
- (
- b"00000000000000000000000000000000",
- b"00000000000000000000000000000000",
- b"08a4e2efec8a8e3312ca7460b9040bbf",
- b"58c8e00b2631686d54eab84b91f0aca1"
- ),
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"f34481ec3cc627bacd5dc3fb08f273e6",
+ "ciphertext": b"0336763e966d92595a567cc9ce537f5e",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"9798c4640bad75c7c3227db910174e72",
+ "ciphertext": b"a9a1631bf4996954ebc093957b234589",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"96ab5c2ff612d9dfaae8c31f30c42168",
+ "ciphertext": b"ff4f8391a6a40ca5b25d23bedd44a597",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"6a118a874519e64e9963798a503f1d35",
+ "ciphertext": b"dc43be40be0e53712f7e2bf5ca707209",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"cb9fceec81286ca3e989bd979b0cb284",
+ "ciphertext": b"92beedab1895a94faa69b632e5cc47ce",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"b26aeb1874e47ca8358ff22378f09144",
+ "ciphertext": b"459264f4798f6a78bacb89c15ed3d601",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "iv": b"00000000000000000000000000000000",
+ "plaintext": b"58c8e00b2631686d54eab84b91f0aca1",
+ "ciphertext": b"08a4e2efec8a8e3312ca7460b9040bbf",
+ },
]
@@ -254,21 +248,21 @@ def test_load_cryptrec_vectors():
""").splitlines()
assert load_cryptrec_vectors(vector_data) == [
- (
- b"00000000000000000000000000000000",
- b"80000000000000000000000000000000",
- b"07923A39EB0A817D1C4D87BDB82D1F1C",
- ),
- (
- b"00000000000000000000000000000000",
- b"40000000000000000000000000000000",
- b"48CD6419809672D2349260D89A08D3D3",
- ),
- (
- b"10000000000000000000000000000000",
- b"80000000000000000000000000000000",
- b"07923A39EB0A817D1C4D87BDB82D1F1C",
- ),
+ {
+ "key": b"00000000000000000000000000000000",
+ "plaintext": b"80000000000000000000000000000000",
+ "ciphertext": b"07923A39EB0A817D1C4D87BDB82D1F1C",
+ },
+ {
+ "key": b"00000000000000000000000000000000",
+ "plaintext": b"40000000000000000000000000000000",
+ "ciphertext": b"48CD6419809672D2349260D89A08D3D3",
+ },
+ {
+ "key": b"10000000000000000000000000000000",
+ "plaintext": b"80000000000000000000000000000000",
+ "ciphertext": b"07923A39EB0A817D1C4D87BDB82D1F1C",
+ },
]
@@ -277,11 +271,11 @@ def test_load_cryptrec_vectors_from_file_encrypt():
"Camellia/NTT/camellia-128-ecb.txt"
)
assert test_set[0] == (
- (
- b"00000000000000000000000000000000",
- b"80000000000000000000000000000000",
- b"07923A39EB0A817D1C4D87BDB82D1F1C",
- )
+ {
+ "key": b"00000000000000000000000000000000",
+ "plaintext": b"80000000000000000000000000000000",
+ "ciphertext": b"07923A39EB0A817D1C4D87BDB82D1F1C",
+ }
)
assert len(test_set) == 1280
@@ -310,30 +304,30 @@ def test_load_openssl_vectors():
).splitlines()
assert load_openssl_vectors(vector_data) == [
- (
- b"2B7E151628AED2A6ABF7158809CF4F3C",
- b"000102030405060708090A0B0C0D0E0F",
- b"6BC1BEE22E409F96E93D7E117393172A",
- b"14F7646187817EB586599146B82BD719",
- ),
- (
- b"2B7E151628AED2A6ABF7158809CF4F3C",
- b"14F7646187817EB586599146B82BD719",
- b"AE2D8A571E03AC9C9EB76FAC45AF8E51",
- b"A53D28BB82DF741103EA4F921A44880B",
- ),
- (
- b"2B7E151628AED2A6ABF7158809CF4F3C",
- b"000102030405060708090A0B0C0D0E0F",
- b"6BC1BEE22E409F96E93D7E117393172A",
- b"14F7646187817EB586599146B82BD719",
- ),
- (
- b"2B7E151628AED2A6ABF7158809CF4F3C",
- b"14F7646187817EB586599146B82BD719",
- b"AE2D8A571E03AC9C9EB76FAC45AF8E51",
- b"A53D28BB82DF741103EA4F921A44880B",
- ),
+ {
+ "key": b"2B7E151628AED2A6ABF7158809CF4F3C",
+ "iv": b"000102030405060708090A0B0C0D0E0F",
+ "plaintext": b"6BC1BEE22E409F96E93D7E117393172A",
+ "ciphertext": b"14F7646187817EB586599146B82BD719",
+ },
+ {
+ "key": b"2B7E151628AED2A6ABF7158809CF4F3C",
+ "iv": b"14F7646187817EB586599146B82BD719",
+ "plaintext": b"AE2D8A571E03AC9C9EB76FAC45AF8E51",
+ "ciphertext": b"A53D28BB82DF741103EA4F921A44880B",
+ },
+ {
+ "key": b"2B7E151628AED2A6ABF7158809CF4F3C",
+ "iv": b"000102030405060708090A0B0C0D0E0F",
+ "plaintext": b"6BC1BEE22E409F96E93D7E117393172A",
+ "ciphertext": b"14F7646187817EB586599146B82BD719",
+ },
+ {
+ "key": b"2B7E151628AED2A6ABF7158809CF4F3C",
+ "iv": b"14F7646187817EB586599146B82BD719",
+ "plaintext": b"AE2D8A571E03AC9C9EB76FAC45AF8E51",
+ "ciphertext": b"A53D28BB82DF741103EA4F921A44880B",
+ },
]
@@ -341,28 +335,28 @@ def test_load_openssl_vectors_from_file():
test_list = load_openssl_vectors_from_file("Camellia/camellia-ofb.txt")
assert len(test_list) == 24
assert test_list[:4] == [
- (
- b"2B7E151628AED2A6ABF7158809CF4F3C",
- b"000102030405060708090A0B0C0D0E0F",
- b"6BC1BEE22E409F96E93D7E117393172A",
- b"14F7646187817EB586599146B82BD719",
- ),
- (
- b"2B7E151628AED2A6ABF7158809CF4F3C",
- b"50FE67CC996D32B6DA0937E99BAFEC60",
- b"AE2D8A571E03AC9C9EB76FAC45AF8E51",
- b"25623DB569CA51E01482649977E28D84",
- ),
- (
- b"2B7E151628AED2A6ABF7158809CF4F3C",
- b"D9A4DADA0892239F6B8B3D7680E15674",
- b"30C81C46A35CE411E5FBC1191A0A52EF",
- b"C776634A60729DC657D12B9FCA801E98",
- ),
- (
- b"2B7E151628AED2A6ABF7158809CF4F3C",
- b"A78819583F0308E7A6BF36B1386ABF23",
- b"F69F2445DF4F9B17AD2B417BE66C3710",
- b"D776379BE0E50825E681DA1A4C980E8E",
- ),
+ {
+ "key": b"2B7E151628AED2A6ABF7158809CF4F3C",
+ "iv": b"000102030405060708090A0B0C0D0E0F",
+ "plaintext": b"6BC1BEE22E409F96E93D7E117393172A",
+ "ciphertext": b"14F7646187817EB586599146B82BD719",
+ },
+ {
+ "key": b"2B7E151628AED2A6ABF7158809CF4F3C",
+ "iv": b"50FE67CC996D32B6DA0937E99BAFEC60",
+ "plaintext": b"AE2D8A571E03AC9C9EB76FAC45AF8E51",
+ "ciphertext": b"25623DB569CA51E01482649977E28D84",
+ },
+ {
+ "key": b"2B7E151628AED2A6ABF7158809CF4F3C",
+ "iv": b"D9A4DADA0892239F6B8B3D7680E15674",
+ "plaintext": b"30C81C46A35CE411E5FBC1191A0A52EF",
+ "ciphertext": b"C776634A60729DC657D12B9FCA801E98",
+ },
+ {
+ "key": b"2B7E151628AED2A6ABF7158809CF4F3C",
+ "iv": b"A78819583F0308E7A6BF36B1386ABF23",
+ "plaintext": b"F69F2445DF4F9B17AD2B417BE66C3710",
+ "ciphertext": b"D776379BE0E50825E681DA1A4C980E8E",
+ },
]
diff --git a/tests/utils.py b/tests/utils.py
index d06c9e3b..6b1cfd79 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -14,7 +14,7 @@
import os.path
-def load_nist_vectors(vector_data, op, fields):
+def load_nist_vectors(vector_data, op):
section, count, data = None, None, {}
for line in vector_data:
@@ -44,21 +44,19 @@ def load_nist_vectors(vector_data, op, fields):
# For all other tokens we simply want the name, value stored in
# the dictionary
else:
- data[section][count][name.lower()] = value
+ data[section][count][name.lower()] = value.encode("ascii")
- # We want to test only for a particular operation
- return [
- tuple(vector[1][f].encode("ascii") for f in fields)
- for vector in sorted(data[op].items(), key=lambda v: v[0])
- ]
+ # We want to test only for a particular operation, we sort them for the
+ # benefit of the tests of this function.
+ return [v for k, v in sorted(data[op].items(), key=lambda kv: kv[0])]
-def load_nist_vectors_from_file(filename, op, fields):
+def load_nist_vectors_from_file(filename, op):
base = os.path.join(
os.path.dirname(__file__), "primitives", "vectors", "NIST",
)
with open(os.path.join(base, filename), "r") as vector_file:
- return load_nist_vectors(vector_file, op, fields)
+ return load_nist_vectors(vector_file, op)
def load_cryptrec_vectors_from_file(filename):
@@ -87,7 +85,11 @@ def load_cryptrec_vectors(vector_data):
ct = line.split(" : ")[1].replace(" ", "").encode("ascii")
# after a C is found the K+P+C tuple is complete
# there are many P+C pairs for each K
- cryptrec_list.append((key, pt, ct))
+ cryptrec_list.append({
+ "key": key,
+ "plaintext": pt,
+ "ciphertext": ct
+ })
return cryptrec_list
@@ -110,15 +112,10 @@ def load_openssl_vectors(vector_data):
continue
vector = line.split(":")
- params = (
- # key
- vector[1].encode("ascii"),
- # iv
- vector[2].encode("ascii"),
- # plaintext
- vector[3].encode("ascii"),
- # ciphertext
- vector[4].encode("ascii")
- )
- vectors.append(params)
+ vectors.append({
+ "key": vector[1].encode("ascii"),
+ "iv": vector[2].encode("ascii"),
+ "plaintext": vector[3].encode("ascii"),
+ "ciphertext": vector[4].encode("ascii"),
+ })
return vectors
diff --git a/tox.ini b/tox.ini
index 4d17ebe8..0a28af15 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,9 +3,12 @@ envlist = py26,py27,pypy,py32,py33,docs,pep8
[testenv]
deps =
- pytest-cov
+ pytest
+ coverage
pretend
-commands = py.test --cov=cryptography/ --cov=tests/
+commands =
+ coverage run --source=cryptography/,tests/ -m pytest
+ coverage report -m
[testenv:docs]
deps = sphinx