From 8ee102762525ff7619bc5b9c16f53f4c8537abfc Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 16 Oct 2013 18:00:50 -0700 Subject: Refactor how cipher names are computed --- cryptography/bindings/openssl/api.py | 52 +++++++++++++++++++++++++++----- cryptography/primitives/block/base.py | 4 +-- tests/bindings/test_openssl.py | 2 +- tests/primitives/test_cryptrec.py | 2 +- tests/primitives/test_openssl_vectors.py | 6 ++-- 5 files changed, 50 insertions(+), 16 deletions(-) diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py index f1a2c087..ced2cf89 100644 --- a/cryptography/bindings/openssl/api.py +++ b/cryptography/bindings/openssl/api.py @@ -13,11 +13,23 @@ 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 +from cryptography.primitives.block.modes import CBC, 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) class API(object): @@ -78,6 +90,9 @@ class API(object): 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. @@ -86,20 +101,41 @@ 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 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, ECB, OFB, CFB], + ): + self.register_cipher_adapter( + cipher_cls, + mode_cls, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") + ) def create_block_cipher_context(self, cipher, mode): ctx = self.ffi.new("EVP_CIPHER_CTX *") res = self.lib.EVP_CIPHER_CTX_init(ctx) assert res != 0 ctx = self.ffi.gc(ctx, self.lib.EVP_CIPHER_CTX_cleanup) - # 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")) + 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 diff --git a/cryptography/primitives/block/base.py b/cryptography/primitives/block/base.py index b84ca9c4..cb68361b 100644 --- a/cryptography/primitives/block/base.py +++ b/cryptography/primitives/block/base.py @@ -15,8 +15,6 @@ from __future__ import absolute_import, division, print_function from enum import Enum -from cryptography.bindings import _default_api - class _Operation(Enum): encrypt = 0 @@ -28,7 +26,7 @@ class BlockCipher(object): super(BlockCipher, self).__init__() if api is None: - api = _default_api + from cryptography.bindings import _default_api as api self.cipher = cipher self.mode = mode diff --git a/tests/bindings/test_openssl.py b/tests/bindings/test_openssl.py index e5b78d18..2d513308 100644 --- a/tests/bindings/test_openssl.py +++ b/tests/bindings/test_openssl.py @@ -30,4 +30,4 @@ class TestOpenSSL(object): assert api.openssl_version_text().startswith("OpenSSL") def test_supports_cipher(self): - assert api.supports_cipher("not-a-real-cipher") is False + assert api.supports_cipher(None, None) is False diff --git a/tests/primitives/test_cryptrec.py b/tests/primitives/test_cryptrec.py index edf97652..56eca3a1 100644 --- a/tests/primitives/test_cryptrec.py +++ b/tests/primitives/test_cryptrec.py @@ -37,6 +37,6 @@ class TestCamelliaECB(object): ], lambda key: ciphers.Camellia(binascii.unhexlify((key))), lambda key: modes.ECB(), - only_if=lambda api: api.supports_cipher("camellia-128-ecb"), + only_if=lambda api: api.supports_cipher(ciphers.Camellia("\x00" * 16), modes.ECB()), skip_message="Does not support Camellia ECB", ) diff --git a/tests/primitives/test_openssl_vectors.py b/tests/primitives/test_openssl_vectors.py index 6e32eca6..f53ade8e 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("camellia-128-cbc"), + only_if=lambda api: api.supports_cipher(ciphers.Camellia("\x00" * 16), modes.CBC("\x00" * 16)), skip_message="Does not support Camellia CBC", ) @@ -44,7 +44,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("camellia-128-ofb"), + only_if=lambda api: api.supports_cipher(ciphers.Camellia("\x00" * 16), modes.OFB("\x00" * 16)), skip_message="Does not support Camellia OFB", ) @@ -56,6 +56,6 @@ 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("camellia-128-cfb"), + only_if=lambda api: api.supports_cipher(ciphers.Camellia("\x00" * 16), modes.CFB("\x00" * 16)), skip_message="Does not support Camellia CFB", ) -- cgit v1.2.3 From b400804424143ed8e3a80846236174d738769353 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 16 Oct 2013 18:49:26 -0700 Subject: pep8 and py3k fixes --- cryptography/bindings/openssl/api.py | 2 +- tests/primitives/test_cryptrec.py | 4 +++- tests/primitives/test_openssl_vectors.py | 12 +++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py index ced2cf89..d5a319c9 100644 --- a/cryptography/bindings/openssl/api.py +++ b/cryptography/bindings/openssl/api.py @@ -29,7 +29,7 @@ class GetCipherByName(object): def __call__(self, api, cipher, mode): cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower() - return api.lib.EVP_get_cipherbyname(cipher_name) + return api.lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) class API(object): diff --git a/tests/primitives/test_cryptrec.py b/tests/primitives/test_cryptrec.py index 56eca3a1..02a04473 100644 --- a/tests/primitives/test_cryptrec.py +++ b/tests/primitives/test_cryptrec.py @@ -37,6 +37,8 @@ class TestCamelliaECB(object): ], lambda key: ciphers.Camellia(binascii.unhexlify((key))), lambda key: modes.ECB(), - only_if=lambda api: api.supports_cipher(ciphers.Camellia("\x00" * 16), modes.ECB()), + only_if=lambda api: api.supports_cipher( + ciphers.Camellia("\x00" * 16), modes.ECB() + ), skip_message="Does not support Camellia ECB", ) diff --git a/tests/primitives/test_openssl_vectors.py b/tests/primitives/test_openssl_vectors.py index f53ade8e..bcbda861 100644 --- a/tests/primitives/test_openssl_vectors.py +++ b/tests/primitives/test_openssl_vectors.py @@ -32,7 +32,9 @@ 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(ciphers.Camellia("\x00" * 16), modes.CBC("\x00" * 16)), + only_if=lambda api: api.supports_cipher( + ciphers.Camellia("\x00" * 16), modes.CBC("\x00" * 16) + ), skip_message="Does not support Camellia CBC", ) @@ -44,7 +46,9 @@ 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(ciphers.Camellia("\x00" * 16), modes.OFB("\x00" * 16)), + only_if=lambda api: api.supports_cipher( + ciphers.Camellia("\x00" * 16), modes.OFB("\x00" * 16) + ), skip_message="Does not support Camellia OFB", ) @@ -56,6 +60,8 @@ 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(ciphers.Camellia("\x00" * 16), modes.CFB("\x00" * 16)), + only_if=lambda api: api.supports_cipher( + ciphers.Camellia("\x00" * 16), modes.CFB("\x00" * 16) + ), skip_message="Does not support Camellia CFB", ) -- cgit v1.2.3 From a4da1d2a6e568e2ec4c474c5d41bbc445f7c90e8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 16 Oct 2013 19:07:33 -0700 Subject: Up our coverage --- tests/bindings/test_openssl.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/bindings/test_openssl.py b/tests/bindings/test_openssl.py index 2d513308..bf201e4d 100644 --- a/tests/bindings/test_openssl.py +++ b/tests/bindings/test_openssl.py @@ -11,7 +11,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + from cryptography.bindings.openssl.api import api +from cryptography.primitives.block.ciphers import AES +from cryptography.primitives.block.modes import CBC class TestOpenSSL(object): @@ -31,3 +35,7 @@ class TestOpenSSL(object): def test_supports_cipher(self): assert api.supports_cipher(None, None) is False + + def test_register_duplicate_cipher_adapter(self): + with pytest.raises(ValueError): + api.register_cipher_adapter(AES, CBC, None) -- cgit v1.2.3 From 9bd4f45fcb317fd8fd1b278254b2041b7b42aa47 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 17 Oct 2013 12:16:11 -0700 Subject: Include CTR mode --- cryptography/bindings/openssl/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py index 1d7ea13d..d804de43 100644 --- a/cryptography/bindings/openssl/api.py +++ b/cryptography/bindings/openssl/api.py @@ -20,7 +20,7 @@ import cffi from cryptography.primitives import interfaces from cryptography.primitives.block.ciphers import AES, Camellia -from cryptography.primitives.block.modes import CBC, ECB, OFB, CFB +from cryptography.primitives.block.modes import CBC, CTR, ECB, OFB, CFB class GetCipherByName(object): @@ -119,7 +119,7 @@ class API(object): def _register_default_ciphers(self): for cipher_cls, mode_cls in itertools.product( [AES, Camellia], - [CBC, ECB, OFB, CFB], + [CBC, CTR, ECB, OFB, CFB], ): self.register_cipher_adapter( cipher_cls, -- cgit v1.2.3 From d6644815913e878462aa51c95c84e6d871406e27 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 17 Oct 2013 13:08:01 -0700 Subject: fix --- tests/primitives/test_openssl_vectors.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/primitives/test_openssl_vectors.py b/tests/primitives/test_openssl_vectors.py index 5706b16a..86ff7cad 100644 --- a/tests/primitives/test_openssl_vectors.py +++ b/tests/primitives/test_openssl_vectors.py @@ -74,6 +74,8 @@ 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("aes-128-ctr"), + only_if=lambda api: api.supports_cipher( + ciphers.AES("\x00" * 16), modes.CTR("\x00" * 16) + ), skip_message="Does not support AES CTR", ) -- cgit v1.2.3 From c5833bfcad56fe44e30455dc037c2874e425b241 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 20 Oct 2013 22:11:04 -0500 Subject: Add HMAC bindings --- cryptography/bindings/openssl/api.py | 1 + cryptography/bindings/openssl/hmac.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 cryptography/bindings/openssl/hmac.py diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py index f5e042e7..12082c09 100644 --- a/cryptography/bindings/openssl/api.py +++ b/cryptography/bindings/openssl/api.py @@ -35,6 +35,7 @@ class API(object): "engine", "err", "evp", + "hmac", "nid", "opensslv", "pem", diff --git a/cryptography/bindings/openssl/hmac.py b/cryptography/bindings/openssl/hmac.py new file mode 100644 index 00000000..7a9d05b5 --- /dev/null +++ b/cryptography/bindings/openssl/hmac.py @@ -0,0 +1,33 @@ +# 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 +""" + +TYPES = """ +struct hmac_ctx_st { ...; }; +typedef struct hmac_ctx_st HMAC_CTX; +""" + +FUNCTIONS = """ +void HMAC_CTX_init(HMAC_CTX *); +void HMAC_CTX_cleanup(HMAC_CTX *); +int HMAC_Init_ex(HMAC_CTX *, const void *, int, const EVP_MD *, ENGINE *); +int HMAC_Update(HMAC_CTX *, const unsigned char *, size_t); +int HMAC_Final(HMAC_CTX *, unsigned char *, unsigned int *); +int HMAC_CTX_copy(HMAC_CTX *, HMAC_CTX *); +""" + +MACROS = """ +""" -- cgit v1.2.3 From 02cd1fc7c4d5722c78ec1f586044ff21dea98975 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 20 Oct 2013 22:36:32 -0500 Subject: simplify HMAC_CTX typedef --- cryptography/bindings/openssl/hmac.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cryptography/bindings/openssl/hmac.py b/cryptography/bindings/openssl/hmac.py index 7a9d05b5..e97ac35e 100644 --- a/cryptography/bindings/openssl/hmac.py +++ b/cryptography/bindings/openssl/hmac.py @@ -16,8 +16,7 @@ INCLUDES = """ """ TYPES = """ -struct hmac_ctx_st { ...; }; -typedef struct hmac_ctx_st HMAC_CTX; +typedef struct { ...; } HMAC_CTX; """ FUNCTIONS = """ -- cgit v1.2.3