diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2013-10-22 21:45:16 -0500 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2013-10-22 21:45:16 -0500 |
commit | 14c3a35447c61e63196a46100a009ee2ea3102a2 (patch) | |
tree | a94fb1889f872c6541730a1685e941cd06f05ddf | |
parent | f4c59767cdfe7716c82a72b00baa427637b505bd (diff) | |
download | cryptography-14c3a35447c61e63196a46100a009ee2ea3102a2.tar.gz cryptography-14c3a35447c61e63196a46100a009ee2ea3102a2.tar.bz2 cryptography-14c3a35447c61e63196a46100a009ee2ea3102a2.zip |
split backend up (refs #170)
* Moves cipher methods into a Ciphers class and hash methods to a Hashes
class and makes them available inside Backend as pluralized
attributes.
* Shortened many of the methods since their purpose is now defined by
their container class
-rw-r--r-- | cryptography/bindings/openssl/backend.py | 68 | ||||
-rw-r--r-- | cryptography/primitives/block/base.py | 16 | ||||
-rw-r--r-- | cryptography/primitives/hashes.py | 10 | ||||
-rw-r--r-- | tests/bindings/test_openssl.py | 4 | ||||
-rw-r--r-- | tests/primitives/test_cryptrec.py | 2 | ||||
-rw-r--r-- | tests/primitives/test_hash_vectors.py | 20 | ||||
-rw-r--r-- | tests/primitives/test_hashes.py | 23 | ||||
-rw-r--r-- | tests/primitives/test_openssl_vectors.py | 8 |
8 files changed, 82 insertions, 69 deletions
diff --git a/cryptography/bindings/openssl/backend.py b/cryptography/bindings/openssl/backend.py index 492f2e54..9c80be66 100644 --- a/cryptography/bindings/openssl/backend.py +++ b/cryptography/bindings/openssl/backend.py @@ -23,15 +23,6 @@ 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. @@ -99,8 +90,8 @@ class Backend(object): self.lib.OpenSSL_add_all_algorithms() self.lib.SSL_load_error_strings() - self._cipher_registry = {} - self._register_default_ciphers() + self.ciphers = Ciphers(self.ffi, self.lib) + self.hashes = Hashes(self.ffi, self.lib) def openssl_version_text(self): """ @@ -110,7 +101,25 @@ class Backend(object): """ return self.ffi.string(self.lib.OPENSSL_VERSION_TEXT).decode("ascii") - def supports_cipher(self, cipher, mode): + +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 Ciphers(object): + def __init__(self, ffi, lib): + super(Ciphers, self).__init__() + self.ffi = ffi + self.lib = lib + self._cipher_registry = {} + self._register_default_ciphers() + + def supported(self, cipher, mode): try: adapter = self._cipher_registry[type(cipher), type(mode)] except KeyError: @@ -142,8 +151,8 @@ class Backend(object): 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) + def create_encrypt_ctx(self, cipher, mode): + ctx, evp, iv_nonce = self._create_ctx(cipher, mode) res = self.lib.EVP_EncryptInit_ex(ctx, evp, self.ffi.NULL, cipher.key, iv_nonce) assert res != 0 @@ -152,8 +161,8 @@ class Backend(object): 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) + def create_decrypt_ctx(self, cipher, mode): + ctx, evp, iv_nonce = self._create_ctx(cipher, mode) res = self.lib.EVP_DecryptInit_ex(ctx, evp, self.ffi.NULL, cipher.key, iv_nonce) assert res != 0 @@ -162,7 +171,7 @@ class Backend(object): self.lib.EVP_CIPHER_CTX_set_padding(ctx, 0) return ctx - def _create_block_cipher_context(self, cipher, mode): + def _create_ctx(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)]( @@ -178,7 +187,7 @@ class Backend(object): return (ctx, evp_cipher, iv_nonce) - def update_encrypt_context(self, ctx, data): + def update_encrypt_ctx(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 *") @@ -186,7 +195,7 @@ class Backend(object): assert res != 0 return self.ffi.buffer(buf)[:outlen[0]] - def update_decrypt_context(self, ctx, data): + def update_decrypt_ctx(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 *") @@ -194,7 +203,7 @@ class Backend(object): assert res != 0 return self.ffi.buffer(buf)[:outlen[0]] - def finalize_encrypt_context(self, ctx): + def finalize_encrypt_ctx(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 *") @@ -204,7 +213,7 @@ class Backend(object): assert res == 1 return self.ffi.buffer(buf)[:outlen[0]] - def finalize_decrypt_context(self, ctx): + def finalize_decrypt_ctx(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 *") @@ -214,11 +223,18 @@ class Backend(object): assert res == 1 return self.ffi.buffer(buf)[:outlen[0]] - def supports_hash(self, hash_cls): + +class Hashes(object): + def __init__(self, ffi, lib): + super(Hashes, self).__init__() + self.ffi = ffi + self.lib = lib + + def supported(self, hash_cls): return (self.ffi.NULL != self.lib.EVP_get_digestbyname(hash_cls.name.encode("ascii"))) - def create_hash_context(self, hashobject): + def create_ctx(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")) @@ -227,11 +243,11 @@ class Backend(object): assert res != 0 return ctx - def update_hash_context(self, ctx, data): + def update_ctx(self, ctx, data): res = self.lib.EVP_DigestUpdate(ctx, data, len(data)) assert res != 0 - def finalize_hash_context(self, ctx, digest_size): + def finalize_ctx(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 @@ -239,7 +255,7 @@ class Backend(object): assert res == 1 return self.ffi.buffer(buf)[:digest_size] - def copy_hash_context(self, ctx): + def copy_ctx(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) diff --git a/cryptography/primitives/block/base.py b/cryptography/primitives/block/base.py index e9f52887..e9b949c0 100644 --- a/cryptography/primitives/block/base.py +++ b/cryptography/primitives/block/base.py @@ -39,19 +39,17 @@ class _CipherEncryptionContext(object): def __init__(self, cipher, mode, backend): super(_CipherEncryptionContext, self).__init__() self._backend = backend - self._ctx = self._backend.create_block_cipher_encrypt_context( - cipher, mode - ) + self._ctx = self._backend.ciphers.create_encrypt_ctx(cipher, mode) def update(self, data): if self._ctx is None: raise ValueError("Context was already finalized") - return self._backend.update_encrypt_context(self._ctx, data) + return self._backend.ciphers.update_encrypt_ctx(self._ctx, data) def finalize(self): if self._ctx is None: raise ValueError("Context was already finalized") - data = self._backend.finalize_encrypt_context(self._ctx) + data = self._backend.ciphers.finalize_encrypt_ctx(self._ctx) self._ctx = None return data @@ -61,18 +59,16 @@ class _CipherDecryptionContext(object): def __init__(self, cipher, mode, backend): super(_CipherDecryptionContext, self).__init__() self._backend = backend - self._ctx = self._backend.create_block_cipher_decrypt_context( - cipher, mode - ) + self._ctx = self._backend.ciphers.create_decrypt_ctx(cipher, mode) def update(self, data): if self._ctx is None: raise ValueError("Context was already finalized") - return self._backend.update_decrypt_context(self._ctx, data) + return self._backend.ciphers.update_decrypt_ctx(self._ctx, data) def finalize(self): if self._ctx is None: raise ValueError("Context was already finalized") - data = self._backend.finalize_decrypt_context(self._ctx) + data = self._backend.ciphers.finalize_decrypt_ctx(self._ctx) self._ctx = None return data diff --git a/cryptography/primitives/hashes.py b/cryptography/primitives/hashes.py index 4cd68adc..023041cb 100644 --- a/cryptography/primitives/hashes.py +++ b/cryptography/primitives/hashes.py @@ -27,7 +27,7 @@ class BaseHash(six.with_metaclass(abc.ABCMeta)): backend = _default_backend self._backend = backend if ctx is None: - self._ctx = self._backend.create_hash_context(self) + self._ctx = self._backend.hashes.create_ctx(self) else: self._ctx = None @@ -37,20 +37,20 @@ class BaseHash(six.with_metaclass(abc.ABCMeta)): def update(self, data): if isinstance(data, six.text_type): raise TypeError("Unicode-objects must be encoded before hashing") - self._backend.update_hash_context(self._ctx, data) + self._backend.hashes.update_ctx(self._ctx, data) def copy(self): return self.__class__(backend=self._backend, ctx=self._copy_ctx()) def digest(self): - return self._backend.finalize_hash_context(self._copy_ctx(), - self.digest_size) + return self._backend.hashes.finalize_ctx(self._copy_ctx(), + self.digest_size) def hexdigest(self): return str(binascii.hexlify(self.digest()).decode("ascii")) def _copy_ctx(self): - return self._backend.copy_hash_context(self._ctx) + return self._backend.hashes.copy_ctx(self._ctx) class SHA1(BaseHash): diff --git a/tests/bindings/test_openssl.py b/tests/bindings/test_openssl.py index bdfbed36..6f9c9d25 100644 --- a/tests/bindings/test_openssl.py +++ b/tests/bindings/test_openssl.py @@ -34,8 +34,8 @@ class TestOpenSSL(object): assert backend.openssl_version_text().startswith("OpenSSL") def test_supports_cipher(self): - assert backend.supports_cipher(None, None) is False + assert backend.ciphers.supported(None, None) is False def test_register_duplicate_cipher_adapter(self): with pytest.raises(ValueError): - backend.register_cipher_adapter(AES, CBC, None) + backend.ciphers.register_cipher_adapter(AES, CBC, None) diff --git a/tests/primitives/test_cryptrec.py b/tests/primitives/test_cryptrec.py index d8c9aaa3..5e0b12df 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 backend: backend.supports_cipher( + only_if=lambda backend: backend.ciphers.supported( 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 b42021c9..e3854726 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 backend: backend.supports_hash(hashes.SHA1), + only_if=lambda backend: backend.hashes.supported(hashes.SHA1), skip_message="Does not support SHA1", ) @@ -44,7 +44,7 @@ class TestSHA224(object): "SHA224ShortMsg.rsp", ], hashes.SHA224, - only_if=lambda backend: backend.supports_hash(hashes.SHA224), + only_if=lambda backend: backend.hashes.supported(hashes.SHA224), skip_message="Does not support SHA224", ) @@ -58,7 +58,7 @@ class TestSHA256(object): "SHA256ShortMsg.rsp", ], hashes.SHA256, - only_if=lambda backend: backend.supports_hash(hashes.SHA256), + only_if=lambda backend: backend.hashes.supported(hashes.SHA256), skip_message="Does not support SHA256", ) @@ -72,7 +72,7 @@ class TestSHA384(object): "SHA384ShortMsg.rsp", ], hashes.SHA384, - only_if=lambda backend: backend.supports_hash(hashes.SHA384), + only_if=lambda backend: backend.hashes.supported(hashes.SHA384), skip_message="Does not support SHA384", ) @@ -86,7 +86,7 @@ class TestSHA512(object): "SHA512ShortMsg.rsp", ], hashes.SHA512, - only_if=lambda backend: backend.supports_hash(hashes.SHA512), + only_if=lambda backend: backend.hashes.supported(hashes.SHA512), skip_message="Does not support SHA512", ) @@ -99,14 +99,14 @@ class TestRIPEMD160(object): "ripevectors.txt", ], hashes.RIPEMD160, - only_if=lambda backend: backend.supports_hash(hashes.RIPEMD160), + only_if=lambda backend: backend.hashes.supported(hashes.RIPEMD160), skip_message="Does not support RIPEMD160", ) test_RIPEMD160_long_string = generate_long_string_hash_test( hashes.RIPEMD160, "52783243c1697bdbe16d37f97f68f08325dc1528", - only_if=lambda backend: backend.supports_hash(hashes.RIPEMD160), + only_if=lambda backend: backend.hashes.supported(hashes.RIPEMD160), skip_message="Does not support RIPEMD160", ) @@ -119,7 +119,7 @@ class TestWhirlpool(object): "iso-test-vectors.txt", ], hashes.Whirlpool, - only_if=lambda backend: backend.supports_hash(hashes.Whirlpool), + only_if=lambda backend: backend.hashes.supported(hashes.Whirlpool), skip_message="Does not support Whirlpool", ) @@ -128,7 +128,7 @@ class TestWhirlpool(object): ("0c99005beb57eff50a7cf005560ddf5d29057fd86b2" "0bfd62deca0f1ccea4af51fc15490eddc47af32bb2b" "66c34ff9ad8c6008ad677f77126953b226e4ed8b01"), - only_if=lambda backend: backend.supports_hash(hashes.Whirlpool), + only_if=lambda backend: backend.hashes.supported(hashes.Whirlpool), skip_message="Does not support Whirlpool", ) @@ -141,6 +141,6 @@ class TestMD5(object): "rfc-1321.txt", ], hashes.MD5, - only_if=lambda backend: backend.supports_hash(hashes.MD5), + only_if=lambda backend: backend.hashes.supported(hashes.MD5), skip_message="Does not support MD5", ) diff --git a/tests/primitives/test_hashes.py b/tests/primitives/test_hashes.py index 2efda050..174fd5f4 100644 --- a/tests/primitives/test_hashes.py +++ b/tests/primitives/test_hashes.py @@ -39,17 +39,18 @@ class TestBaseHash(object): class TestCopyHash(object): def test_copy_backend_object(self): - pretend_backend = pretend.stub(copy_hash_context=lambda a: "copiedctx") + pretend_hashes = pretend.stub(copy_ctx=lambda a: "copiedctx") + pretend_backend = pretend.stub(hashes=pretend_hashes) pretend_ctx = pretend.stub() 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): +class TestDefaultBackendSHA1(object): def test_default_backend_creation(self): """ - This test assumes the presence of SHA1 in the default API. + This test assumes the presence of SHA1 in the default backend. """ h = hashes.SHA1() assert h._backend is _default_backend @@ -60,7 +61,7 @@ class TestSHA1(object): hashes.SHA1, digest_size=20, block_size=64, - only_if=lambda backend: backend.supports_hash(hashes.SHA1), + only_if=lambda backend: backend.hashes.supported(hashes.SHA1), skip_message="Does not support SHA1", ) @@ -70,7 +71,7 @@ class TestSHA224(object): hashes.SHA224, digest_size=28, block_size=64, - only_if=lambda backend: backend.supports_hash(hashes.SHA224), + only_if=lambda backend: backend.hashes.supported(hashes.SHA224), skip_message="Does not support SHA224", ) @@ -80,7 +81,7 @@ class TestSHA256(object): hashes.SHA256, digest_size=32, block_size=64, - only_if=lambda backend: backend.supports_hash(hashes.SHA256), + only_if=lambda backend: backend.hashes.supported(hashes.SHA256), skip_message="Does not support SHA256", ) @@ -90,7 +91,7 @@ class TestSHA384(object): hashes.SHA384, digest_size=48, block_size=128, - only_if=lambda backend: backend.supports_hash(hashes.SHA384), + only_if=lambda backend: backend.hashes.supported(hashes.SHA384), skip_message="Does not support SHA384", ) @@ -100,7 +101,7 @@ class TestSHA512(object): hashes.SHA512, digest_size=64, block_size=128, - only_if=lambda backend: backend.supports_hash(hashes.SHA512), + only_if=lambda backend: backend.hashes.supported(hashes.SHA512), skip_message="Does not support SHA512", ) @@ -110,7 +111,7 @@ class TestRIPEMD160(object): hashes.RIPEMD160, digest_size=20, block_size=64, - only_if=lambda backend: backend.supports_hash(hashes.RIPEMD160), + only_if=lambda backend: backend.hashes.supported(hashes.RIPEMD160), skip_message="Does not support RIPEMD160", ) @@ -120,7 +121,7 @@ class TestWhirlpool(object): hashes.Whirlpool, digest_size=64, block_size=64, - only_if=lambda backend: backend.supports_hash(hashes.Whirlpool), + only_if=lambda backend: backend.hashes.supported(hashes.Whirlpool), skip_message="Does not support Whirlpool", ) @@ -130,6 +131,6 @@ class TestMD5(object): hashes.MD5, digest_size=16, block_size=64, - only_if=lambda backend: backend.supports_hash(hashes.MD5), + only_if=lambda backend: backend.hashes.supported(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 ff42b169..0f242efc 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 backend: backend.supports_cipher( + only_if=lambda backend: backend.ciphers.supported( 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 backend: backend.supports_cipher( + only_if=lambda backend: backend.ciphers.supported( 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 backend: backend.supports_cipher( + only_if=lambda backend: backend.ciphers.supported( 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 backend: backend.supports_cipher( + only_if=lambda backend: backend.ciphers.supported( ciphers.AES("\x00" * 16), modes.CTR("\x00" * 16) ), skip_message="Does not support AES CTR", |