From db37d0e29d6a7ff41e5c312e7ad1f904c0bc310e Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 22 Oct 2013 20:13:06 -0500 Subject: the great api -> backend rename --- cryptography/bindings/__init__.py | 6 +- cryptography/bindings/openssl/__init__.py | 4 +- cryptography/bindings/openssl/api.py | 250 ------------------------------ cryptography/bindings/openssl/backend.py | 250 ++++++++++++++++++++++++++++++ cryptography/primitives/block/base.py | 36 +++-- cryptography/primitives/hashes.py | 25 +-- docs/bindings/openssl.rst | 6 +- tests/bindings/test_openssl.py | 12 +- tests/conftest.py | 6 +- tests/primitives/test_block.py | 10 +- tests/primitives/test_cryptrec.py | 2 +- tests/primitives/test_hash_vectors.py | 20 +-- tests/primitives/test_hashes.py | 24 +-- tests/primitives/test_openssl_vectors.py | 8 +- tests/primitives/test_utils.py | 8 +- tests/primitives/utils.py | 48 +++--- 16 files changed, 361 insertions(+), 354 deletions(-) delete mode 100644 cryptography/bindings/openssl/api.py create mode 100644 cryptography/bindings/openssl/backend.py diff --git a/cryptography/bindings/__init__.py b/cryptography/bindings/__init__.py index 215f17c7..5006d134 100644 --- a/cryptography/bindings/__init__.py +++ b/cryptography/bindings/__init__.py @@ -14,7 +14,7 @@ from cryptography.bindings import openssl -_default_api = openssl.api -_ALL_APIS = [ - openssl.api +_default_backend = openssl.backend +_ALL_BACKENDS = [ + openssl.backend ] diff --git a/cryptography/bindings/openssl/__init__.py b/cryptography/bindings/openssl/__init__.py index 103b1db0..cfe2e665 100644 --- a/cryptography/bindings/openssl/__init__.py +++ b/cryptography/bindings/openssl/__init__.py @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from cryptography.bindings.openssl.api import api +from cryptography.bindings.openssl.backend import backend -__all__ = ["api"] +__all__ = ["backend"] diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py deleted file mode 100644 index fedaf9cc..00000000 --- a/cryptography/bindings/openssl/api.py +++ /dev/null @@ -1,250 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import absolute_import, division, print_function - -import itertools -import sys - -import cffi - -from cryptography.primitives import interfaces -from cryptography.primitives.block.ciphers import AES, Camellia, TripleDES -from cryptography.primitives.block.modes import CBC, CTR, ECB, OFB, CFB - - -class GetCipherByName(object): - def __init__(self, fmt): - self._fmt = fmt - - def __call__(self, api, cipher, mode): - cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower() - return api.lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) - - -class API(object): - """ - OpenSSL API wrapper. - """ - _modules = [ - "asn1", - "bignum", - "bio", - "conf", - "crypto", - "dh", - "dsa", - "engine", - "err", - "evp", - "hmac", - "nid", - "opensslv", - "pem", - "pkcs7", - "pkcs12", - "rand", - "rsa", - "ssl", - "x509", - "x509name", - "x509v3", - ] - - 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) - - 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 + functions), - libraries=["crypto", "ssl"], - ) - - self.lib.OpenSSL_add_all_algorithms() - self.lib.SSL_load_error_strings() - - self._cipher_registry = {} - self._register_default_ciphers() - - def openssl_version_text(self): - """ - Friendly string name of linked OpenSSL. - - Example: OpenSSL 1.0.1e 11 Feb 2013 - """ - return self.ffi.string(self.lib.OPENSSL_VERSION_TEXT).decode("ascii") - - def supports_cipher(self, cipher, mode): - try: - adapter = self._cipher_registry[type(cipher), type(mode)] - except KeyError: - return False - evp_cipher = adapter(self, cipher, mode) - return self.ffi.NULL != evp_cipher - - def register_cipher_adapter(self, cipher_cls, mode_cls, adapter): - if (cipher_cls, mode_cls) in self._cipher_registry: - raise ValueError("Duplicate registration for: {0} {1}".format( - cipher_cls, mode_cls) - ) - self._cipher_registry[cipher_cls, mode_cls] = adapter - - def _register_default_ciphers(self): - for cipher_cls, mode_cls in itertools.product( - [AES, Camellia], - [CBC, CTR, ECB, OFB, CFB], - ): - self.register_cipher_adapter( - cipher_cls, - mode_cls, - GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") - ) - for mode_cls in [CBC, CFB, OFB]: - self.register_cipher_adapter( - TripleDES, - mode_cls, - GetCipherByName("des-ede3-{mode.name}") - ) - - def create_block_cipher_encrypt_context(self, cipher, mode): - ctx, evp, iv_nonce = self._create_block_cipher_context(cipher, mode) - res = self.lib.EVP_EncryptInit_ex(ctx, evp, api.ffi.NULL, cipher.key, - iv_nonce) - assert res != 0 - # We purposely disable padding here as it's handled higher up in the - # API. - self.lib.EVP_CIPHER_CTX_set_padding(ctx, 0) - return ctx - - def create_block_cipher_decrypt_context(self, cipher, mode): - ctx, evp, iv_nonce = self._create_block_cipher_context(cipher, mode) - res = self.lib.EVP_DecryptInit_ex(ctx, evp, api.ffi.NULL, cipher.key, - iv_nonce) - assert res != 0 - # We purposely disable padding here as it's handled higher up in the - # API. - self.lib.EVP_CIPHER_CTX_set_padding(ctx, 0) - return ctx - - def _create_block_cipher_context(self, cipher, mode): - ctx = self.lib.EVP_CIPHER_CTX_new() - ctx = self.ffi.gc(ctx, self.lib.EVP_CIPHER_CTX_free) - evp_cipher = self._cipher_registry[type(cipher), type(mode)]( - self, cipher, mode - ) - 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 - - return (ctx, evp_cipher, iv_nonce) - - def update_encrypt_context(self, ctx, data): - block_size = self.lib.EVP_CIPHER_CTX_block_size(ctx) - buf = self.ffi.new("unsigned char[]", len(data) + block_size - 1) - outlen = self.ffi.new("int *") - res = self.lib.EVP_EncryptUpdate(ctx, buf, outlen, data, len(data)) - assert res != 0 - return self.ffi.buffer(buf)[:outlen[0]] - - def update_decrypt_context(self, ctx, data): - block_size = self.lib.EVP_CIPHER_CTX_block_size(ctx) - buf = self.ffi.new("unsigned char[]", len(data) + block_size - 1) - outlen = self.ffi.new("int *") - res = self.lib.EVP_DecryptUpdate(ctx, buf, outlen, data, len(data)) - assert res != 0 - return self.ffi.buffer(buf)[:outlen[0]] - - def finalize_encrypt_context(self, ctx): - block_size = self.lib.EVP_CIPHER_CTX_block_size(ctx) - buf = self.ffi.new("unsigned char[]", block_size) - outlen = self.ffi.new("int *") - res = self.lib.EVP_EncryptFinal_ex(ctx, buf, outlen) - assert res != 0 - res = self.lib.EVP_CIPHER_CTX_cleanup(ctx) - assert res == 1 - return self.ffi.buffer(buf)[:outlen[0]] - - def finalize_decrypt_context(self, ctx): - block_size = self.lib.EVP_CIPHER_CTX_block_size(ctx) - buf = self.ffi.new("unsigned char[]", block_size) - outlen = self.ffi.new("int *") - res = self.lib.EVP_DecryptFinal_ex(ctx, buf, outlen) - assert res != 0 - res = self.lib.EVP_CIPHER_CTX_cleanup(ctx) - assert res == 1 - return self.ffi.buffer(buf)[:outlen[0]] - - def supports_hash(self, hash_cls): - return (self.ffi.NULL != - self.lib.EVP_get_digestbyname(hash_cls.name.encode("ascii"))) - - def create_hash_context(self, hashobject): - ctx = self.lib.EVP_MD_CTX_create() - ctx = self.ffi.gc(ctx, self.lib.EVP_MD_CTX_destroy) - evp_md = self.lib.EVP_get_digestbyname(hashobject.name.encode("ascii")) - assert evp_md != self.ffi.NULL - res = self.lib.EVP_DigestInit_ex(ctx, evp_md, self.ffi.NULL) - assert res != 0 - return ctx - - def update_hash_context(self, ctx, data): - res = self.lib.EVP_DigestUpdate(ctx, data, len(data)) - assert res != 0 - - def finalize_hash_context(self, ctx, digest_size): - buf = self.ffi.new("unsigned char[]", digest_size) - res = self.lib.EVP_DigestFinal_ex(ctx, buf, self.ffi.NULL) - assert res != 0 - res = self.lib.EVP_MD_CTX_cleanup(ctx) - assert res == 1 - return self.ffi.buffer(buf)[:digest_size] - - def copy_hash_context(self, ctx): - copied_ctx = self.lib.EVP_MD_CTX_create() - copied_ctx = self.ffi.gc(copied_ctx, self.lib.EVP_MD_CTX_destroy) - res = self.lib.EVP_MD_CTX_copy_ex(copied_ctx, ctx) - assert res != 0 - return copied_ctx - - -api = API() diff --git a/cryptography/bindings/openssl/backend.py b/cryptography/bindings/openssl/backend.py new file mode 100644 index 00000000..492f2e54 --- /dev/null +++ b/cryptography/bindings/openssl/backend.py @@ -0,0 +1,250 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import, division, print_function + +import itertools +import sys + +import cffi + +from cryptography.primitives import interfaces +from cryptography.primitives.block.ciphers import AES, Camellia, TripleDES +from cryptography.primitives.block.modes import CBC, CTR, ECB, OFB, CFB + + +class GetCipherByName(object): + def __init__(self, fmt): + self._fmt = fmt + + def __call__(self, backend, cipher, mode): + cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower() + return backend.lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) + + +class Backend(object): + """ + OpenSSL API wrapper. + """ + _modules = [ + "asn1", + "bignum", + "bio", + "conf", + "crypto", + "dh", + "dsa", + "engine", + "err", + "evp", + "hmac", + "nid", + "opensslv", + "pem", + "pkcs7", + "pkcs12", + "rand", + "rsa", + "ssl", + "x509", + "x509name", + "x509v3", + ] + + 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) + + 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 + functions), + libraries=["crypto", "ssl"], + ) + + self.lib.OpenSSL_add_all_algorithms() + self.lib.SSL_load_error_strings() + + self._cipher_registry = {} + self._register_default_ciphers() + + def openssl_version_text(self): + """ + Friendly string name of linked OpenSSL. + + Example: OpenSSL 1.0.1e 11 Feb 2013 + """ + return self.ffi.string(self.lib.OPENSSL_VERSION_TEXT).decode("ascii") + + def supports_cipher(self, cipher, mode): + try: + adapter = self._cipher_registry[type(cipher), type(mode)] + except KeyError: + return False + evp_cipher = adapter(self, cipher, mode) + return self.ffi.NULL != evp_cipher + + def register_cipher_adapter(self, cipher_cls, mode_cls, adapter): + if (cipher_cls, mode_cls) in self._cipher_registry: + raise ValueError("Duplicate registration for: {0} {1}".format( + cipher_cls, mode_cls) + ) + self._cipher_registry[cipher_cls, mode_cls] = adapter + + def _register_default_ciphers(self): + for cipher_cls, mode_cls in itertools.product( + [AES, Camellia], + [CBC, CTR, ECB, OFB, CFB], + ): + self.register_cipher_adapter( + cipher_cls, + mode_cls, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") + ) + for mode_cls in [CBC, CFB, OFB]: + self.register_cipher_adapter( + TripleDES, + mode_cls, + GetCipherByName("des-ede3-{mode.name}") + ) + + def create_block_cipher_encrypt_context(self, cipher, mode): + ctx, evp, iv_nonce = self._create_block_cipher_context(cipher, mode) + res = self.lib.EVP_EncryptInit_ex(ctx, evp, self.ffi.NULL, cipher.key, + iv_nonce) + assert res != 0 + # We purposely disable padding here as it's handled higher up in the + # API. + self.lib.EVP_CIPHER_CTX_set_padding(ctx, 0) + return ctx + + def create_block_cipher_decrypt_context(self, cipher, mode): + ctx, evp, iv_nonce = self._create_block_cipher_context(cipher, mode) + res = self.lib.EVP_DecryptInit_ex(ctx, evp, self.ffi.NULL, cipher.key, + iv_nonce) + assert res != 0 + # We purposely disable padding here as it's handled higher up in the + # API. + self.lib.EVP_CIPHER_CTX_set_padding(ctx, 0) + return ctx + + def _create_block_cipher_context(self, cipher, mode): + ctx = self.lib.EVP_CIPHER_CTX_new() + ctx = self.ffi.gc(ctx, self.lib.EVP_CIPHER_CTX_free) + evp_cipher = self._cipher_registry[type(cipher), type(mode)]( + self, cipher, mode + ) + 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 + + return (ctx, evp_cipher, iv_nonce) + + def update_encrypt_context(self, ctx, data): + block_size = self.lib.EVP_CIPHER_CTX_block_size(ctx) + buf = self.ffi.new("unsigned char[]", len(data) + block_size - 1) + outlen = self.ffi.new("int *") + res = self.lib.EVP_EncryptUpdate(ctx, buf, outlen, data, len(data)) + assert res != 0 + return self.ffi.buffer(buf)[:outlen[0]] + + def update_decrypt_context(self, ctx, data): + block_size = self.lib.EVP_CIPHER_CTX_block_size(ctx) + buf = self.ffi.new("unsigned char[]", len(data) + block_size - 1) + outlen = self.ffi.new("int *") + res = self.lib.EVP_DecryptUpdate(ctx, buf, outlen, data, len(data)) + assert res != 0 + return self.ffi.buffer(buf)[:outlen[0]] + + def finalize_encrypt_context(self, ctx): + block_size = self.lib.EVP_CIPHER_CTX_block_size(ctx) + buf = self.ffi.new("unsigned char[]", block_size) + outlen = self.ffi.new("int *") + res = self.lib.EVP_EncryptFinal_ex(ctx, buf, outlen) + assert res != 0 + res = self.lib.EVP_CIPHER_CTX_cleanup(ctx) + assert res == 1 + return self.ffi.buffer(buf)[:outlen[0]] + + def finalize_decrypt_context(self, ctx): + block_size = self.lib.EVP_CIPHER_CTX_block_size(ctx) + buf = self.ffi.new("unsigned char[]", block_size) + outlen = self.ffi.new("int *") + res = self.lib.EVP_DecryptFinal_ex(ctx, buf, outlen) + assert res != 0 + res = self.lib.EVP_CIPHER_CTX_cleanup(ctx) + assert res == 1 + return self.ffi.buffer(buf)[:outlen[0]] + + def supports_hash(self, hash_cls): + return (self.ffi.NULL != + self.lib.EVP_get_digestbyname(hash_cls.name.encode("ascii"))) + + def create_hash_context(self, hashobject): + ctx = self.lib.EVP_MD_CTX_create() + ctx = self.ffi.gc(ctx, self.lib.EVP_MD_CTX_destroy) + evp_md = self.lib.EVP_get_digestbyname(hashobject.name.encode("ascii")) + assert evp_md != self.ffi.NULL + res = self.lib.EVP_DigestInit_ex(ctx, evp_md, self.ffi.NULL) + assert res != 0 + return ctx + + def update_hash_context(self, ctx, data): + res = self.lib.EVP_DigestUpdate(ctx, data, len(data)) + assert res != 0 + + def finalize_hash_context(self, ctx, digest_size): + buf = self.ffi.new("unsigned char[]", digest_size) + res = self.lib.EVP_DigestFinal_ex(ctx, buf, self.ffi.NULL) + assert res != 0 + res = self.lib.EVP_MD_CTX_cleanup(ctx) + assert res == 1 + return self.ffi.buffer(buf)[:digest_size] + + def copy_hash_context(self, ctx): + copied_ctx = self.lib.EVP_MD_CTX_create() + copied_ctx = self.ffi.gc(copied_ctx, self.lib.EVP_MD_CTX_destroy) + res = self.lib.EVP_MD_CTX_copy_ex(copied_ctx, ctx) + assert res != 0 + return copied_ctx + + +backend = Backend() diff --git a/cryptography/primitives/block/base.py b/cryptography/primitives/block/base.py index 12b6f626..e9f52887 100644 --- a/cryptography/primitives/block/base.py +++ b/cryptography/primitives/block/base.py @@ -17,58 +17,62 @@ from cryptography.primitives import interfaces class BlockCipher(object): - def __init__(self, cipher, mode, api=None): + def __init__(self, cipher, mode, backend=None): super(BlockCipher, self).__init__() - if api is None: - from cryptography.bindings import _default_api as api + if backend is None: + from cryptography.bindings import _default_backend as backend self.cipher = cipher self.mode = mode - self._api = api + self._backend = backend def encryptor(self): - return _CipherEncryptionContext(self.cipher, self.mode, self._api) + return _CipherEncryptionContext(self.cipher, self.mode, self._backend) def decryptor(self): - return _CipherDecryptionContext(self.cipher, self.mode, self._api) + return _CipherDecryptionContext(self.cipher, self.mode, self._backend) @interfaces.register(interfaces.CipherContext) class _CipherEncryptionContext(object): - def __init__(self, cipher, mode, api): + def __init__(self, cipher, mode, backend): super(_CipherEncryptionContext, self).__init__() - self._api = api - self._ctx = self._api.create_block_cipher_encrypt_context(cipher, mode) + self._backend = backend + self._ctx = self._backend.create_block_cipher_encrypt_context( + cipher, mode + ) def update(self, data): if self._ctx is None: raise ValueError("Context was already finalized") - return self._api.update_encrypt_context(self._ctx, data) + return self._backend.update_encrypt_context(self._ctx, data) def finalize(self): if self._ctx is None: raise ValueError("Context was already finalized") - data = self._api.finalize_encrypt_context(self._ctx) + data = self._backend.finalize_encrypt_context(self._ctx) self._ctx = None return data @interfaces.register(interfaces.CipherContext) class _CipherDecryptionContext(object): - def __init__(self, cipher, mode, api): + def __init__(self, cipher, mode, backend): super(_CipherDecryptionContext, self).__init__() - self._api = api - self._ctx = self._api.create_block_cipher_decrypt_context(cipher, mode) + self._backend = backend + self._ctx = self._backend.create_block_cipher_decrypt_context( + cipher, mode + ) def update(self, data): if self._ctx is None: raise ValueError("Context was already finalized") - return self._api.update_decrypt_context(self._ctx, data) + return self._backend.update_decrypt_context(self._ctx, data) def finalize(self): if self._ctx is None: raise ValueError("Context was already finalized") - data = self._api.finalize_decrypt_context(self._ctx) + data = self._backend.finalize_decrypt_context(self._ctx) self._ctx = None return data diff --git a/cryptography/primitives/hashes.py b/cryptography/primitives/hashes.py index 7133a916..f3eccc6e 100644 --- a/cryptography/primitives/hashes.py +++ b/cryptography/primitives/hashes.py @@ -19,35 +19,38 @@ import binascii import six -from cryptography.bindings import _default_api - class BaseHash(six.with_metaclass(abc.ABCMeta)): - def __init__(self, data=None, api=None, ctx=None): - if api is None: - api = _default_api - self._api = api - self._ctx = self._api.create_hash_context(self) if ctx is None else ctx + def __init__(self, data=None, backend=None, ctx=None): + if backend is None: + from cryptography.bindings import _default_backend + backend = _default_backend + self._backend = backend + if ctx is None: + self._ctx = self._backend.create_hash_context(self) + else: + self._ctx = None + if data is not None: self.update(data) def update(self, data): if isinstance(data, six.text_type): raise TypeError("Unicode-objects must be encoded before hashing") - self._api.update_hash_context(self._ctx, data) + self._backend.update_hash_context(self._ctx, data) def copy(self): return self.__class__(ctx=self._copy_ctx()) def digest(self): - return self._api.finalize_hash_context(self._copy_ctx(), - self.digest_size) + return self._backend.finalize_hash_context(self._copy_ctx(), + self.digest_size) def hexdigest(self): return str(binascii.hexlify(self.digest()).decode("ascii")) def _copy_ctx(self): - return self._api.copy_hash_context(self._ctx) + return self._backend.copy_hash_context(self._ctx) class SHA1(BaseHash): diff --git a/docs/bindings/openssl.rst b/docs/bindings/openssl.rst index 241cc4d6..14d62116 100644 --- a/docs/bindings/openssl.rst +++ b/docs/bindings/openssl.rst @@ -3,16 +3,16 @@ OpenSSL .. warning:: - The OpenSSL API is not easy to use, small mistakes can lead to significant + The OpenSSL backend is not easy to use, small mistakes can lead to significant security vulnerabilities. We strongly recommend not using this directly, and instead using one of the higher level APIs exposed by ``cryptography``. These are `CFFI`_ bindings to the `OpenSSL`_ C library. -.. data:: cryptography.bindings.openssl.api +.. data:: cryptography.bindings.openssl.backend - This is the exposed API for the OpenSSL bindings. It has two public + This is the exposed backend for the OpenSSL bindings. It has two public attributes: .. attribute:: ffi diff --git a/tests/bindings/test_openssl.py b/tests/bindings/test_openssl.py index bf201e4d..bdfbed36 100644 --- a/tests/bindings/test_openssl.py +++ b/tests/bindings/test_openssl.py @@ -13,14 +13,14 @@ import pytest -from cryptography.bindings.openssl.api import api +from cryptography.bindings.openssl.backend import backend from cryptography.primitives.block.ciphers import AES from cryptography.primitives.block.modes import CBC class TestOpenSSL(object): - def test_api_exists(self): - assert api + def test_backend_exists(self): + assert backend def test_openssl_version_text(self): """ @@ -31,11 +31,11 @@ class TestOpenSSL(object): if it starts with OpenSSL as that appears to be true for every OpenSSL. """ - assert api.openssl_version_text().startswith("OpenSSL") + assert backend.openssl_version_text().startswith("OpenSSL") def test_supports_cipher(self): - assert api.supports_cipher(None, None) is False + assert backend.supports_cipher(None, None) is False def test_register_duplicate_cipher_adapter(self): with pytest.raises(ValueError): - api.register_cipher_adapter(AES, CBC, None) + backend.register_cipher_adapter(AES, CBC, None) diff --git a/tests/conftest.py b/tests/conftest.py index b526f2bf..d2ba03de 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ def pytest_generate_tests(metafunc): - from cryptography.bindings import _ALL_APIS + from cryptography.bindings import _ALL_BACKENDS - if "api" in metafunc.fixturenames: - metafunc.parametrize("api", _ALL_APIS) + if "backend" in metafunc.fixturenames: + metafunc.parametrize("backend", _ALL_BACKENDS) diff --git a/tests/primitives/test_block.py b/tests/primitives/test_block.py index 5e147a79..3b3b1f91 100644 --- a/tests/primitives/test_block.py +++ b/tests/primitives/test_block.py @@ -22,7 +22,7 @@ from cryptography.primitives.block import BlockCipher, ciphers, modes class TestBlockCipher(object): - def test_instantiate_without_api(self): + def test_instantiate_without_backend(self): BlockCipher( ciphers.AES(binascii.unhexlify(b"0" * 32)), modes.CBC(binascii.unhexlify(b"0" * 32)) @@ -44,11 +44,11 @@ class TestBlockCipher(object): class TestBlockCipherContext(object): - def test_use_after_finalize(self, api): + def test_use_after_finalize(self, backend): cipher = BlockCipher( ciphers.AES(binascii.unhexlify(b"0" * 32)), modes.CBC(binascii.unhexlify(b"0" * 32)), - api + backend ) encryptor = cipher.encryptor() encryptor.update(b"a" * 16) @@ -65,11 +65,11 @@ class TestBlockCipherContext(object): with pytest.raises(ValueError): decryptor.finalize() - def test_unaligned_block_encryption(self, api): + def test_unaligned_block_encryption(self, backend): cipher = BlockCipher( ciphers.AES(binascii.unhexlify(b"0" * 32)), modes.ECB(), - api + backend ) encryptor = cipher.encryptor() ct = encryptor.update(b"a" * 15) diff --git a/tests/primitives/test_cryptrec.py b/tests/primitives/test_cryptrec.py index 02a04473..d8c9aaa3 100644 --- a/tests/primitives/test_cryptrec.py +++ b/tests/primitives/test_cryptrec.py @@ -37,7 +37,7 @@ class TestCamelliaECB(object): ], lambda key: ciphers.Camellia(binascii.unhexlify((key))), lambda key: modes.ECB(), - only_if=lambda api: api.supports_cipher( + only_if=lambda backend: backend.supports_cipher( ciphers.Camellia("\x00" * 16), modes.ECB() ), skip_message="Does not support Camellia ECB", diff --git a/tests/primitives/test_hash_vectors.py b/tests/primitives/test_hash_vectors.py index 02ef4dbb..b42021c9 100644 --- a/tests/primitives/test_hash_vectors.py +++ b/tests/primitives/test_hash_vectors.py @@ -30,7 +30,7 @@ class TestSHA1(object): "SHA1ShortMsg.rsp", ], hashes.SHA1, - only_if=lambda api: api.supports_hash(hashes.SHA1), + only_if=lambda backend: backend.supports_hash(hashes.SHA1), skip_message="Does not support SHA1", ) @@ -44,7 +44,7 @@ class TestSHA224(object): "SHA224ShortMsg.rsp", ], hashes.SHA224, - only_if=lambda api: api.supports_hash(hashes.SHA224), + only_if=lambda backend: backend.supports_hash(hashes.SHA224), skip_message="Does not support SHA224", ) @@ -58,7 +58,7 @@ class TestSHA256(object): "SHA256ShortMsg.rsp", ], hashes.SHA256, - only_if=lambda api: api.supports_hash(hashes.SHA256), + only_if=lambda backend: backend.supports_hash(hashes.SHA256), skip_message="Does not support SHA256", ) @@ -72,7 +72,7 @@ class TestSHA384(object): "SHA384ShortMsg.rsp", ], hashes.SHA384, - only_if=lambda api: api.supports_hash(hashes.SHA384), + only_if=lambda backend: backend.supports_hash(hashes.SHA384), skip_message="Does not support SHA384", ) @@ -86,7 +86,7 @@ class TestSHA512(object): "SHA512ShortMsg.rsp", ], hashes.SHA512, - only_if=lambda api: api.supports_hash(hashes.SHA512), + only_if=lambda backend: backend.supports_hash(hashes.SHA512), skip_message="Does not support SHA512", ) @@ -99,14 +99,14 @@ class TestRIPEMD160(object): "ripevectors.txt", ], hashes.RIPEMD160, - only_if=lambda api: api.supports_hash(hashes.RIPEMD160), + only_if=lambda backend: backend.supports_hash(hashes.RIPEMD160), skip_message="Does not support RIPEMD160", ) test_RIPEMD160_long_string = generate_long_string_hash_test( hashes.RIPEMD160, "52783243c1697bdbe16d37f97f68f08325dc1528", - only_if=lambda api: api.supports_hash(hashes.RIPEMD160), + only_if=lambda backend: backend.supports_hash(hashes.RIPEMD160), skip_message="Does not support RIPEMD160", ) @@ -119,7 +119,7 @@ class TestWhirlpool(object): "iso-test-vectors.txt", ], hashes.Whirlpool, - only_if=lambda api: api.supports_hash(hashes.Whirlpool), + only_if=lambda backend: backend.supports_hash(hashes.Whirlpool), skip_message="Does not support Whirlpool", ) @@ -128,7 +128,7 @@ class TestWhirlpool(object): ("0c99005beb57eff50a7cf005560ddf5d29057fd86b2" "0bfd62deca0f1ccea4af51fc15490eddc47af32bb2b" "66c34ff9ad8c6008ad677f77126953b226e4ed8b01"), - only_if=lambda api: api.supports_hash(hashes.Whirlpool), + only_if=lambda backend: backend.supports_hash(hashes.Whirlpool), skip_message="Does not support Whirlpool", ) @@ -141,6 +141,6 @@ class TestMD5(object): "rfc-1321.txt", ], hashes.MD5, - only_if=lambda api: api.supports_hash(hashes.MD5), + only_if=lambda backend: backend.supports_hash(hashes.MD5), skip_message="Does not support MD5", ) diff --git a/tests/primitives/test_hashes.py b/tests/primitives/test_hashes.py index 03de8916..505f6c8a 100644 --- a/tests/primitives/test_hashes.py +++ b/tests/primitives/test_hashes.py @@ -23,13 +23,13 @@ from .utils import generate_base_hash_test class TestBaseHash(object): - def test_base_hash_reject_unicode(self, api): - m = hashes.SHA1(api=api) + def test_base_hash_reject_unicode(self, backend): + m = hashes.SHA1(backend=backend) with pytest.raises(TypeError): m.update(six.u("\u00FC")) - def test_base_hash_hexdigest_string_type(self, api): - m = hashes.SHA1(api=api, data=b"") + def test_base_hash_hexdigest_string_type(self, backend): + m = hashes.SHA1(backend=backend, data=b"") assert isinstance(m.hexdigest(), str) @@ -38,7 +38,7 @@ class TestSHA1(object): hashes.SHA1, digest_size=20, block_size=64, - only_if=lambda api: api.supports_hash(hashes.SHA1), + only_if=lambda backend: backend.supports_hash(hashes.SHA1), skip_message="Does not support SHA1", ) @@ -48,7 +48,7 @@ class TestSHA224(object): hashes.SHA224, digest_size=28, block_size=64, - only_if=lambda api: api.supports_hash(hashes.SHA224), + only_if=lambda backend: backend.supports_hash(hashes.SHA224), skip_message="Does not support SHA224", ) @@ -58,7 +58,7 @@ class TestSHA256(object): hashes.SHA256, digest_size=32, block_size=64, - only_if=lambda api: api.supports_hash(hashes.SHA256), + only_if=lambda backend: backend.supports_hash(hashes.SHA256), skip_message="Does not support SHA256", ) @@ -68,7 +68,7 @@ class TestSHA384(object): hashes.SHA384, digest_size=48, block_size=128, - only_if=lambda api: api.supports_hash(hashes.SHA384), + only_if=lambda backend: backend.supports_hash(hashes.SHA384), skip_message="Does not support SHA384", ) @@ -78,7 +78,7 @@ class TestSHA512(object): hashes.SHA512, digest_size=64, block_size=128, - only_if=lambda api: api.supports_hash(hashes.SHA512), + only_if=lambda backend: backend.supports_hash(hashes.SHA512), skip_message="Does not support SHA512", ) @@ -88,7 +88,7 @@ class TestRIPEMD160(object): hashes.RIPEMD160, digest_size=20, block_size=64, - only_if=lambda api: api.supports_hash(hashes.RIPEMD160), + only_if=lambda backend: backend.supports_hash(hashes.RIPEMD160), skip_message="Does not support RIPEMD160", ) @@ -98,7 +98,7 @@ class TestWhirlpool(object): hashes.Whirlpool, digest_size=64, block_size=64, - only_if=lambda api: api.supports_hash(hashes.Whirlpool), + only_if=lambda backend: backend.supports_hash(hashes.Whirlpool), skip_message="Does not support Whirlpool", ) @@ -108,6 +108,6 @@ class TestMD5(object): hashes.MD5, digest_size=16, block_size=64, - only_if=lambda api: api.supports_hash(hashes.MD5), + only_if=lambda backend: backend.supports_hash(hashes.MD5), skip_message="Does not support MD5", ) diff --git a/tests/primitives/test_openssl_vectors.py b/tests/primitives/test_openssl_vectors.py index 86ff7cad..ff42b169 100644 --- a/tests/primitives/test_openssl_vectors.py +++ b/tests/primitives/test_openssl_vectors.py @@ -32,7 +32,7 @@ class TestCamelliaCBC(object): ["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( + only_if=lambda backend: backend.supports_cipher( ciphers.Camellia("\x00" * 16), modes.CBC("\x00" * 16) ), skip_message="Does not support Camellia CBC", @@ -46,7 +46,7 @@ class TestCamelliaOFB(object): ["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( + only_if=lambda backend: backend.supports_cipher( ciphers.Camellia("\x00" * 16), modes.OFB("\x00" * 16) ), skip_message="Does not support Camellia OFB", @@ -60,7 +60,7 @@ class TestCamelliaCFB(object): ["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( + only_if=lambda backend: backend.supports_cipher( ciphers.Camellia("\x00" * 16), modes.CFB("\x00" * 16) ), skip_message="Does not support Camellia CFB", @@ -74,7 +74,7 @@ class TestAESCTR(object): ["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( + only_if=lambda backend: backend.supports_cipher( ciphers.AES("\x00" * 16), modes.CTR("\x00" * 16) ), skip_message="Does not support AES CTR", diff --git a/tests/primitives/test_utils.py b/tests/primitives/test_utils.py index 6e197923..b7fa3d35 100644 --- a/tests/primitives/test_utils.py +++ b/tests/primitives/test_utils.py @@ -10,7 +10,7 @@ class TestEncryptTest(object): with pytest.raises(pytest.skip.Exception) as exc_info: encrypt_test( None, None, None, None, - only_if=lambda api: False, + only_if=lambda backend: False, skip_message="message!" ) assert exc_info.value.args[0] == "message!" @@ -21,7 +21,7 @@ class TestHashTest(object): with pytest.raises(pytest.skip.Exception) as exc_info: hash_test( None, None, None, - only_if=lambda api: False, + only_if=lambda backend: False, skip_message="message!" ) assert exc_info.value.args[0] == "message!" @@ -32,7 +32,7 @@ class TestBaseHashTest(object): with pytest.raises(pytest.skip.Exception) as exc_info: base_hash_test( None, None, None, None, - only_if=lambda api: False, + only_if=lambda backend: False, skip_message="message!" ) assert exc_info.value.args[0] == "message!" @@ -43,7 +43,7 @@ class TestLongHashTest(object): with pytest.raises(pytest.skip.Exception) as exc_info: long_string_hash_test( None, None, None, - only_if=lambda api: False, + only_if=lambda backend: False, skip_message="message!" ) assert exc_info.value.args[0] == "message!" diff --git a/tests/primitives/utils.py b/tests/primitives/utils.py index 91ca36d8..d3b2134f 100644 --- a/tests/primitives/utils.py +++ b/tests/primitives/utils.py @@ -3,20 +3,20 @@ import os import pytest -from cryptography.bindings import _ALL_APIS +from cryptography.bindings import _ALL_BACKENDS from cryptography.primitives.block import BlockCipher def generate_encrypt_test(param_loader, path, file_names, cipher_factory, - mode_factory, only_if=lambda api: True, + mode_factory, only_if=lambda backend: True, skip_message=None): def test_encryption(self): - for api in _ALL_APIS: + for backend in _ALL_BACKENDS: for file_name in file_names: for params in param_loader(os.path.join(path, file_name)): yield ( encrypt_test, - api, + backend, cipher_factory, mode_factory, params, @@ -26,16 +26,16 @@ def generate_encrypt_test(param_loader, path, file_names, cipher_factory, return test_encryption -def encrypt_test(api, cipher_factory, mode_factory, params, only_if, +def encrypt_test(backend, cipher_factory, mode_factory, params, only_if, skip_message): - if not only_if(api): + if not only_if(backend): pytest.skip(skip_message) plaintext = params.pop("plaintext") ciphertext = params.pop("ciphertext") cipher = BlockCipher( cipher_factory(**params), mode_factory(**params), - api + backend ) encryptor = cipher.encryptor() actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext)) @@ -50,12 +50,12 @@ def encrypt_test(api, cipher_factory, mode_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 api in _ALL_APIS: + for backend in _ALL_BACKENDS: for file_name in file_names: for params in param_loader(os.path.join(path, file_name)): yield ( hash_test, - api, + backend, hash_cls, params, only_if, @@ -64,25 +64,25 @@ def generate_hash_test(param_loader, path, file_names, hash_cls, return test_hash -def hash_test(api, hash_cls, params, only_if, skip_message): - if only_if is not None and not only_if(api): +def hash_test(backend, hash_cls, params, only_if, skip_message): + if only_if is not None and not only_if(backend): pytest.skip(skip_message) msg = params[0] md = params[1] - m = hash_cls(api=api) + m = hash_cls(backend=backend) m.update(binascii.unhexlify(msg)) assert m.hexdigest() == md.replace(" ", "").lower() - digest = hash_cls(api=api, data=binascii.unhexlify(msg)).hexdigest() - assert digest == md.replace(" ", "").lower() + digst = hash_cls(backend=backend, data=binascii.unhexlify(msg)).hexdigest() + assert digst == md.replace(" ", "").lower() def generate_base_hash_test(hash_cls, digest_size, block_size, only_if=None, skip_message=None): def test_base_hash(self): - for api in _ALL_APIS: + for backend in _ALL_BACKENDS: yield ( base_hash_test, - api, + backend, hash_cls, digest_size, block_size, @@ -92,11 +92,11 @@ def generate_base_hash_test(hash_cls, digest_size, block_size, return test_base_hash -def base_hash_test(api, hash_cls, digest_size, block_size, only_if, +def base_hash_test(backend, hash_cls, digest_size, block_size, only_if, skip_message): - if only_if is not None and not only_if(api): + if only_if is not None and not only_if(backend): pytest.skip(skip_message) - m = hash_cls(api=api) + m = hash_cls(backend=backend) assert m.digest_size == digest_size assert m.block_size == block_size m_copy = m.copy() @@ -107,10 +107,10 @@ def base_hash_test(api, hash_cls, 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 api in _ALL_APIS: + for backend in _ALL_BACKENDS: yield( long_string_hash_test, - api, + backend, hash_factory, md, only_if, @@ -119,9 +119,9 @@ def generate_long_string_hash_test(hash_factory, md, only_if=None, return test_long_string_hash -def long_string_hash_test(api, hash_factory, md, only_if, skip_message): - if only_if is not None and not only_if(api): +def long_string_hash_test(backend, hash_factory, md, only_if, skip_message): + if only_if is not None and not only_if(backend): pytest.skip(skip_message) - m = hash_factory(api=api) + m = hash_factory(backend=backend) m.update(b"a" * 1000000) assert m.hexdigest() == md.lower() -- cgit v1.2.3 From 2c4873f6255c70257a5a35efbad84e24fc2be63f Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 22 Oct 2013 20:19:38 -0500 Subject: we regret the excesses of our previous api culling. restore some apis. --- docs/bindings/openssl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/bindings/openssl.rst b/docs/bindings/openssl.rst index 14d62116..e59b0c13 100644 --- a/docs/bindings/openssl.rst +++ b/docs/bindings/openssl.rst @@ -3,7 +3,7 @@ OpenSSL .. warning:: - The OpenSSL backend is not easy to use, small mistakes can lead to significant + The OpenSSL API is not easy to use, small mistakes can lead to significant security vulnerabilities. We strongly recommend not using this directly, and instead using one of the higher level APIs exposed by ``cryptography``. @@ -12,7 +12,7 @@ These are `CFFI`_ bindings to the `OpenSSL`_ C library. .. data:: cryptography.bindings.openssl.backend - This is the exposed backend for the OpenSSL bindings. It has two public + This is the exposed API for the OpenSSL bindings. It has two public attributes: .. attribute:: ffi -- cgit v1.2.3 From f4c59767cdfe7716c82a72b00baa427637b505bd Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 22 Oct 2013 20:26:24 -0500 Subject: more backend renames from merged commits --- cryptography/primitives/hashes.py | 2 +- tests/primitives/test_hashes.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cryptography/primitives/hashes.py b/cryptography/primitives/hashes.py index 474dc167..4cd68adc 100644 --- a/cryptography/primitives/hashes.py +++ b/cryptography/primitives/hashes.py @@ -40,7 +40,7 @@ class BaseHash(six.with_metaclass(abc.ABCMeta)): self._backend.update_hash_context(self._ctx, data) def copy(self): - return self.__class__(api=self._api, ctx=self._copy_ctx()) + return self.__class__(backend=self._backend, ctx=self._copy_ctx()) def digest(self): return self._backend.finalize_hash_context(self._copy_ctx(), diff --git a/tests/primitives/test_hashes.py b/tests/primitives/test_hashes.py index 7ddd1859..2efda050 100644 --- a/tests/primitives/test_hashes.py +++ b/tests/primitives/test_hashes.py @@ -19,7 +19,7 @@ import pytest import six -from cryptography.bindings import _default_api +from cryptography.bindings import _default_backend from cryptography.primitives import hashes @@ -38,21 +38,21 @@ class TestBaseHash(object): class TestCopyHash(object): - def test_copy_api_object(self): - pretend_api = pretend.stub(copy_hash_context=lambda a: "copiedctx") + def test_copy_backend_object(self): + pretend_backend = pretend.stub(copy_hash_context=lambda a: "copiedctx") pretend_ctx = pretend.stub() - h = hashes.SHA1(api=pretend_api, ctx=pretend_ctx) - assert h._api is pretend_api - assert h.copy()._api is h._api + h = hashes.SHA1(backend=pretend_backend, ctx=pretend_ctx) + assert h._backend is pretend_backend + assert h.copy()._backend is h._backend class TestDefaultAPISHA1(object): - def test_default_api_creation(self): + def test_default_backend_creation(self): """ This test assumes the presence of SHA1 in the default API. """ h = hashes.SHA1() - assert h._api is _default_api + assert h._backend is _default_backend class TestSHA1(object): -- cgit v1.2.3