diff --git a/tests/tlstest.py b/tests/tlstest.py index f1930c8f6..1df22ccf7 100755 --- a/tests/tlstest.py +++ b/tests/tlstest.py @@ -921,10 +921,13 @@ def connect(): continue if cipher in ("aes128gcm", "aes256gcm") and \ implementation not in ("pycrypto", - "python"): + "python", "openssl"): continue - if cipher in ("chacha20-poly1305_draft00", "chacha20-poly1305", - "aes128ccm", "aes128ccm_8", "aes256ccm", "aes256ccm_8") \ + if cipher in ("aes128ccm", "aes128ccm_8", + "aes256ccm", "aes256ccm_8") and \ + implementation not in ("python", "openssl"): + continue + if cipher in ("chacha20-poly1305_draft00", "chacha20-poly1305") \ and implementation not in ("python", ): continue @@ -2211,11 +2214,13 @@ def server_bind(self): continue if cipher in ("aes128gcm", "aes256gcm") and \ implementation not in ("pycrypto", - "python"): + "python", "openssl"): + continue + if cipher in ("aes128ccm", "aes128ccm_8", + "aes256ccm", "aes256ccm_8") and \ + implementation not in ("python", "openssl"): continue - if cipher in ("chacha20-poly1305_draft00", "chacha20-poly1305", - "aes128ccm", "aes128ccm_8", - "aes256ccm", "aes256ccm_8") \ + if cipher in ("chacha20-poly1305_draft00", "chacha20-poly1305") \ and implementation not in ("python", ): continue diff --git a/tlslite/utils/aes.py b/tlslite/utils/aes.py index 5a038fb9f..830ff3718 100644 --- a/tlslite/utils/aes.py +++ b/tlslite/utils/aes.py @@ -7,10 +7,14 @@ class AES(object): def __init__(self, key, mode, IV, implementation): if len(key) not in (16, 24, 32): raise AssertionError() - if mode != 2: - raise AssertionError() - if len(IV) != 16: + if mode not in [2, 6]: raise AssertionError() + if mode == 2: + if len(IV) != 16: + raise AssertionError() + if mode == 6: + if len(IV) > 16: + raise AssertionError() self.isBlockCipher = True self.isAEAD = False self.block_size = 16 diff --git a/tlslite/utils/aesccm.py b/tlslite/utils/aesccm.py index 23b7c6aed..2bcf8a2d5 100644 --- a/tlslite/utils/aesccm.py +++ b/tlslite/utils/aesccm.py @@ -4,10 +4,9 @@ # from __future__ import division -from tlslite.utils.cryptomath import numberToByteArray, divceil -from tlslite.utils.python_aes import Python_AES -import sys -import array +from tlslite.utils import cryptomath +from tlslite.utils.cryptomath import numberToByteArray +from tlslite.utils import python_aes, openssl_aes class AESCCM(object): @@ -18,6 +17,10 @@ def __init__(self, key, implementation, rawAesEncrypt, tag_length=16): self.isAEAD = True self.key = key self.tagLength = tag_length + self._rawAesEncrypt = rawAesEncrypt + self.nonceLength = 12 + self.implementation = implementation + if len(self.key) == 16 and self.tagLength == 8: self.name = "aes128ccm_8" elif len(self.key) == 16 and self.tagLength == 16: @@ -27,10 +30,10 @@ def __init__(self, key, implementation, rawAesEncrypt, tag_length=16): else: assert len(self.key) == 32 and self.tagLength == 16 self.name = "aes256ccm" - self._rawAesEncrypt = rawAesEncrypt - self.implementation = implementation - self.nonceLength = 12 - self._cbc = Python_AES(self.key, 2, bytearray(b'\x00' * 16)) + + self._ctr = python_aes.new(self.key, 6, bytearray(b'\x00' * 16)) + self._cbc = python_aes.new(self.key, 2, bytearray(b'\x00' * 16)) + def _cbcmac_calc(self, nonce, aad, msg): L = 15 - len(nonce) @@ -89,7 +92,6 @@ def seal(self, nonce, msg, aad): raise ValueError("Bad nonce length") L = 15 - len(nonce) - auth_value = bytearray(self.tagLength) # We construct the key stream blocks. # S_0 is not used for encrypting the message, it is only used @@ -97,17 +99,14 @@ def seal(self, nonce, msg, aad): # S_1..S_n are used to encrypt the message. flags = L - 1 - s_0 = self._rawAesEncrypt(bytearray([flags]) + - nonce + numberToByteArray(0, L)) - - s_n = self._construct_s_n(msg, flags, nonce, L) - - enc_msg = self._xor(msg, s_n) + s_0 = bytearray([flags]) + nonce + numberToByteArray(0, L) + s_n = bytearray([flags]) + nonce + numberToByteArray(1, L) mac = self._cbcmac_calc(nonce, aad, msg) - - for i in range(self.tagLength): - auth_value[i] = mac[i] ^ s_0[i] + self._ctr.counter = s_0 + auth_value = self._ctr.encrypt(mac) + self._ctr.counter = s_n + enc_msg = self._ctr.encrypt(msg) ciphertext = enc_msg + auth_value return ciphertext @@ -122,61 +121,31 @@ def open(self, nonce, ciphertext, aad): return None L = 15 - len(nonce) - received_mac = bytearray(self.tagLength) flags = L - 1 # Same construction as in seal function - s_0 = self._rawAesEncrypt(bytearray([flags]) + - nonce + numberToByteArray(0, L)) + s_0 = bytearray([flags]) + nonce + numberToByteArray(0, L) + s_n = bytearray([flags]) + nonce + numberToByteArray(1, L) - s_n = self._construct_s_n(ciphertext, flags, nonce, L) + auth_value = ciphertext[-self.tagLength:] - msg = self._xor(ciphertext, s_n) + # We decrypt the auth value + self._ctr.counter = s_0 + received_mac = self._ctr.decrypt(auth_value) + self._ctr.counter = s_n + msg = self._ctr.decrypt(ciphertext) msg = msg[:-self.tagLength] - - auth_value = ciphertext[-self.tagLength:] computed_mac = self._cbcmac_calc(nonce, aad, msg) - # We decrypt the auth value - for i in range(self.tagLength): - received_mac[i] = auth_value[i] ^ s_0[i] # Compare the mac vlaue is the same as the one we computed if received_mac != computed_mac: return None return msg - def _construct_s_n(self, ciphertext, flags, nonce, L): - s_n = bytearray() - counter_lmt = divceil(len(ciphertext), 16) - for i in range(1, int(counter_lmt) + 1): - s_n += self._rawAesEncrypt(bytearray([flags]) + - nonce + numberToByteArray(i, L)) - return s_n - - if sys.version_info[0] >= 3: - def _xor(self, inp, s_n): - inp_added = -((8 - (len(inp) % 8)) % 8) or None - self._pad_with_zeroes(inp, 8) - msg = self._use_memoryview(inp, s_n)[:inp_added] - inp[:] = inp[:inp_added] - return msg - else: - def _xor(self, inp, s_n): - msg = bytearray(i ^ j for i, j in zip(inp, s_n)) - return msg - @staticmethod def _pad_with_zeroes(data, size): if len(data) % size != 0: zeroes_to_add = size - (len(data) % size) data += b'\x00' * zeroes_to_add - - @staticmethod - def _use_memoryview(msg, s_n): - msg_mv = memoryview(msg).cast('Q') - s_n_mv = memoryview(s_n).cast('Q') - enc_arr = array.array('Q', (i ^ j for i, j in zip(msg_mv, s_n_mv))) - enc_msg = bytearray(enc_arr.tobytes()) - return enc_msg diff --git a/tlslite/utils/aesgcm.py b/tlslite/utils/aesgcm.py index 1dccb4ca2..34e773807 100644 --- a/tlslite/utils/aesgcm.py +++ b/tlslite/utils/aesgcm.py @@ -14,6 +14,7 @@ # look-up table. from __future__ import division +from tlslite.utils import python_aes from .constanttime import ct_compare_digest from .cryptomath import bytesToNumber, numberToByteArray @@ -35,8 +36,10 @@ def __init__(self, key, implementation, rawAesEncrypt): self.name = "aes256gcm" else: raise AssertionError() + self.key = key self._rawAesEncrypt = rawAesEncrypt + self._ctr = python_aes.new(self.key, 6, bytearray(b'\x00' * 16)) # The GCM key is AES(0). h = bytesToNumber(self._rawAesEncrypt(bytearray(16))) @@ -53,18 +56,6 @@ def __init__(self, key, implementation, rawAesEncrypt): self._productTable[self._reverseBits(i+1)] = \ self._gcmAdd(self._productTable[self._reverseBits(i)], h) - def _rawAesCtrEncrypt(self, counter, inp): - """ - Encrypts (or decrypts) plaintext with AES-CTR. counter is modified. - """ - out = bytearray(len(inp)) - rawAesEncrypt = self._rawAesEncrypt - for i in range(0, len(out), 16): - mask = rawAesEncrypt(counter) - for j in range(i, min(len(out), i + 16)): - out[j] = inp[j] ^ mask[j-i] - self._inc32(counter) - return out def _auth(self, ciphertext, ad, tagMask): y = 0 @@ -125,7 +116,8 @@ def seal(self, nonce, plaintext, data): # The counter starts at 2 for the actual encryption. counter[-1] = 2 - ciphertext = self._rawAesCtrEncrypt(counter, plaintext) + self._ctr.counter = counter + ciphertext = self._ctr.encrypt(plaintext) tag = self._auth(ciphertext, data, tagMask) @@ -158,7 +150,8 @@ def open(self, nonce, ciphertext, data): # The counter starts at 2 for the actual decryption. counter[-1] = 2 - return self._rawAesCtrEncrypt(counter, ciphertext) + self._ctr.counter = counter + return self._ctr.decrypt(ciphertext) @staticmethod def _reverseBits(i): diff --git a/tlslite/utils/cipherfactory.py b/tlslite/utils/cipherfactory.py index ef418ace4..0ee43d4ef 100644 --- a/tlslite/utils/cipherfactory.py +++ b/tlslite/utils/cipherfactory.py @@ -11,6 +11,8 @@ from tlslite.utils import python_chacha20_poly1305 from tlslite.utils import python_rc4 from tlslite.utils import python_tripledes +from tlslite.utils import openssl_aesccm +from tlslite.utils import openssl_aesgcm from tlslite.utils import cryptomath @@ -53,7 +55,27 @@ def createAES(key, IV, implList=None): elif impl == "pycrypto" and cryptomath.pycryptoLoaded: return pycrypto_aes.new(key, 2, IV) elif impl == "python": - return python_aes.new(key, 2, IV) + return python_aes.new(key, 2, IV) + raise NotImplementedError() + +def createAESCTR(key, IV, implList=None): + """Create a new AESCTR object. + + :type key: str + :param key: A 16, 24, or 32 byte string. + + :type IV: str + :param IV: A 8 or 12 byte string + + :rtype: tlslite.utils.AES + :returns: An AES object. + """ + if implList is None: + implList = ["python"] + + for impl in implList: + if impl == "python": + return python_aes.new(key, 6, IV) raise NotImplementedError() def createAESGCM(key, implList=None): @@ -66,13 +88,15 @@ def createAESGCM(key, implList=None): :returns: An AESGCM object. """ if implList is None: - implList = ["pycrypto", "python"] + implList = ["pycrypto", "python", "openssl"] for impl in implList: if impl == "pycrypto" and cryptomath.pycryptoLoaded: return pycrypto_aesgcm.new(key) if impl == "python": return python_aesgcm.new(key) + if impl == "openssl" and cryptomath.m2cryptoLoaded: + return openssl_aesgcm.new(key) raise NotImplementedError() def createAESCCM(key, implList=None): @@ -86,11 +110,13 @@ def createAESCCM(key, implList=None): """ if implList is None: - implList = ["python"] + implList = ["python", "openssl"] for impl in implList: if impl == "python": return python_aesccm.new(key) + if impl == "openssl": + return openssl_aesccm.new(key) raise NotImplementedError() @@ -105,11 +131,13 @@ def createAESCCM_8(key, implList=None): """ if implList is None: - implList = ["python"] + implList = ["python", "openssl"] for impl in implList: if impl == "python": return python_aesccm.new(key, 8) + if impl == "openssl": + return openssl_aesccm.new(key) raise NotImplementedError() diff --git a/tlslite/utils/openssl_aes.py b/tlslite/utils/openssl_aes.py index fe077f2f7..75c3ff161 100644 --- a/tlslite/utils/openssl_aes.py +++ b/tlslite/utils/openssl_aes.py @@ -11,7 +11,11 @@ def new(key, mode, IV): # IV argument name is a part of the interface # pylint: disable=invalid-name - return OpenSSL_AES(key, mode, IV) + if mode == 2: + return OpenSSL_AES(key, mode, IV) + if mode == 6: + return OpenSSL_CTR(key, mode, IV) + class OpenSSL_AES(AES): @@ -58,3 +62,50 @@ def decrypt(self, ciphertext): def __del__(self): if self._context is not None: m2.cipher_ctx_free(self._context) + + + class OpenSSL_CTR(AES): + + def __init__(self, key, mode, IV): + # IV argument/field names are a part of the interface + # pylint: disable=invalid-name + AES.__init__(self, key, mode, IV, "openssl") + self._IV = IV + self.key = key + self._context = None + self._encrypt = None + + @property + def counter(self): + return self._IV + + @counter.setter + def counter(self, ctr): + self.__del__() + self._IV = ctr + self._init_context() + + def _init_context(self, encrypt=True): + if len(self.key) == 16: + cipherType = m2.aes_128_ctr() + if len(self.key) == 24: + cipherType = m2.aes_192_ctr() + if len(self.key) == 32: + cipherType = m2.aes_256_ctr() + self._context = m2.cipher_ctx_new() + m2.cipher_init(self._context, cipherType, self.key, self._IV, + int(encrypt)) + m2.cipher_set_padding(self._context, 0) + self._encrypt = encrypt + + def encrypt(self, plaintext): + ciphertext = m2.cipher_update(self._context, plaintext) + return bytearray(ciphertext) + + def decrypt(self, ciphertext): + plaintext = m2.cipher_update(self._context, ciphertext) + return bytearray(plaintext) + + def __del__(self): + if self._context is not None: + m2.cipher_ctx_free(self._context) diff --git a/tlslite/utils/openssl_aesccm.py b/tlslite/utils/openssl_aesccm.py new file mode 100644 index 000000000..cf42b633d --- /dev/null +++ b/tlslite/utils/openssl_aesccm.py @@ -0,0 +1,16 @@ +# Author: Ivan Nikolchev +# See the LICENSE file for legal information regarding use of this file. + +"""AESCCM with CTR and CBC from m2crypto""" + +from tlslite.utils.cryptomath import * +from tlslite.utils.aesccm import AESCCM +from tlslite.utils import openssl_aes +from tlslite.utils.rijndael import Rijndael + +if m2cryptoLoaded: + def new(key): + aesccm = AESCCM(key, "openssl", Rijndael(key, 16).encrypt) + aesccm._ctr = openssl_aes.new(key, 6, bytearray(b'\x00' * 16)) + aesccm._cbc = openssl_aes.new(key, 2, bytearray(b'\x00' * 16)) + return aesccm diff --git a/tlslite/utils/openssl_aesgcm.py b/tlslite/utils/openssl_aesgcm.py new file mode 100644 index 000000000..0d27c610c --- /dev/null +++ b/tlslite/utils/openssl_aesgcm.py @@ -0,0 +1,15 @@ +# Author: Ivan Nikolchev +# See the LICENSE file for legal information regarding use of this file. + +"""AESGCM with CTR from m2crypto""" + +from tlslite.utils.cryptomath import * +from tlslite.utils.aesgcm import AESGCM +from tlslite.utils import openssl_aes +from tlslite.utils.rijndael import Rijndael + +if m2cryptoLoaded: + def new(key): + aesgcm = AESGCM(key, "openssl", Rijndael(key, 16).encrypt) + aesgcm._ctr = openssl_aes.new(key, 6, bytearray(b'\x00' * 16)) + return aesgcm diff --git a/tlslite/utils/python_aes.py b/tlslite/utils/python_aes.py index e792823f1..fa91b5d09 100644 --- a/tlslite/utils/python_aes.py +++ b/tlslite/utils/python_aes.py @@ -5,7 +5,7 @@ from .aes import AES from .rijndael import Rijndael - +from .cryptomath import bytesToNumber, numberToByteArray __all__ = ['new', 'Python_AES'] @@ -13,7 +13,10 @@ def new(key, mode, IV): # IV argument name is a part of the interface # pylint: disable=invalid-name - return Python_AES(key, mode, IV) + if mode == 2: + return Python_AES(key, mode, IV) + elif mode == 6: + return Python_AES_CTR(key, mode, IV) class Python_AES(AES): @@ -75,3 +78,40 @@ def decrypt(self, ciphertext): self.IV = chainBytes[:] return ciphertextBytes + + +class Python_AES_CTR(AES): + def __init__(self, key, mode, IV): + super(Python_AES_CTR, self).__init__(key, mode, IV, "python") + self.rijndael = Rijndael(key, 16) + self.IV = IV + self._counter_bytes = 16 - len(self.IV) + self._counter = self.IV + bytearray(b'\x00' * self._counter_bytes) + + @property + def counter(self): + return self._counter + + @counter.setter + def counter(self, ctr): + self._counter = ctr + + def _counter_update(self): + counter_int = bytesToNumber(self._counter) + 1 + self._counter = numberToByteArray(counter_int, 16) + if self._counter_bytes > 0 and \ + self._counter[-self._counter_bytes:] == \ + bytearray(b'\xff' * self._counter_bytes): + raise OverflowError("CTR counter overflowed") + + def encrypt(self, plaintext): + + mask = bytearray() + while len(mask) < len(plaintext): + mask += self.rijndael.encrypt(self._counter) + self._counter_update() + inp_bytes = bytearray(i ^ j for i, j in zip(plaintext, mask)) + return inp_bytes + + def decrypt(self, ciphertext): + return self.encrypt(ciphertext) diff --git a/unit_tests/test_tlslite_utils_aescbc.py b/unit_tests/test_tlslite_utils_aescbc.py new file mode 100644 index 000000000..f5b4da1fa --- /dev/null +++ b/unit_tests/test_tlslite_utils_aescbc.py @@ -0,0 +1,215 @@ +# compatibility with Python 2.6, for that we need unittest2 package, +# which is not available on 3.3 or 3.4 +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tlslite.utils.rijndael import Rijndael +from tlslite.utils.python_aes import Python_AES + + +class TestAESCBC(unittest.TestCase): + def test___init__(self): + key = bytearray(16) + aesCBC = Python_AES(key, 2, bytearray(b'\x00' * 16)) + + self.assertIsNotNone(aesCBC) + + def test___init___with_invalid_key(self): + key = bytearray(8) + + with self.assertRaises(AssertionError): + aesCBC = Python_AES(key, 2, bytearray(b'\x00' * 16)) + + def test___init___with_invalid_iv(self): + key = bytearray(16) + + with self.assertRaises(AssertionError): + aesCBC = Python_AES(key, 2, bytearray(b'\x00' * 8)) + + def test_encrypt_with_test_vector_1(self): + + key = bytearray(b'\x2b\x7e\x15\x16\x28\xae\xd2' + b'\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c') + + IV = bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07' + b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f') + + plaintext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + ciphertext = bytearray(b'\x76\x49\xab\xac\x81\x19\xb2\x46' + b'\xce\xe9\x8e\x9b\x12\xe9\x19\x7d' + b'\x50\x86\xcb\x9b\x50\x72\x19\xee' + b'\x95\xdb\x11\x3a\x91\x76\x78\xb2' + b'\x73\xbe\xd6\xb8\xe3\xc1\x74\x3b' + b'\x71\x16\xe6\x9e\x22\x22\x95\x16' + b'\x3f\xf1\xca\xa1\x68\x1f\xac\x09' + b'\x12\x0e\xca\x30\x75\x86\xe1\xa7') + + aesCBC = Python_AES(key, 2, IV) + self.assertEqual(aesCBC.encrypt(plaintext), ciphertext) + + def test_decrypt_with_test_vector_1(self): + + key = bytearray(b'\x2b\x7e\x15\x16\x28\xae\xd2' + b'\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c') + + IV = bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07' + b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f') + + plaintext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + ciphertext = bytearray(b'\x76\x49\xab\xac\x81\x19\xb2\x46' + b'\xce\xe9\x8e\x9b\x12\xe9\x19\x7d' + b'\x50\x86\xcb\x9b\x50\x72\x19\xee' + b'\x95\xdb\x11\x3a\x91\x76\x78\xb2' + b'\x73\xbe\xd6\xb8\xe3\xc1\x74\x3b' + b'\x71\x16\xe6\x9e\x22\x22\x95\x16' + b'\x3f\xf1\xca\xa1\x68\x1f\xac\x09' + b'\x12\x0e\xca\x30\x75\x86\xe1\xa7') + + aesCBC = Python_AES(key, 2, IV) + self.assertEqual(aesCBC.decrypt(ciphertext), plaintext) + + def test_encrypt_with_test_vector_2(self): + + key = bytearray(b'\x8e\x73\xb0\xf7\xda\x0e\x64\x52' + b'\xc8\x10\xf3\x2b\x80\x90\x79\xe5' + b'\x62\xf8\xea\xd2\x52\x2c\x6b\x7b') + + IV = bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07' + b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f') + + plaintext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + ciphertext = bytearray(b'\x4f\x02\x1d\xb2\x43\xbc\x63\x3d' + b'\x71\x78\x18\x3a\x9f\xa0\x71\xe8' + b'\xb4\xd9\xad\xa9\xad\x7d\xed\xf4' + b'\xe5\xe7\x38\x76\x3f\x69\x14\x5a' + b'\x57\x1b\x24\x20\x12\xfb\x7a\xe0' + b'\x7f\xa9\xba\xac\x3d\xf1\x02\xe0' + b'\x08\xb0\xe2\x79\x88\x59\x88\x81' + b'\xd9\x20\xa9\xe6\x4f\x56\x15\xcd') + + aesCBC = Python_AES(key, 2, IV) + self.assertEqual(aesCBC.encrypt(plaintext), ciphertext) + + def test_decrypt_with_test_vector_2(self): + + key = bytearray(b'\x8e\x73\xb0\xf7\xda\x0e\x64\x52' + b'\xc8\x10\xf3\x2b\x80\x90\x79\xe5' + b'\x62\xf8\xea\xd2\x52\x2c\x6b\x7b') + + IV = bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07' + b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f') + + plaintext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + ciphertext = bytearray(b'\x4f\x02\x1d\xb2\x43\xbc\x63\x3d' + b'\x71\x78\x18\x3a\x9f\xa0\x71\xe8' + b'\xb4\xd9\xad\xa9\xad\x7d\xed\xf4' + b'\xe5\xe7\x38\x76\x3f\x69\x14\x5a' + b'\x57\x1b\x24\x20\x12\xfb\x7a\xe0' + b'\x7f\xa9\xba\xac\x3d\xf1\x02\xe0' + b'\x08\xb0\xe2\x79\x88\x59\x88\x81' + b'\xd9\x20\xa9\xe6\x4f\x56\x15\xcd') + + aesCBC = Python_AES(key, 2, IV) + self.assertEqual(aesCBC.decrypt(ciphertext), plaintext) + + def test_encrypt_with_test_vector_3(self): + + key = bytearray(b'\x60\x3d\xeb\x10\x15\xca\x71\xbe' + b'\x2b\x73\xae\xf0\x85\x7d\x77\x81' + b'\x1f\x35\x2c\x07\x3b\x61\x08\xd7' + b'\x2d\x98\x10\xa3\x09\x14\xdf\xf4') + + IV = bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07' + b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f') + + plaintext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + ciphertext = bytearray(b'\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba' + b'\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6' + b'\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d' + b'\x67\x9f\x77\x7b\xc6\x70\x2c\x7d' + b'\x39\xf2\x33\x69\xa9\xd9\xba\xcf' + b'\xa5\x30\xe2\x63\x04\x23\x14\x61' + b'\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc' + b'\xda\x6c\x19\x07\x8c\x6a\x9d\x1b') + + aesCBC = Python_AES(key, 2, IV) + self.assertEqual(aesCBC.encrypt(plaintext), ciphertext) + + def test_decrypt_with_test_vector_3(self): + + key = bytearray(b'\x60\x3d\xeb\x10\x15\xca\x71\xbe' + b'\x2b\x73\xae\xf0\x85\x7d\x77\x81' + b'\x1f\x35\x2c\x07\x3b\x61\x08\xd7' + b'\x2d\x98\x10\xa3\x09\x14\xdf\xf4') + + IV = bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07' + b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f') + + plaintext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + ciphertext = bytearray(b'\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba' + b'\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6' + b'\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d' + b'\x67\x9f\x77\x7b\xc6\x70\x2c\x7d' + b'\x39\xf2\x33\x69\xa9\xd9\xba\xcf' + b'\xa5\x30\xe2\x63\x04\x23\x14\x61' + b'\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc' + b'\xda\x6c\x19\x07\x8c\x6a\x9d\x1b') + + aesCBC = Python_AES(key, 2, IV) + self.assertEqual(aesCBC.decrypt(ciphertext), plaintext) diff --git a/unit_tests/test_tlslite_utils_aesccm.py b/unit_tests/test_tlslite_utils_aesccm.py index b77461661..18e3412a0 100644 --- a/unit_tests/test_tlslite_utils_aesccm.py +++ b/unit_tests/test_tlslite_utils_aesccm.py @@ -5,8 +5,10 @@ except ImportError: import unittest +from tlslite.utils.cryptomath import * from tlslite.utils.rijndael import Rijndael from tlslite.utils.aesccm import AESCCM +from tlslite.utils import openssl_aesccm from tlslite.utils.cipherfactory import createAESCCM, createAESCCM_8 @@ -348,3 +350,119 @@ def test_seal_with_test_vector_6(self): self.assertEqual(bytearray(b'\xc1\x94@D\xc8\xe7\xaa\x95\xd2\xde\x95' b'\x13\xc7\xf3\xdd\x8cK\n>^Q\xf1Q\xeb\x0f' b'\xfa\xe7\xc4=\x01\x0f\xdb'), encData) + + if m2cryptoLoaded: + def test_seal_with_test_vector_1_openssl(self): + key = bytearray(b'\x00'*16) + aesCCM = openssl_aesccm.new(key) + + nonce = bytearray(b'\x00'*12) + + plaintext = bytearray(b'') + self.assertEqual(len(plaintext), 0) + + encData = aesCCM.seal(nonce, plaintext, bytearray(0)) + self.assertEqual(bytearray(b'\xb9\xf6P\xfb<9\xbb\x1b\xee\x0e)\x1d3' + b'\xf6\xae('), encData) + + def test_seal_with_test_vector_2_openssl(self): + key = bytearray(b'\x00'*16) + aesCCM = openssl_aesccm.new(key) + + nonce = bytearray(b'\x00'*12) + + plaintext = bytearray(b'\x00'*16) + self.assertEqual(len(plaintext), 16) + + encData = aesCCM.seal(nonce, plaintext, bytearray(0)) + + self.assertEqual(bytearray(b'n\xc7_\xb2\xe2\xb4\x87F\x1e\xdd\xcb\xb8' + b'\x97\x11\x92\xbaMO\xa3\xaf\x0b\xf6\xd3E' + b'Aq0o\xfa\xdd\x9a\xfd'), encData) + + def test_seal_with_test_vector_3_openssl(self): + key = bytearray(b'\xfe\xff\xe9\x92\x86\x65\x73\x1c' + b'\x6d\x6a\x8f\x94\x67\x30\x83\x08') + aesCCM = openssl_aesccm.new(key) + + nonce = bytearray(b'\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88') + + plaintext = bytearray(b'\xd9\x31\x32\x25\xf8\x84\x06\xe5' + b'\xa5\x59\x09\xc5\xaf\xf5\x26\x9a' + b'\x86\xa7\xa9\x53\x15\x34\xf7\xda' + b'\x2e\x4c\x30\x3d\x8a\x31\x8a\x72' + b'\x1c\x3c\x0c\x95\x95\x68\x09\x53' + b'\x2f\xcf\x0e\x24\x49\xa6\xb5\x25' + b'\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57' + b'\xba\x63\x7b\x39\x1a\xaf\xd2\x55') + + self.assertEqual(len(plaintext), 4*16) + + encData = aesCCM.seal(nonce, plaintext, bytearray(0)) + + self.assertEqual(bytearray(b"\x08\x93\xe9K\x91H\x80\x1a\xf0\xf74&" + b"\xab\xb0\x0e<\xa4\x9b\xf0\x9dy\xa2" + b"\x01\'\xa7\xeb\x19&\xfa\x89\x057\x87" + b"\xff\x02\xd0}q\x81;\x88[\x85\xe7\xf9" + b"lN\xed\xf4 \xdb\x12j\x04Q\xce\x13\xbdA" + b"\xba\x01\x8d\x1b\xa7\xfc\xece\x99Dg\xa7" + b"{\x8b&B\xde\x91,\x01."), encData) + + def test_seal_with_test_vector_4_openssl(self): + key = bytearray(b'\xfe\xff\xe9\x92\x86\x65\x73\x1c' + + b'\x6d\x6a\x8f\x94\x67\x30\x83\x08') + aesCCM = openssl_aesccm.new(key) + + nonce = bytearray(b'\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88') + + plaintext = bytearray(b'\xd9\x31\x32\x25\xf8\x84\x06\xe5' + b'\xa5\x59\x09\xc5\xaf\xf5\x26\x9a' + b'\x86\xa7\xa9\x53\x15\x34\xf7\xda' + b'\x2e\x4c\x30\x3d\x8a\x31\x8a\x72' + b'\x1c\x3c\x0c\x95\x95\x68\x09\x53' + b'\x2f\xcf\x0e\x24\x49\xa6\xb5\x25' + b'\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57' + b'\xba\x63\x7b\x39') + + data = bytearray(b'\xfe\xed\xfa\xce\xde\xad\xbe\xef' + b'\xfe\xed\xfa\xce\xde\xad\xbe\xef' + b'\xab\xad\xda\xd2') + + encData = aesCCM.seal(nonce, plaintext, data) + + self.assertEqual(bytearray(b'\x08\x93\xe9K\x91H\x80\x1a\xf0\xf74&\xab' + b'\xb0\x0e<\xa4\x9b\xf0\x9dy\xa2\x01\'\xa7' + b'\xeb\x19&\xfa\x89\x057\x87\xff\x02\xd0}q' + b'\x81;\x88[\x85\xe7\xf9lN\xed\xf4 \xdb' + b'\x12j\x04Q\xce\x13\xbdA\xba\x028\xc3&' + b'\xb4{4\xf7\x8fe\x9eu' + b'\x10\x96\xcd"'), encData) + + def test_seal_with_test_vector_5_openssl(self): + key = bytearray(32) + + aesCCM = openssl_aesccm.new(key) + + nonce = bytearray(12) + plaintext = bytearray(0) + data = bytearray(0) + + encData = aesCCM.seal(nonce, plaintext, data) + + self.assertEqual(bytearray(b'\xa8\x90&^C\xa2hU\xf2i' + b'\xb9?\xf4\xdd\xde\xf6'), encData) + + def test_seal_with_test_vector_6_openssl(self): + key = bytearray(32) + + aesCCM = openssl_aesccm.new(key) + + nonce = bytearray(12) + plaintext = bytearray(16) + data = bytearray(0) + + encData = aesCCM.seal(nonce, plaintext, data) + + self.assertEqual(bytearray(b'\xc1\x94@D\xc8\xe7\xaa\x95\xd2\xde\x95' + b'\x13\xc7\xf3\xdd\x8cK\n>^Q\xf1Q\xeb\x0f' + b'\xfa\xe7\xc4=\x01\x0f\xdb'), encData) diff --git a/unit_tests/test_tlslite_utils_aesctr.py b/unit_tests/test_tlslite_utils_aesctr.py new file mode 100644 index 000000000..2afa27d0f --- /dev/null +++ b/unit_tests/test_tlslite_utils_aesctr.py @@ -0,0 +1,217 @@ +# compatibility with Python 2.6, for that we need unittest2 package, +# which is not available on 3.3 or 3.4 +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tlslite.utils.rijndael import Rijndael +from tlslite.utils.python_aes import Python_AES_CTR + + +class TestAESCTR(unittest.TestCase): + def test___init__(self): + key = bytearray(16) + aesCTR = Python_AES_CTR(key, mode=6, IV=bytearray(b'\x00' * 12)) + + self.assertIsNotNone(aesCTR) + + def test___init___with_invalid_key(self): + key = bytearray(8) + + with self.assertRaises(AssertionError): + aesCTR = Python_AES_CTR(key, mode=6, IV=bytearray(b'\x00' * 12)) + + def test_encrypt_with_test_vector_1(self): + + key = bytearray(b'\x2b\x7e\x15\x16\x28\xae\xd2' + b'\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c') + + plaintext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + ciphertext = bytearray(b'\x87\x4d\x61\x91\xb6\x20\xe3' + b'\x26\x1b\xef\x68\x64\x99\x0d' + b'\xb6\xce\x98\x06\xf6\x6b\x79' + b'\x70\xfd\xff\x86\x17\x18\x7b' + b'\xb9\xff\xfd\xff\x5a\xe4\xdf' + b'\x3e\xdb\xd5\xd3\x5e\x5b\x4f' + b'\x09\x02\x0d\xb0\x3e\xab\x1e' + b'\x03\x1d\xda\x2f\xbe\x03\xd1' + b'\x79\x21\x70\xa0\xf3\x00\x9c\xee') + + counter = bytearray(b'\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8' + b'\xf9\xfa\xfb\xfc\xfd\xfe\xff') + + aesCTR = Python_AES_CTR(key, mode=6, IV=bytearray(b'\x00' * 12)) + aesCTR.counter = counter + self.assertEqual(aesCTR.encrypt(plaintext), ciphertext) + + def test_decrypt_with_test_vector_1(self): + + key = bytearray(b'\x2b\x7e\x15\x16\x28\xae\xd2' + b'\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c') + + plaintext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + ciphertext = bytearray(b'\x87\x4d\x61\x91\xb6\x20\xe3' + b'\x26\x1b\xef\x68\x64\x99\x0d' + b'\xb6\xce\x98\x06\xf6\x6b\x79' + b'\x70\xfd\xff\x86\x17\x18\x7b' + b'\xb9\xff\xfd\xff\x5a\xe4\xdf' + b'\x3e\xdb\xd5\xd3\x5e\x5b\x4f' + b'\x09\x02\x0d\xb0\x3e\xab\x1e' + b'\x03\x1d\xda\x2f\xbe\x03\xd1' + b'\x79\x21\x70\xa0\xf3\x00\x9c\xee') + + counter = bytearray(b'\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8' + b'\xf9\xfa\xfb\xfc\xfd\xfe\xff') + + aesCTR = Python_AES_CTR(key, mode=6, IV=bytearray(b'\x00' * 12)) + aesCTR.counter = counter + self.assertEqual(aesCTR.decrypt(ciphertext), plaintext) + + def test_encrypt_with_test_vector_2(self): + + key = bytearray(b'\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8' + b'\x10\xf3\x2b\x80\x90\x79\xe5\x62\xf8' + b'\xea\xd2\x52\x2c\x6b\x7b') + + plaintext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + ciphertext = bytearray(b'\x1a\xbc\x93\x24\x17\x52\x1c\xa2' + b'\x4f\x2b\x04\x59\xfe\x7e\x6e\x0b' + b'\x09\x03\x39\xec\x0a\xa6\xfa\xef' + b'\xd5\xcc\xc2\xc6\xf4\xce\x8e\x94' + b'\x1e\x36\xb2\x6b\xd1\xeb\xc6\x70' + b'\xd1\xbd\x1d\x66\x56\x20\xab\xf7' + b'\x4f\x78\xa7\xf6\xd2\x98\x09\x58' + b'\x5a\x97\xda\xec\x58\xc6\xb0\x50') + + counter = bytearray(b'\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8' + b'\xf9\xfa\xfb\xfc\xfd\xfe\xff') + + aesCTR = Python_AES_CTR(key, mode=6, IV=bytearray(b'\x00' * 12)) + aesCTR.counter = counter + self.assertEqual(aesCTR.encrypt(plaintext), ciphertext) + + def test_decrypt_with_test_vector_2(self): + + key = bytearray(b'\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8' + b'\x10\xf3\x2b\x80\x90\x79\xe5\x62\xf8' + b'\xea\xd2\x52\x2c\x6b\x7b') + + ciphertext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + plaintext = bytearray(b'\x1a\xbc\x93\x24\x17\x52\x1c\xa2' + b'\x4f\x2b\x04\x59\xfe\x7e\x6e\x0b' + b'\x09\x03\x39\xec\x0a\xa6\xfa\xef' + b'\xd5\xcc\xc2\xc6\xf4\xce\x8e\x94' + b'\x1e\x36\xb2\x6b\xd1\xeb\xc6\x70' + b'\xd1\xbd\x1d\x66\x56\x20\xab\xf7' + b'\x4f\x78\xa7\xf6\xd2\x98\x09\x58' + b'\x5a\x97\xda\xec\x58\xc6\xb0\x50') + + counter = bytearray(b'\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8' + b'\xf9\xfa\xfb\xfc\xfd\xfe\xff') + + aesCTR = Python_AES_CTR(key, mode=6, IV=bytearray(b'\x00' * 12)) + aesCTR.counter = counter + self.assertEqual(aesCTR.decrypt(ciphertext), plaintext) + + def test_encrypt_with_test_vector_3(self): + + key = bytearray(b'\x60\x3d\xeb\x10\x15\xca\x71\xbe' + b'\x2b\x73\xae\xf0\x85\x7d\x77\x81' + b'\x1f\x35\x2c\x07\x3b\x61\x08\xd7' + b'\x2d\x98\x10\xa3\x09\x14\xdf\xf4') + + ciphertext = bytearray(b'\x60\x1e\xc3\x13\x77\x57\x89\xa5' + b'\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28' + b'\xf4\x43\xe3\xca\x4d\x62\xb5\x9a' + b'\xca\x84\xe9\x90\xca\xca\xf5\xc5' + b'\x2b\x09\x30\xda\xa2\x3d\xe9\x4c' + b'\xe8\x70\x17\xba\x2d\x84\x98\x8d' + b'\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6' + b'\x13\xc2\xdd\x08\x45\x79\x41\xa6') + + plaintext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + counter = bytearray(b'\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8' + b'\xf9\xfa\xfb\xfc\xfd\xfe\xff') + + aesCTR = Python_AES_CTR(key, mode=6, IV=bytearray(b'\x00' * 12)) + aesCTR.counter = counter + self.assertEqual(aesCTR.encrypt(plaintext), ciphertext) + + def test_decrypt_with_test_vector_3(self): + + key = bytearray(b'\x60\x3d\xeb\x10\x15\xca\x71\xbe' + b'\x2b\x73\xae\xf0\x85\x7d\x77\x81' + b'\x1f\x35\x2c\x07\x3b\x61\x08\xd7' + b'\x2d\x98\x10\xa3\x09\x14\xdf\xf4') + + plaintext = bytearray(b'\x60\x1e\xc3\x13\x77\x57\x89\xa5' + b'\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28' + b'\xf4\x43\xe3\xca\x4d\x62\xb5\x9a' + b'\xca\x84\xe9\x90\xca\xca\xf5\xc5' + b'\x2b\x09\x30\xda\xa2\x3d\xe9\x4c' + b'\xe8\x70\x17\xba\x2d\x84\x98\x8d' + b'\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6' + b'\x13\xc2\xdd\x08\x45\x79\x41\xa6') + + ciphertext = bytearray(b'\x6b\xc1\xbe\xe2\x2e\x40\x9f' + b'\x96\xe9\x3d\x7e\x11\x73\x93' + b'\x17\x2a\xae\x2d\x8a\x57\x1e' + b'\x03\xac\x9c\x9e\xb7\x6f\xac' + b'\x45\xaf\x8e\x51\x30\xc8\x1c' + b'\x46\xa3\x5c\xe4\x11\xe5\xfb' + b'\xc1\x19\x1a\x0a\x52\xef\xf6' + b'\x9f\x24\x45\xdf\x4f\x9b\x17' + b'\xad\x2b\x41\x7b\xe6\x6c\x37\x10') + + counter = bytearray(b'\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8' + b'\xf9\xfa\xfb\xfc\xfd\xfe\xff') + + aesCTR = Python_AES_CTR(key, mode=6, IV=bytearray(b'\x00' * 12)) + aesCTR.counter = counter + self.assertEqual(aesCTR.decrypt(ciphertext), plaintext) diff --git a/unit_tests/test_tlslite_utils_aesgcm.py b/unit_tests/test_tlslite_utils_aesgcm.py index 8864bf551..06444eda0 100644 --- a/unit_tests/test_tlslite_utils_aesgcm.py +++ b/unit_tests/test_tlslite_utils_aesgcm.py @@ -9,8 +9,10 @@ except ImportError: import unittest +from tlslite.utils.cryptomath import * from tlslite.utils.rijndael import Rijndael from tlslite.utils.aesgcm import AESGCM +from tlslite.utils import openssl_aesgcm class TestAESGCM(unittest.TestCase): def test___init__(self): @@ -254,3 +256,141 @@ def test_seal_with_test_vector_14(self): b'\xd0\xd1\xc8\xa7\x99\x99\x6b\xf0' + b'\x26\x5b\x98\xb5\xd4\x8a\xb9\x19' ), encData) + + if m2cryptoLoaded: + def test_seal_with_test_vector_1_openssl(self): + key = bytearray(b'\x00'*16) + aesGCM = openssl_aesgcm.new(key) + + nonce = bytearray(b'\x00'*12) + + plaintext = bytearray(b'') + self.assertEqual(len(plaintext), 0) + + encData = aesGCM.seal(nonce, plaintext, bytearray(0)) + + self.assertEqual(bytearray( + b'\x58\xe2\xfc\xce\xfa\x7e\x30\x61' + + b'\x36\x7f\x1d\x57\xa4\xe7\x45\x5a'), encData) + + def test_seal_with_test_vector_2_openssl(self): + key = bytearray(b'\x00'*16) + aesGCM = openssl_aesgcm.new(key) + + nonce = bytearray(b'\x00'*12) + + plaintext = bytearray(b'\x00'*16) + self.assertEqual(len(plaintext), 16) + + encData = aesGCM.seal(nonce, plaintext, bytearray(0)) + + self.assertEqual(bytearray( + b'\x03\x88\xda\xce\x60\xb6\xa3\x92' + + b'\xf3\x28\xc2\xb9\x71\xb2\xfe\x78' + + b'\xab\x6e\x47\xd4\x2c\xec\x13\xbd' + + b'\xf5\x3a\x67\xb2\x12\x57\xbd\xdf'), encData) + + def test_seal_with_test_vector_3_openssl(self): + key = bytearray(b'\xfe\xff\xe9\x92\x86\x65\x73\x1c' + + b'\x6d\x6a\x8f\x94\x67\x30\x83\x08') + aesGCM = openssl_aesgcm.new(key) + + nonce = bytearray(b'\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88') + + plaintext = bytearray(b'\xd9\x31\x32\x25\xf8\x84\x06\xe5' + + b'\xa5\x59\x09\xc5\xaf\xf5\x26\x9a' + + b'\x86\xa7\xa9\x53\x15\x34\xf7\xda' + + b'\x2e\x4c\x30\x3d\x8a\x31\x8a\x72' + + b'\x1c\x3c\x0c\x95\x95\x68\x09\x53' + + b'\x2f\xcf\x0e\x24\x49\xa6\xb5\x25' + + b'\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57' + + b'\xba\x63\x7b\x39\x1a\xaf\xd2\x55') + + self.assertEqual(len(plaintext), 4*16) + + encData = aesGCM.seal(nonce, plaintext, bytearray(0)) + + self.assertEqual(bytearray( + b'\x42\x83\x1e\xc2\x21\x77\x74\x24' + + b'\x4b\x72\x21\xb7\x84\xd0\xd4\x9c' + + b'\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0' + + b'\x35\xc1\x7e\x23\x29\xac\xa1\x2e' + + b'\x21\xd5\x14\xb2\x54\x66\x93\x1c' + + b'\x7d\x8f\x6a\x5a\xac\x84\xaa\x05' + + b'\x1b\xa3\x0b\x39\x6a\x0a\xac\x97' + + b'\x3d\x58\xe0\x91\x47\x3f\x59\x85' + + b'\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6' + + b'\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4' + ), encData) + + def test_seal_with_test_vector_4_openssl(self): + key = bytearray(b'\xfe\xff\xe9\x92\x86\x65\x73\x1c' + + b'\x6d\x6a\x8f\x94\x67\x30\x83\x08') + + aesGCM = openssl_aesgcm.new(key) + + nonce = bytearray(b'\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88') + + plaintext = bytearray(b'\xd9\x31\x32\x25\xf8\x84\x06\xe5' + + b'\xa5\x59\x09\xc5\xaf\xf5\x26\x9a' + + b'\x86\xa7\xa9\x53\x15\x34\xf7\xda' + + b'\x2e\x4c\x30\x3d\x8a\x31\x8a\x72' + + b'\x1c\x3c\x0c\x95\x95\x68\x09\x53' + + b'\x2f\xcf\x0e\x24\x49\xa6\xb5\x25' + + b'\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57' + + b'\xba\x63\x7b\x39') + + data = bytearray(b'\xfe\xed\xfa\xce\xde\xad\xbe\xef' + + b'\xfe\xed\xfa\xce\xde\xad\xbe\xef' + + b'\xab\xad\xda\xd2') + + encData = aesGCM.seal(nonce, plaintext, data) + + self.assertEqual(bytearray( + b'\x42\x83\x1e\xc2\x21\x77\x74\x24' + + b'\x4b\x72\x21\xb7\x84\xd0\xd4\x9c' + + b'\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0' + + b'\x35\xc1\x7e\x23\x29\xac\xa1\x2e' + + b'\x21\xd5\x14\xb2\x54\x66\x93\x1c' + + b'\x7d\x8f\x6a\x5a\xac\x84\xaa\x05' + + b'\x1b\xa3\x0b\x39\x6a\x0a\xac\x97' + + b'\x3d\x58\xe0\x91' + + b'\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb' + + b'\x94\xfa\xe9\x5a\xe7\x12\x1a\x47'), encData) + + def test_seal_with_test_vector_13_openssl(self): + key = bytearray(32) + + aesGCM = openssl_aesgcm.new(key) + + self.assertEqual(aesGCM.name, "aes256gcm") + + nonce = bytearray(12) + data = bytearray(0) + + encData = aesGCM.seal(nonce, data, data) + + self.assertEqual(bytearray( + b'\x53\x0f\x8a\xfb\xc7\x45\x36\xb9' + + b'\xa9\x63\xb4\xf1\xc4\xcb\x73\x8b' + ), encData) + + def test_seal_with_test_vector_14_openssl(self): + key = bytearray(32) + + aesGCM = openssl_aesgcm.new(key) + + self.assertEqual(aesGCM.name, "aes256gcm") + + nonce = bytearray(12) + plaintext = bytearray(16) + data = bytearray(0) + + encData = aesGCM.seal(nonce, plaintext, data) + + self.assertEqual(bytearray( + b'\xce\xa7\x40\x3d\x4d\x60\x6b\x6e' + + b'\x07\x4e\xc5\xd3\xba\xf3\x9d\x18' + + b'\xd0\xd1\xc8\xa7\x99\x99\x6b\xf0' + + b'\x26\x5b\x98\xb5\xd4\x8a\xb9\x19' + ), encData)