Skip to content

Commit

Permalink
Merge pull request #410 from inikolcev/fix_openssl_aesccm
Browse files Browse the repository at this point in the history
fix aesccm when using m2crypto
  • Loading branch information
inikolcev committed Jun 1, 2020
2 parents 6355810 + d8eff3c commit 7c6fbf9
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 89 deletions.
14 changes: 12 additions & 2 deletions tlslite/utils/aesccm.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,12 @@ def seal(self, nonce, msg, aad):

mac = self._cbcmac_calc(nonce, aad, msg)
self._ctr.counter = s_0
auth_value = self._ctr.encrypt(mac)
if self.tagLength == 16:
auth_value = self._ctr.encrypt(mac)
else:
assert self.tagLength == 8
self._pad_with_zeroes(mac, 16)
auth_value = self._ctr.encrypt(mac)[:8]
enc_msg = self._ctr.encrypt(msg)

ciphertext = enc_msg + auth_value
Expand All @@ -127,7 +132,12 @@ def open(self, nonce, ciphertext, aad):

# We decrypt the auth value
self._ctr.counter = s_0
received_mac = self._ctr.decrypt(auth_value)
if self.tagLength == 16:
received_mac = self._ctr.decrypt(auth_value)
else:
assert self.tagLength == 8
self._pad_with_zeroes(auth_value, 16)
received_mac = self._ctr.decrypt(auth_value)[:8]
msg = self._ctr.decrypt(ciphertext)
msg = msg[:-self.tagLength]
computed_mac = self._cbcmac_calc(nonce, aad, msg)
Expand Down
15 changes: 13 additions & 2 deletions tlslite/utils/openssl_aes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,21 @@ 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, self._key = IV, key
self._IV, self._key = IV, key
self._context = None
self._encrypt = None

@property
def IV(self):
return self._IV

@IV.setter
def IV(self, iv):
if self._context is not None:
m2.cipher_ctx_free(self._context)
self._IV = iv
self._init_context()

def _init_context(self, encrypt=True):
if len(self._key) == 16:
cipherType = m2.aes_128_cbc()
Expand All @@ -37,7 +48,7 @@ def _init_context(self, encrypt=True):
if len(self._key) == 32:
cipherType = m2.aes_256_cbc()
self._context = m2.cipher_ctx_new()
m2.cipher_init(self._context, cipherType, self._key, self.IV,
m2.cipher_init(self._context, cipherType, self._key, self._IV,
int(encrypt))
m2.cipher_set_padding(self._context, 0)
self._encrypt = encrypt
Expand Down
279 changes: 194 additions & 85 deletions unit_tests/test_tlslite_utils_aesccm.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,118 +359,227 @@ def test_seal_with_test_vector_6(self):
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)
@unittest.skipUnless(m2cryptoLoaded, "requires M2Crypto")
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)

@unittest.skipUnless(m2cryptoLoaded, "requires M2Crypto")
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)

@unittest.skipUnless(m2cryptoLoaded, "requires M2Crypto")
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)

@unittest.skipUnless(m2cryptoLoaded, "requires M2Crypto")
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'\x00'*12)
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)

@unittest.skipUnless(m2cryptoLoaded, "requires M2Crypto")
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)
@unittest.skipUnless(m2cryptoLoaded, "requires M2Crypto")
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)


class TestAESCCMIdentical(unittest.TestCase):
@classmethod
def setUpClass(self):
self.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')

plaintext = bytearray(b'')
self.assertEqual(len(plaintext), 0)
self.ciphertext = bytearray(b'\xbace\x8cG\x8c\x19i\xbc\x93C\xf2w\xd6?'
b'\x8c\x8c\x11\xd3\x99r\x95Za\x17\x10F'
b'\xb75\x17\x01\x14\xab\x0b\x12\x03KElyBoJ'
b'\xda\xaa\xc0\xa9\'\xb3\xd5\x12\xa2\x1fF,'
b'\x8e\x04\xf5{\xf8\xfdN\xfe\xe2\xe9x\xfe1'
b'\x175\xa6\xc4\\Q3\x80\xf4\xcaR\x8c')

encData = aesCCM.seal(nonce, plaintext, bytearray(0))
self.assertEqual(bytearray(b'\xb9\xf6P\xfb<9\xbb\x1b\xee\x0e)\x1d3'
b'\xf6\xae('), encData)
self.ciphertext_8 = bytearray(b'\xbace\x8cG\x8c\x19i\xbc\x93C\xf2w'
b'\xd6?\x8c\x8c\x11\xd3\x99r\x95Za'
b'\x17\x10F\xb75\x17\x01\x14\xab\x0b'
b'\x12\x03KElyBoJ\xda\xaa\xc0\xa9\'\xb3'
b'\xd5\x12\xa2\x1fF,\x8e\x04\xf5{\xf8'
b'\xfdN\xfe\xe2\x1f\xae\xeb\xcb:\xb2/\xd0')

def test_seal_with_test_vector_2_openssl(self):
key = bytearray(b'\x00'*16)
aesCCM = openssl_aesccm.new(key)
self.key = bytearray(b'\xfe\xff\xe9\x92\x86\x65\x73\x1c'
b'\x6d\x6a\x8f\x94\x67\x30\x83\x08')

nonce = bytearray(b'\x00'*12)
self.nonce = bytearray(b'\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88')

plaintext = bytearray(b'\x00'*16)
self.assertEqual(len(plaintext), 16)
self.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, bytearray(0))
def test_seal_identical_messages_python(self):

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)
aesCCM = AESCCM(self.key, "python", Rijndael(self.key, 16).encrypt)

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)
for _ in range(2):
encData = aesCCM.seal(self.nonce, self.plaintext, self.data)
self.assertEqual(self.ciphertext, encData)

nonce = bytearray(b'\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88')
def test_open_identical_messages_python(self):

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')
aesCCM = AESCCM(self.key, "python", Rijndael(self.key, 16).encrypt)

self.assertEqual(len(plaintext), 4*16)
for _ in range(2):
decData = aesCCM.open(self.nonce, self.ciphertext, self.data)
self.assertEqual(self.plaintext, decData)

encData = aesCCM.seal(nonce, plaintext, bytearray(0))
def test_seal_identical_messages_8_python(self):

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)
aesCCM = AESCCM(self.key, "python", Rijndael(self.key, 16).encrypt, 8)

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)
for _ in range(2):
encData = aesCCM.seal(self.nonce, self.plaintext, self.data)
self.assertEqual(self.ciphertext_8, encData)

nonce = bytearray(b'\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88')
def test_open_identical_messages_8_python(self):

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')
aesCCM = AESCCM(self.key, "python", Rijndael(self.key, 16).encrypt, 8)

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')
for _ in range(2):
decData = aesCCM.open(self.nonce, self.ciphertext_8, self.data)
self.assertEqual(self.plaintext, decData)

encData = aesCCM.seal(nonce, plaintext, data)
@unittest.skipUnless(m2cryptoLoaded, "requires M2Crypto")
def test_seal_identical_messages_openssl(self):

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)
aesCCM = openssl_aesccm.new(self.key)

def test_seal_with_test_vector_5_openssl(self):
key = bytearray(32)
for _ in range(2):
encData = aesCCM.seal(self.nonce, self.plaintext, self.data)
self.assertEqual(self.ciphertext, encData)

aesCCM = openssl_aesccm.new(key)
@unittest.skipUnless(m2cryptoLoaded, "requires M2Crypto")
def test_open_identical_messages_openssl(self):

nonce = bytearray(12)
plaintext = bytearray(0)
data = bytearray(0)
aesCCM = openssl_aesccm.new(self.key)

encData = aesCCM.seal(nonce, plaintext, data)
for _ in range(2):
decData = aesCCM.open(self.nonce, self.ciphertext, self.data)
self.assertEqual(self.plaintext, decData)

self.assertEqual(bytearray(b'\xa8\x90&^C\xa2hU\xf2i'
b'\xb9?\xf4\xdd\xde\xf6'), encData)
@unittest.skipUnless(m2cryptoLoaded, "requires M2Crypto")
def test_seal_identical_messages_8_openssl(self):

def test_seal_with_test_vector_6_openssl(self):
key = bytearray(32)
aesCCM = openssl_aesccm.new(self.key, 8)

aesCCM = openssl_aesccm.new(key)
for _ in range(2):
encData = aesCCM.seal(self.nonce, self.plaintext, self.data)
self.assertEqual(self.ciphertext_8, encData)

nonce = bytearray(12)
plaintext = bytearray(16)
data = bytearray(0)
@unittest.skipUnless(m2cryptoLoaded, "requires M2Crypto")
def test_open_identical_messages_8_openssl(self):

encData = aesCCM.seal(nonce, plaintext, data)
aesCCM = openssl_aesccm.new(self.key, 8)

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)
for _ in range(2):
decData = aesCCM.open(self.nonce, self.ciphertext_8, self.data)
self.assertEqual(self.plaintext, decData)

0 comments on commit 7c6fbf9

Please sign in to comment.