aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDonald Stufft <donald@stufft.io>2013-10-21 15:39:18 -0700
committerDonald Stufft <donald@stufft.io>2013-10-21 15:39:18 -0700
commitc160079df8dd021b6b1e8091025ba27ddc6cd6c0 (patch)
treedcbc2e2491bffc6ad19eea41bbeeba85d65a48b3
parent71ed449ffe7e26e9217b6c44bb27e19996315a64 (diff)
parent6f874ff9279376b6962c514ae0e59b90e7082e15 (diff)
downloadcryptography-c160079df8dd021b6b1e8091025ba27ddc6cd6c0.tar.gz
cryptography-c160079df8dd021b6b1e8091025ba27ddc6cd6c0.tar.bz2
cryptography-c160079df8dd021b6b1e8091025ba27ddc6cd6c0.zip
Merge pull request #109 from alex/refactor-cipher-names
[WIP] Refactor how cipher names are computed
-rw-r--r--cryptography/bindings/openssl/api.py51
-rw-r--r--cryptography/primitives/block/base.py4
-rw-r--r--tests/bindings/test_openssl.py10
-rw-r--r--tests/primitives/test_cryptrec.py4
-rw-r--r--tests/primitives/test_openssl_vectors.py16
5 files changed, 68 insertions, 17 deletions
diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py
index 12082c09..7d189d62 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, 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):
@@ -87,6 +99,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.
@@ -95,18 +110,38 @@ 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, CTR, 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.lib.EVP_CIPHER_CTX_new()
ctx = self.ffi.gc(ctx, self.lib.EVP_CIPHER_CTX_free)
- # 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 50e9e9e5..42c1f799 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..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):
@@ -30,4 +34,8 @@ 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
+
+ def test_register_duplicate_cipher_adapter(self):
+ with pytest.raises(ValueError):
+ api.register_cipher_adapter(AES, CBC, None)
diff --git a/tests/primitives/test_cryptrec.py b/tests/primitives/test_cryptrec.py
index edf97652..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("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 5b2be784..86ff7cad 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("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 +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("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,7 +60,9 @@ 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",
)
@@ -68,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",
)