From 9188b01511849d3731e838decfcaece475d5d7ba Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 24 Oct 2013 11:33:36 -0700 Subject: Initial refactoring of backend specific contexts. --- cryptography/bindings/openssl/backend.py | 103 +++++++++++++++++-------------- cryptography/primitives/block/base.py | 38 +++--------- 2 files changed, 65 insertions(+), 76 deletions(-) diff --git a/cryptography/bindings/openssl/backend.py b/cryptography/bindings/openssl/backend.py index 6ddceb5a..99124e1c 100644 --- a/cryptography/bindings/openssl/backend.py +++ b/cryptography/bindings/openssl/backend.py @@ -111,10 +111,59 @@ class GetCipherByName(object): return backend.lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) -class Ciphers(object): - OPENSSL_ENCRYPT = 1 - OPENSSL_DECRYPT = 0 +class _CipherContext(object): + _ENCRYPT = 1 + _DECRYPT = 0 + + def __init__(self, backend, cipher, mode, operation): + self._backend = backend + + ctx = self._backend.lib.EVP_CIPHER_CTX_new() + ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_CIPHER_CTX_free) + + registry = self._backend.ciphers._cipher_registry + evp_cipher = registry[type(cipher), type(mode)]( + self._backend, cipher, mode + ) + assert evp_cipher != self._backend.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._backend.ffi.NULL + res = self._backend.lib.EVP_CipherInit_ex(ctx, evp_cipher, + self._backend.ffi.NULL, + cipher.key, iv_nonce, + operation) + assert res != 0 + # We purposely disable padding here as it's handled higher up in the + # API. + self._backend.lib.EVP_CIPHER_CTX_set_padding(ctx, 0) + self._ctx = ctx + + def update(self, data): + block_size = self._backend.lib.EVP_CIPHER_CTX_block_size(self._ctx) + buf = self._backend.ffi.new("unsigned char[]", + len(data) + block_size - 1) + outlen = self._backend.ffi.new("int *") + res = self._backend.lib.EVP_CipherUpdate(self._ctx, buf, outlen, data, + len(data)) + assert res != 0 + return self._backend.ffi.buffer(buf)[:outlen[0]] + + def finalize(self): + block_size = self._backend.lib.EVP_CIPHER_CTX_block_size(self._ctx) + buf = self._backend.ffi.new("unsigned char[]", block_size) + outlen = self._backend.ffi.new("int *") + res = self._backend.lib.EVP_CipherFinal_ex(self._ctx, buf, outlen) + assert res != 0 + res = self._backend.lib.EVP_CIPHER_CTX_cleanup(self._ctx) + assert res == 1 + return self._backend.ffi.buffer(buf)[:outlen[0]] + +class Ciphers(object): def __init__(self, backend): super(Ciphers, self).__init__() self._backend = backend @@ -154,52 +203,12 @@ class Ciphers(object): ) def create_encrypt_ctx(self, cipher, mode): - return self._create_ctx(cipher, mode, self.OPENSSL_ENCRYPT) + return _CipherContext(self._backend, cipher, mode, + _CipherContext._ENCRYPT) def create_decrypt_ctx(self, cipher, mode): - return self._create_ctx(cipher, mode, self.OPENSSL_DECRYPT) - - def _create_ctx(self, cipher, mode, enc): - ctx = self._backend.lib.EVP_CIPHER_CTX_new() - ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_CIPHER_CTX_free) - evp_cipher = self._cipher_registry[type(cipher), type(mode)]( - self._backend, cipher, mode - ) - assert evp_cipher != self._backend.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._backend.ffi.NULL - res = self._backend.lib.EVP_CipherInit_ex(ctx, evp_cipher, - self._backend.ffi.NULL, - cipher.key, iv_nonce, enc) - assert res != 0 - # We purposely disable padding here as it's handled higher up in the - # API. - self._backend.lib.EVP_CIPHER_CTX_set_padding(ctx, 0) - return ctx - - def update_ctx(self, ctx, data): - block_size = self._backend.lib.EVP_CIPHER_CTX_block_size(ctx) - buf = self._backend.ffi.new("unsigned char[]", - len(data) + block_size - 1) - outlen = self._backend.ffi.new("int *") - res = self._backend.lib.EVP_CipherUpdate(ctx, buf, outlen, data, - len(data)) - assert res != 0 - return self._backend.ffi.buffer(buf)[:outlen[0]] - - def finalize_ctx(self, ctx): - block_size = self._backend.lib.EVP_CIPHER_CTX_block_size(ctx) - buf = self._backend.ffi.new("unsigned char[]", block_size) - outlen = self._backend.ffi.new("int *") - res = self._backend.lib.EVP_CipherFinal_ex(ctx, buf, outlen) - assert res != 0 - res = self._backend.lib.EVP_CIPHER_CTX_cleanup(ctx) - assert res == 1 - return self._backend.ffi.buffer(buf)[:outlen[0]] + return _CipherContext(self._backend, cipher, mode, + _CipherContext._DECRYPT) class Hashes(object): diff --git a/cryptography/primitives/block/base.py b/cryptography/primitives/block/base.py index 2d4623a8..e7559143 100644 --- a/cryptography/primitives/block/base.py +++ b/cryptography/primitives/block/base.py @@ -28,47 +28,27 @@ class BlockCipher(object): self._backend = backend def encryptor(self): - return _CipherEncryptionContext(self.cipher, self.mode, self._backend) + return _OneTimeCipherContext( + self._backend.ciphers.create_encrypt_ctx(self.cipher, self.mode)) def decryptor(self): - return _CipherDecryptionContext(self.cipher, self.mode, self._backend) + return _OneTimeCipherContext( + self._backend.ciphers.create_decrypt_ctx(self.cipher, self.mode)) @interfaces.register(interfaces.CipherContext) -class _CipherEncryptionContext(object): - def __init__(self, cipher, mode, backend): - super(_CipherEncryptionContext, self).__init__() - self._backend = backend - 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.ciphers.update_ctx(self._ctx, data) - - def finalize(self): - if self._ctx is None: - raise ValueError("Context was already finalized") - data = self._backend.ciphers.finalize_ctx(self._ctx) - self._ctx = None - return data - - -@interfaces.register(interfaces.CipherContext) -class _CipherDecryptionContext(object): - def __init__(self, cipher, mode, backend): - super(_CipherDecryptionContext, self).__init__() - self._backend = backend - self._ctx = self._backend.ciphers.create_decrypt_ctx(cipher, mode) +class _OneTimeCipherContext(object): + def __init__(self, ctx): + self._ctx = ctx def update(self, data): if self._ctx is None: raise ValueError("Context was already finalized") - return self._backend.ciphers.update_ctx(self._ctx, data) + return self._ctx.update(data) def finalize(self): if self._ctx is None: raise ValueError("Context was already finalized") - data = self._backend.ciphers.finalize_ctx(self._ctx) + data = self._ctx.finalize() self._ctx = None return data -- cgit v1.2.3 From 488c79487873d7c145bbd4afb81826f24234e500 Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 24 Oct 2013 14:41:17 -0700 Subject: Don't forget to provide an interface. --- cryptography/bindings/openssl/backend.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cryptography/bindings/openssl/backend.py b/cryptography/bindings/openssl/backend.py index 99124e1c..4ec16189 100644 --- a/cryptography/bindings/openssl/backend.py +++ b/cryptography/bindings/openssl/backend.py @@ -111,6 +111,7 @@ class GetCipherByName(object): return backend.lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) +@interfaces.register(interfaces.CipherContext) class _CipherContext(object): _ENCRYPT = 1 _DECRYPT = 0 -- cgit v1.2.3 From acedb32800c486a8874ff6b7136f1db83adbc63b Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 24 Oct 2013 16:03:36 -0700 Subject: Rename _OneTimeCipherContext --- cryptography/primitives/block/base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cryptography/primitives/block/base.py b/cryptography/primitives/block/base.py index e7559143..7924cf9c 100644 --- a/cryptography/primitives/block/base.py +++ b/cryptography/primitives/block/base.py @@ -28,16 +28,16 @@ class BlockCipher(object): self._backend = backend def encryptor(self): - return _OneTimeCipherContext( + return _CipherContext( self._backend.ciphers.create_encrypt_ctx(self.cipher, self.mode)) def decryptor(self): - return _OneTimeCipherContext( + return _CipherContext( self._backend.ciphers.create_decrypt_ctx(self.cipher, self.mode)) @interfaces.register(interfaces.CipherContext) -class _OneTimeCipherContext(object): +class _CipherContext(object): def __init__(self, ctx): self._ctx = ctx -- cgit v1.2.3