aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2013-10-24 16:23:50 -0700
committerAlex Gaynor <alex.gaynor@gmail.com>2013-10-24 16:23:50 -0700
commit9f17d497ade880a0316de304db19eac60fd49a5c (patch)
tree85a42dbd67879de29184ebb390072e2e039bed94
parent9f611ee88c02a4a4f407854e9589bb446ed1ec06 (diff)
parentacedb32800c486a8874ff6b7136f1db83adbc63b (diff)
downloadcryptography-9f17d497ade880a0316de304db19eac60fd49a5c.tar.gz
cryptography-9f17d497ade880a0316de304db19eac60fd49a5c.tar.bz2
cryptography-9f17d497ade880a0316de304db19eac60fd49a5c.zip
Merge pull request #178 from dreid/composable-contexts
[WIP] Reduce the backend's API surface by making it a vendor of implementation specific CipherContext providers.
-rw-r--r--cryptography/bindings/openssl/backend.py104
-rw-r--r--cryptography/primitives/block/base.py38
2 files changed, 66 insertions, 76 deletions
diff --git a/cryptography/bindings/openssl/backend.py b/cryptography/bindings/openssl/backend.py
index 6ddceb5a..4ec16189 100644
--- a/cryptography/bindings/openssl/backend.py
+++ b/cryptography/bindings/openssl/backend.py
@@ -111,10 +111,60 @@ class GetCipherByName(object):
return backend.lib.EVP_get_cipherbyname(cipher_name.encode("ascii"))
-class Ciphers(object):
- OPENSSL_ENCRYPT = 1
- OPENSSL_DECRYPT = 0
+@interfaces.register(interfaces.CipherContext)
+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 +204,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..7924cf9c 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 _CipherContext(
+ self._backend.ciphers.create_encrypt_ctx(self.cipher, self.mode))
def decryptor(self):
- return _CipherDecryptionContext(self.cipher, self.mode, self._backend)
+ return _CipherContext(
+ 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 _CipherContext(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