From ee6f8cec48028aeab213404dbce04bb6441a473c Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 12 Nov 2013 11:25:43 -0800 Subject: Get a HashContext from the backend like we do a CipherContext --- cryptography/hazmat/bindings/openssl/backend.py | 74 +++++++++++++++---------- cryptography/hazmat/primitives/hashes.py | 9 ++- tests/hazmat/primitives/test_hashes.py | 6 +- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 1cb886dc..86c6f660 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -269,47 +269,61 @@ class Ciphers(object): _CipherContext._DECRYPT) -class Hashes(object): - def __init__(self, backend): - super(Hashes, self).__init__() +@interfaces.register(interfaces.HashContext) +class _HashContext(object): + def __init__(self, backend, algorithm, ctx=None): + self.algorithm = algorithm + self._backend = backend - def supported(self, hash_cls): - return (self._backend.ffi.NULL != - self._backend.lib.EVP_get_digestbyname( - hash_cls.name.encode("ascii"))) + if ctx is None: + ctx = self._backend.lib.EVP_MD_CTX_create() + ctx = self._backend.ffi.gc(ctx, + self._backend.lib.EVP_MD_CTX_destroy) + evp_md = self._backend.lib.EVP_get_digestbyname( + algorithm.name.encode("ascii")) + assert evp_md != self._backend.ffi.NULL + res = self._backend.lib.EVP_DigestInit_ex(ctx, evp_md, + self._backend.ffi.NULL) + assert res != 0 - def create_ctx(self, hashobject): - ctx = self._backend.lib.EVP_MD_CTX_create() - ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_MD_CTX_destroy) - evp_md = self._backend.lib.EVP_get_digestbyname( - hashobject.name.encode("ascii")) - assert evp_md != self._backend.ffi.NULL - res = self._backend.lib.EVP_DigestInit_ex(ctx, evp_md, - self._backend.ffi.NULL) + self._ctx = ctx + + def copy(self): + copied_ctx = self._backend.lib.EVP_MD_CTX_create() + copied_ctx = self._backend.ffi.gc(copied_ctx, + self._backend.lib.EVP_MD_CTX_destroy) + res = self._backend.lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx) assert res != 0 - return ctx + return _HashContext(self._backend, self.algorithm, ctx=copied_ctx) - def update_ctx(self, ctx, data): - res = self._backend.lib.EVP_DigestUpdate(ctx, data, len(data)) + def update(self, data): + res = self._backend.lib.EVP_DigestUpdate(self._ctx, data, len(data)) assert res != 0 - def finalize_ctx(self, ctx, digest_size): - buf = self._backend.ffi.new("unsigned char[]", digest_size) - res = self._backend.lib.EVP_DigestFinal_ex(ctx, buf, + def finalize(self): + buf = self._backend.ffi.new("unsigned char[]", + self.algorithm.digest_size) + res = self._backend.lib.EVP_DigestFinal_ex(self._ctx, buf, self._backend.ffi.NULL) assert res != 0 - res = self._backend.lib.EVP_MD_CTX_cleanup(ctx) + res = self._backend.lib.EVP_MD_CTX_cleanup(self._ctx) assert res == 1 - return self._backend.ffi.buffer(buf)[:digest_size] + return self._backend.ffi.buffer(buf)[:self.algorithm.digest_size] - def copy_ctx(self, ctx): - copied_ctx = self._backend.lib.EVP_MD_CTX_create() - copied_ctx = self._backend.ffi.gc(copied_ctx, - self._backend.lib.EVP_MD_CTX_destroy) - res = self._backend.lib.EVP_MD_CTX_copy_ex(copied_ctx, ctx) - assert res != 0 - return copied_ctx + +class Hashes(object): + def __init__(self, backend): + super(Hashes, self).__init__() + self._backend = backend + + def supported(self, algorithm): + return (self._backend.ffi.NULL != + self._backend.lib.EVP_get_digestbyname( + algorithm.name.encode("ascii"))) + + def create_ctx(self, algorithm): + return _HashContext(self._backend, algorithm) class HMACs(object): diff --git a/cryptography/hazmat/primitives/hashes.py b/cryptography/hazmat/primitives/hashes.py index bdad5e16..c14d0437 100644 --- a/cryptography/hazmat/primitives/hashes.py +++ b/cryptography/hazmat/primitives/hashes.py @@ -34,20 +34,19 @@ class Hash(object): if ctx is None: self._ctx = self._backend.hashes.create_ctx(self.algorithm) else: - self._ctx = None + self._ctx = ctx def update(self, data): if isinstance(data, six.text_type): raise TypeError("Unicode-objects must be encoded before hashing") - self._backend.hashes.update_ctx(self._ctx, data) + self._ctx.update(data) def copy(self): return self.__class__(self.algorithm, backend=self._backend, - ctx=self._backend.hashes.copy_ctx(self._ctx)) + ctx=self._ctx.copy()) def finalize(self): - return self._backend.hashes.finalize_ctx(self._ctx, - self.algorithm.digest_size) + return self._ctx.finalize() @interfaces.register(interfaces.HashAlgorithm) diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py index 07ab2489..6cdb0a07 100644 --- a/tests/hazmat/primitives/test_hashes.py +++ b/tests/hazmat/primitives/test_hashes.py @@ -32,9 +32,9 @@ class TestHashContext(object): m.update(six.u("\u00FC")) def test_copy_backend_object(self): - pretend_hashes = pretend.stub(copy_ctx=lambda a: "copiedctx") - pretend_backend = pretend.stub(hashes=pretend_hashes) - pretend_ctx = pretend.stub() + pretend_backend = pretend.stub() + copied_ctx = pretend.stub() + pretend_ctx = pretend.stub(copy=lambda: copied_ctx) h = hashes.Hash(hashes.SHA1(), backend=pretend_backend, ctx=pretend_ctx) assert h._backend is pretend_backend -- cgit v1.2.3 From ad3102ad806225448bf7274a2c5893cc74eda98e Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 12 Nov 2013 13:26:26 -0800 Subject: Reflow Hashes.supported. --- cryptography/hazmat/bindings/openssl/backend.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 86c6f660..235a8e30 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -318,9 +318,10 @@ class Hashes(object): self._backend = backend def supported(self, algorithm): - return (self._backend.ffi.NULL != - self._backend.lib.EVP_get_digestbyname( - algorithm.name.encode("ascii"))) + digest = self._backend.lib.EVP_get_digestbyname( + algorithm.name.encode("ascii") + ) + return digest != self._backend.ffi.NULL def create_ctx(self, algorithm): return _HashContext(self._backend, algorithm) -- cgit v1.2.3 From a43b6697255a8488cbd7e75182d06bf97bf86750 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 12 Nov 2013 15:35:49 -0600 Subject: GCM loader support --- tests/test_utils.py | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/utils.py | 6 ++- 2 files changed, 135 insertions(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index af575b37..4dede2e7 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -268,3 +268,133 @@ def test_load_vectors_from_file(): ), } ] + + +def test_load_nist_gcm_vectors(): + vector_data = textwrap.dedent(""" + [Keylen = 128] + [IVlen = 96] + [PTlen = 0] + [AADlen = 0] + [Taglen = 128] + + Count = 0 + Key = 11754cd72aec309bf52f7687212e8957 + IV = 3c819d9a9bed087615030b65 + PT = + AAD = + CT = + Tag = 250327c674aaf477aef2675748cf6971 + + Count = 1 + Key = 272f16edb81a7abbea887357a58c1917 + IV = 794ec588176c703d3d2a7a07 + PT = + AAD = + CT = + Tag = b6e6f197168f5049aeda32dafbdaeb + + Count = 2 + Key = a49a5e26a2f8cb63d05546c2a62f5343 + IV = 907763b19b9b4ab6bd4f0281 + CT = + AAD = + Tag = a2be08210d8c470a8df6e8fbd79ec5cf + FAIL + + Count = 3 + Key = 5c1155084cc0ede76b3bc22e9f7574ef + IV = 9549e4ba69a61cad7856efc1 + PT = d1448fa852b84408e2dad8381f363de7 + AAD = e98e9d9c618e46fef32660976f854ee3 + CT = f78b60ca125218493bea1c50a2e12ef4 + Tag = d72da7f5c6cf0bca7242c71835809449 + + [Keylen = 128] + [IVlen = 96] + [PTlen = 0] + [AADlen = 0] + [Taglen = 120] + + Count = 0 + Key = eac258e99c55e6ae8ef1da26640613d7 + IV = 4e8df20faaf2c8eebe922902 + CT = + AAD = + Tag = e39aeaebe86aa309a4d062d6274339 + PT = + + Count = 1 + Key = 3726cf02fcc6b8639a5497652c94350d + IV = 55fef82cde693ce76efcc193 + CT = + AAD = + Tag = 3d68111a81ed22d2ef5bccac4fc27f + FAIL + + Count = 2 + Key = f202299d5fd74f03b12d2119a6c4c038 + IV = eec51e7958c3f20a1bb71815 + CT = + AAD = + Tag = a81886b3fb26e51fca87b267e1e157 + FAIL + + Count = 3 + Key = fd52925f39546b4c55ffb6b20c59898c + IV = f5cf3227444afd905a5f6dba + CT = + AAD = + Tag = 1665b0f1a0b456e1664cfd3de08ccd + PT = + """).splitlines() + assert load_nist_vectors(vector_data) == [ + {'aad': b'', + 'pt': b'', + 'iv': b'4e8df20faaf2c8eebe922902', + 'tag': b'e39aeaebe86aa309a4d062d6274339', + 'key': b'eac258e99c55e6ae8ef1da26640613d7', + 'ct': b''}, + {'aad': b'', + 'iv': b'55fef82cde693ce76efcc193', + 'tag': b'3d68111a81ed22d2ef5bccac4fc27f', + 'key': b'3726cf02fcc6b8639a5497652c94350d', + 'ct': b'', + 'fail': True}, + {'aad': b'', + 'iv': b'eec51e7958c3f20a1bb71815', + 'tag': b'a81886b3fb26e51fca87b267e1e157', + 'key': b'f202299d5fd74f03b12d2119a6c4c038', + 'ct': b'', + 'fail': True}, + {'aad': b'', + 'pt': b'', + 'iv': b'f5cf3227444afd905a5f6dba', + 'tag': b'1665b0f1a0b456e1664cfd3de08ccd', + 'key': b'fd52925f39546b4c55ffb6b20c59898c', + 'ct': b''}, + {'aad': b'', + 'pt': b'', + 'iv': b'3c819d9a9bed087615030b65', + 'tag': b'250327c674aaf477aef2675748cf6971', + 'key': b'11754cd72aec309bf52f7687212e8957', + 'ct': b''}, + {'aad': b'', + 'pt': b'', + 'iv': b'794ec588176c703d3d2a7a07', + 'tag': b'b6e6f197168f5049aeda32dafbdaeb', + 'key': b'272f16edb81a7abbea887357a58c1917', + 'ct': b''}, + {'aad': b'', + 'iv': b'907763b19b9b4ab6bd4f0281', + 'tag': b'a2be08210d8c470a8df6e8fbd79ec5cf', + 'key': b'a49a5e26a2f8cb63d05546c2a62f5343', + 'ct': b'', + 'fail': True}, + {'aad': b'e98e9d9c618e46fef32660976f854ee3', + 'pt': b'd1448fa852b84408e2dad8381f363de7', + 'iv': b'9549e4ba69a61cad7856efc1', + 'tag': b'd72da7f5c6cf0bca7242c71835809449', + 'key': b'5c1155084cc0ede76b3bc22e9f7574ef', + 'ct': b'f78b60ca125218493bea1c50a2e12ef4'}, + ] diff --git a/tests/utils.py b/tests/utils.py index df9232d8..8fa9af92 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -43,8 +43,12 @@ def load_nist_vectors(vector_data): section = line[1:-1] continue + if line.strip() == "FAIL": + data[section, count]["fail"] = True + continue + # Build our data using a simple Key = Value format - name, value = line.split(" = ") + name, value = [c.strip() for c in line.split("=")] # COUNT is a special token that indicates a new block of data if name.upper() == "COUNT": -- cgit v1.2.3 From 73278747b04c3bfca3972d69a917c194db6c24e3 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 12 Nov 2013 14:27:19 -0800 Subject: Drop random support for weird inheritance --- cryptography/hazmat/bindings/openssl/backend.py | 3 --- cryptography/hazmat/primitives/ciphers/algorithms.py | 6 ------ cryptography/hazmat/primitives/ciphers/base.py | 2 -- cryptography/hazmat/primitives/ciphers/modes.py | 4 ---- cryptography/hazmat/primitives/hashes.py | 5 +++-- cryptography/hazmat/primitives/hmac.py | 9 ++++++--- cryptography/hazmat/primitives/padding.py | 3 --- 7 files changed, 9 insertions(+), 23 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 235a8e30..b65583df 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -207,7 +207,6 @@ class _CipherContext(object): class Ciphers(object): def __init__(self, backend): - super(Ciphers, self).__init__() self._backend = backend self._cipher_registry = {} self._register_default_ciphers() @@ -314,7 +313,6 @@ class _HashContext(object): class Hashes(object): def __init__(self, backend): - super(Hashes, self).__init__() self._backend = backend def supported(self, algorithm): @@ -329,7 +327,6 @@ class Hashes(object): class HMACs(object): def __init__(self, backend): - super(HMACs, self).__init__() self._backend = backend def create_ctx(self, key, hash_cls): diff --git a/cryptography/hazmat/primitives/ciphers/algorithms.py b/cryptography/hazmat/primitives/ciphers/algorithms.py index cbfaceb8..32acab14 100644 --- a/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -20,7 +20,6 @@ class AES(object): key_sizes = frozenset([128, 192, 256]) def __init__(self, key): - super(AES, self).__init__() self.key = key # Verify that the key size matches the expected key size @@ -40,7 +39,6 @@ class Camellia(object): key_sizes = frozenset([128, 192, 256]) def __init__(self, key): - super(Camellia, self).__init__() self.key = key # Verify that the key size matches the expected key size @@ -60,7 +58,6 @@ class TripleDES(object): key_sizes = frozenset([64, 128, 192]) def __init__(self, key): - super(TripleDES, self).__init__() if len(key) == 8: key += key + key elif len(key) == 16: @@ -84,7 +81,6 @@ class Blowfish(object): key_sizes = frozenset(range(32, 449, 8)) def __init__(self, key): - super(Blowfish, self).__init__() self.key = key # Verify that the key size matches the expected key size @@ -104,7 +100,6 @@ class CAST5(object): key_sizes = frozenset([40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128]) def __init__(self, key): - super(CAST5, self).__init__() self.key = key # Verify that the key size matches the expected key size @@ -123,7 +118,6 @@ class ARC4(object): key_sizes = frozenset([40, 56, 64, 80, 128, 192, 256]) def __init__(self, key): - super(ARC4, self).__init__() self.key = key # Verify that the key size matches the expected key size diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index 1599308c..d48f9cc7 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -18,8 +18,6 @@ from cryptography.hazmat.primitives import interfaces class Cipher(object): def __init__(self, algorithm, mode, backend=None): - super(Cipher, self).__init__() - if backend is None: from cryptography.hazmat.bindings import ( _default_backend as backend, diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py index e54872a6..915fd83d 100644 --- a/cryptography/hazmat/primitives/ciphers/modes.py +++ b/cryptography/hazmat/primitives/ciphers/modes.py @@ -22,7 +22,6 @@ class CBC(object): name = "CBC" def __init__(self, initialization_vector): - super(CBC, self).__init__() self.initialization_vector = initialization_vector @@ -37,7 +36,6 @@ class OFB(object): name = "OFB" def __init__(self, initialization_vector): - super(OFB, self).__init__() self.initialization_vector = initialization_vector @@ -47,7 +45,6 @@ class CFB(object): name = "CFB" def __init__(self, initialization_vector): - super(CFB, self).__init__() self.initialization_vector = initialization_vector @@ -57,5 +54,4 @@ class CTR(object): name = "CTR" def __init__(self, nonce): - super(CTR, self).__init__() self.nonce = nonce diff --git a/cryptography/hazmat/primitives/hashes.py b/cryptography/hazmat/primitives/hashes.py index c14d0437..6ae622cd 100644 --- a/cryptography/hazmat/primitives/hashes.py +++ b/cryptography/hazmat/primitives/hashes.py @@ -42,8 +42,9 @@ class Hash(object): self._ctx.update(data) def copy(self): - return self.__class__(self.algorithm, backend=self._backend, - ctx=self._ctx.copy()) + return Hash( + self.algorithm, backend=self._backend, ctx=self._ctx.copy() + ) def finalize(self): return self._ctx.finalize() diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py index 1457ed78..ed2dd54a 100644 --- a/cryptography/hazmat/primitives/hmac.py +++ b/cryptography/hazmat/primitives/hmac.py @@ -21,7 +21,6 @@ from cryptography.hazmat.primitives import interfaces @interfaces.register(interfaces.HashContext) class HMAC(object): def __init__(self, key, algorithm, ctx=None, backend=None): - super(HMAC, self).__init__() if not isinstance(algorithm, interfaces.HashAlgorithm): raise TypeError("Expected instance of interfaces.HashAlgorithm.") self.algorithm = algorithm @@ -43,8 +42,12 @@ class HMAC(object): self._backend.hmacs.update_ctx(self._ctx, msg) def copy(self): - return self.__class__(self._key, self.algorithm, backend=self._backend, - ctx=self._backend.hmacs.copy_ctx(self._ctx)) + return HMAC( + self._key, + self.algorithm, + backend=self._backend, + ctx=self._backend.hmacs.copy_ctx(self._ctx) + ) def finalize(self): return self._backend.hmacs.finalize_ctx(self._ctx, diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index eac18c2a..f41c62c3 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -18,7 +18,6 @@ from cryptography.hazmat.primitives import interfaces class PKCS7(object): def __init__(self, block_size): - super(PKCS7, self).__init__() if not (0 <= block_size < 256): raise ValueError("block_size must be in range(0, 256)") @@ -37,7 +36,6 @@ class PKCS7(object): @interfaces.register(interfaces.PaddingContext) class _PKCS7PaddingContext(object): def __init__(self, block_size): - super(_PKCS7PaddingContext, self).__init__() self.block_size = block_size # TODO: O(n ** 2) complexity for repeated concatentation, we should use # zero-buffer (#193) @@ -72,7 +70,6 @@ class _PKCS7PaddingContext(object): @interfaces.register(interfaces.PaddingContext) class _PKCS7UnpaddingContext(object): def __init__(self, block_size): - super(_PKCS7UnpaddingContext, self).__init__() self.block_size = block_size # TODO: O(n ** 2) complexity for repeated concatentation, we should use # zero-buffer (#193) -- cgit v1.2.3 From 3f3921e2d082fd99c6186ed7bb174caf481819bd Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 12 Nov 2013 14:27:55 -0800 Subject: Don't query OpenSSL for block sizes, we already know them --- cryptography/hazmat/bindings/openssl/backend.py | 7 +++---- cryptography/hazmat/primitives/ciphers/algorithms.py | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 235a8e30..89ee2b53 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -140,6 +140,7 @@ class _CipherContext(object): def __init__(self, backend, cipher, mode, operation): self._backend = backend + self._cipher = cipher ctx = self._backend.lib.EVP_CIPHER_CTX_new() ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_CIPHER_CTX_free) @@ -185,9 +186,8 @@ class _CipherContext(object): 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) + len(data) + self._cipher.block_size - 1) outlen = self._backend.ffi.new("int *") res = self._backend.lib.EVP_CipherUpdate(self._ctx, buf, outlen, data, len(data)) @@ -195,8 +195,7 @@ class _CipherContext(object): 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) + buf = self._backend.ffi.new("unsigned char[]", self._cipher.block_size) outlen = self._backend.ffi.new("int *") res = self._backend.lib.EVP_CipherFinal_ex(self._ctx, buf, outlen) assert res != 0 diff --git a/cryptography/hazmat/primitives/ciphers/algorithms.py b/cryptography/hazmat/primitives/ciphers/algorithms.py index cbfaceb8..61e93b0e 100644 --- a/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -120,6 +120,7 @@ class CAST5(object): class ARC4(object): name = "RC4" + block_size = 1 key_sizes = frozenset([40, 56, 64, 80, 128, 192, 256]) def __init__(self, key): -- cgit v1.2.3