diff options
Diffstat (limited to 'cryptography/hazmat')
-rw-r--r-- | cryptography/hazmat/bindings/openssl/backend.py | 43 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/ciphers/base.py | 50 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/ciphers/modes.py | 11 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/interfaces.py | 18 |
4 files changed, 114 insertions, 8 deletions
diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 9f8ea939..08afa4d6 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -28,7 +28,7 @@ from cryptography.hazmat.primitives.ciphers.algorithms import ( AES, Blowfish, Camellia, CAST5, TripleDES, ARC4, ) from cryptography.hazmat.primitives.ciphers.modes import ( - CBC, CTR, ECB, OFB, CFB + CBC, CTR, ECB, OFB, CFB, GCM, ) @@ -186,6 +186,11 @@ class Backend(object): type(None), GetCipherByName("rc4") ) + self.register_cipher_adapter( + AES, + GCM, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") + ) def create_symmetric_encryption_ctx(self, cipher, mode): return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT) @@ -238,6 +243,9 @@ class _CipherContext(object): def __init__(self, backend, cipher, mode, operation): self._backend = backend self._cipher = cipher + self._mode = mode + self._operation = operation + self._tag = None ctx = self._backend.lib.EVP_CIPHER_CTX_new() ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_CIPHER_CTX_free) @@ -270,6 +278,20 @@ class _CipherContext(object): ctx, len(cipher.key) ) assert res != 0 + if isinstance(mode, GCM): + res = self._backend.lib.EVP_CIPHER_CTX_ctrl( + ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_IVLEN, + len(iv_nonce), self._backend.ffi.NULL + ) + assert res != 0 + if operation == self._DECRYPT: + assert mode.tag is not None + res = self._backend.lib.EVP_CIPHER_CTX_ctrl( + ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_TAG, + len(mode.tag), mode.tag + ) + assert res != 0 + # pass key/iv res = self._backend.lib.EVP_CipherInit_ex(ctx, self._backend.ffi.NULL, self._backend.ffi.NULL, @@ -298,10 +320,29 @@ class _CipherContext(object): if res == 0: self._backend._handle_error() + if (isinstance(self._mode, GCM) and + self._operation == self._ENCRYPT): + block_byte_size = self._cipher.block_size // 8 + tag_buf = self._backend.ffi.new("unsigned char[]", block_byte_size) + res = self._backend.lib.EVP_CIPHER_CTX_ctrl( + self._ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_GET_TAG, + block_byte_size, tag_buf + ) + assert res != 0 + size = self._cipher.block_size + self._tag = self._backend.ffi.buffer(tag_buf)[:size] + res = self._backend.lib.EVP_CIPHER_CTX_cleanup(self._ctx) assert res == 1 return self._backend.ffi.buffer(buf)[:outlen[0]] + def add_data(self, data): + outlen = self._backend.ffi.new("int *") + res = self._backend.lib.EVP_CipherUpdate( + self._ctx, self._backend.ffi.NULL, outlen, data, len(data) + ) + assert res != 0 + @utils.register_interface(interfaces.HashContext) class _HashContext(object): diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index 48e6da6f..5a4e7850 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -14,7 +14,7 @@ from __future__ import absolute_import, division, print_function from cryptography import utils -from cryptography.exceptions import AlreadyFinalized +from cryptography.exceptions import AlreadyFinalized, NotFinalized from cryptography.hazmat.primitives import interfaces @@ -28,20 +28,39 @@ class Cipher(object): self._backend = backend def encryptor(self): - return _CipherContext(self._backend.create_symmetric_encryption_ctx( - self.algorithm, self.mode - )) + if isinstance(self.mode, interfaces.ModeWithAAD): + return _AEADCipherContext( + self._backend.create_symmetric_encryption_ctx( + self.algorithm, self.mode + ) + ) + else: + return _CipherContext( + self._backend.create_symmetric_encryption_ctx( + self.algorithm, self.mode + ) + ) def decryptor(self): - return _CipherContext(self._backend.create_symmetric_decryption_ctx( - self.algorithm, self.mode - )) + if isinstance(self.mode, interfaces.ModeWithAAD): + return _AEADCipherContext( + self._backend.create_symmetric_decryption_ctx( + self.algorithm, self.mode + ) + ) + else: + return _CipherContext( + self._backend.create_symmetric_decryption_ctx( + self.algorithm, self.mode + ) + ) @utils.register_interface(interfaces.CipherContext) class _CipherContext(object): def __init__(self, ctx): self._ctx = ctx + self._tag = None def update(self, data): if self._ctx is None: @@ -52,5 +71,22 @@ class _CipherContext(object): if self._ctx is None: raise AlreadyFinalized("Context was already finalized") data = self._ctx.finalize() + self._tag = self._ctx._tag self._ctx = None return data + + +@utils.register_interface(interfaces.AEADCipherContext) +@utils.register_interface(interfaces.CipherContext) +class _AEADCipherContext(_CipherContext): + def add_data(self, data): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized") + self._ctx.add_data(data) + + @property + def tag(self): + if self._ctx is not None: + raise NotFinalized("You must finalize encryption before " + "getting the tag") + return self._tag diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py index 1d0de689..cb191d98 100644 --- a/cryptography/hazmat/primitives/ciphers/modes.py +++ b/cryptography/hazmat/primitives/ciphers/modes.py @@ -56,3 +56,14 @@ class CTR(object): def __init__(self, nonce): self.nonce = nonce + + +@utils.register_interface(interfaces.Mode) +@utils.register_interface(interfaces.ModeWithInitializationVector) +@utils.register_interface(interfaces.ModeWithAAD) +class GCM(object): + name = "GCM" + + def __init__(self, initialization_vector, tag=None): + self.initialization_vector = initialization_vector + self.tag = tag diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index 8cc9d42c..574c8226 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -56,6 +56,10 @@ class ModeWithNonce(six.with_metaclass(abc.ABCMeta)): """ +class ModeWithAAD(six.with_metaclass(abc.ABCMeta)): + pass + + class CipherContext(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def update(self, data): @@ -70,6 +74,20 @@ class CipherContext(six.with_metaclass(abc.ABCMeta)): """ +class AEADCipherContext(six.with_metaclass(abc.ABCMeta)): + @abc.abstractproperty + def tag(self): + """ + Returns tag bytes after finalizing encryption. + """ + + @abc.abstractmethod + def add_data(self, data): + """ + add_data takes bytes and returns nothing. + """ + + class PaddingContext(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def update(self, data): |