diff options
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 78 |
1 files changed, 76 insertions, 2 deletions
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 5e13bfc1..4054e56c 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -25,8 +25,8 @@ from cryptography.exceptions import ( UnsupportedAlgorithm, _Reasons ) from cryptography.hazmat.backends.interfaces import ( - CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend, - RSABackend + CipherBackend, CMACBackend, DSABackend, HMACBackend, HashBackend, + PBKDF2HMACBackend, RSABackend ) from cryptography.hazmat.bindings.openssl.binding import Binding from cryptography.hazmat.primitives import hashes, interfaces @@ -47,6 +47,7 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError", @utils.register_interface(CipherBackend) +@utils.register_interface(CMACBackend) @utils.register_interface(DSABackend) @utils.register_interface(HashBackend) @utils.register_interface(HMACBackend) @@ -554,6 +555,12 @@ class Backend(object): return self._ffi.buffer(buf)[:res] + def cmac_supported(self): + return backend._lib.Cryptography_HAS_CMAC == 1 + + def create_cmac_ctx(self, algorithm): + return _CMACContext(self, algorithm) + class GetCipherByName(object): def __init__(self, fmt): @@ -1240,4 +1247,71 @@ class _RSAVerificationContext(object): raise InvalidSignature +@utils.register_interface(interfaces.CMACContext) +class _CMACContext(object): + def __init__(self, backend, algorithm, ctx=None): + + if not backend.cmac_supported(): + raise UnsupportedAlgorithm("This backend does not support CMAC") + + self._backend = backend + self._key = algorithm.key + self._algorithm = algorithm + self._output_length = algorithm.block_size // 8 + + if ctx is None: + registry = self._backend._cipher_registry + try: + adapter = registry[type(algorithm), CBC] + except KeyError: + raise UnsupportedAlgorithm( + "cipher {0} is not supported by this backend".format( + algorithm.name), _Reasons.UNSUPPORTED_CIPHER + ) + + evp_cipher = adapter(self._backend, algorithm, CBC) + if evp_cipher == self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "cipher {0} is not supported by this backend".format( + algorithm.name), _Reasons.UNSUPPORTED_CIPHER + ) + + ctx = self._backend._lib.CMAC_CTX_new() + self._backend._lib.CMAC_Init( + ctx, self._key, len(self._key), + evp_cipher, self._backend._ffi.NULL + ) + + self._ctx = ctx + + def update(self, data): + res = self._backend._lib.CMAC_Update(self._ctx, data, len(data)) + assert res == 1 + + def finalize(self): + buf = self._backend._ffi.new("unsigned char[]", self._output_length) + length = self._backend._ffi.new("size_t *", self._output_length) + res = self._backend._lib.CMAC_Final( + self._ctx, buf, length + ) + assert res == 1 + + self._backend._lib.CMAC_CTX_free(self._ctx) + return self._backend._ffi.buffer(buf)[:] + + def copy(self): + copied_ctx = self._backend._lib.CMAC_CTX_new() + self._backend._lib.CMAC_CTX_init(copied_ctx) + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.CMAC_CTX_free() + ) + res = self._backend._lib.CMAC_CTX_copy( + copied_ctx, self._ctx + ) + assert res != 0 + return _CMACContext( + self._backend, self.algorithm, ctx=copied_ctx + ) + + backend = Backend() |