mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 21:05:08 +00:00
crypto: Test all of the AES-CCM KAT vectors.
Previously, only test vectors which used the default nonce and tag sizes (12 and 16, respectively) were tested. This now tests all of the vectors. This exposed some additional issues around requests with an empty payload (which wasn't supported) and an empty AAD (which falls back to CIOCCRYPT instead of CIOCCRYPTAEAD). - Make use of the 'ivlen' and 'maclen' fields for CIOGSESSION2 to test AES-CCM vectors with non-default nonce and tag lengths. - Permit requests with an empty payload. - Permit an input MAC for requests without AAD. Reviewed by: markj Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D32121
This commit is contained in:
parent
4361c4eb6e
commit
668770dc7d
|
@ -79,10 +79,10 @@ class SessionOp2(dpkt.Packet):
|
|||
('mackey', 'P', 0),
|
||||
('ses', 'I', 0),
|
||||
('crid', 'i', 0),
|
||||
('ivlen', 'i', 0),
|
||||
('maclen', 'i', 0),
|
||||
('pad0', 'i', 0),
|
||||
('pad1', 'i', 0),
|
||||
('pad2', 'i', 0),
|
||||
('pad3', 'i', 0),
|
||||
)
|
||||
|
||||
class CryptOp(dpkt.Packet):
|
||||
|
@ -159,6 +159,11 @@ def array_tobytes(array_obj):
|
|||
return array_obj.tobytes()
|
||||
return array_obj.tostring()
|
||||
|
||||
def empty_bytes():
|
||||
if sys.version_info[0] >= 3:
|
||||
return b''
|
||||
return ""
|
||||
|
||||
class Crypto:
|
||||
@staticmethod
|
||||
def findcrid(name):
|
||||
|
@ -169,7 +174,8 @@ def getcridname(crid):
|
|||
return _findop(crid, '')[1]
|
||||
|
||||
def __init__(self, cipher=0, key=None, mac=0, mackey=None,
|
||||
crid=CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE, maclen=None):
|
||||
crid=CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE, maclen=None,
|
||||
ivlen=None):
|
||||
self._ses = None
|
||||
self._maclen = maclen
|
||||
ses = SessionOp2()
|
||||
|
@ -191,6 +197,10 @@ def __init__(self, cipher=0, key=None, mac=0, mackey=None,
|
|||
if not cipher and not mac:
|
||||
raise ValueError('one of cipher or mac MUST be specified.')
|
||||
ses.crid = crid
|
||||
if ivlen:
|
||||
ses.ivlen = ivlen
|
||||
if maclen:
|
||||
ses.maclen = maclen
|
||||
#print(ses)
|
||||
s = array.array('B', ses.pack_hdr())
|
||||
#print(s)
|
||||
|
@ -209,16 +219,23 @@ def __del__(self):
|
|||
pass
|
||||
self._ses = None
|
||||
|
||||
def _doop(self, op, src, iv):
|
||||
def _doop(self, op, src, iv, mac=None):
|
||||
cop = CryptOp()
|
||||
cop.ses = self._ses
|
||||
cop.op = op
|
||||
cop.flags = 0
|
||||
cop.len = len(src)
|
||||
s = array.array('B', src)
|
||||
cop.src = cop.dst = s.buffer_info()[0]
|
||||
if src is not None:
|
||||
cop.len = len(src)
|
||||
s = array.array('B', src)
|
||||
cop.src = cop.dst = s.buffer_info()[0]
|
||||
if mac is not None:
|
||||
assert len(mac) == self._maclen, \
|
||||
'%d != %d' % (len(tag), self._maclen)
|
||||
if self._maclen is not None:
|
||||
m = array.array('B', [0] * self._maclen)
|
||||
if mac is None:
|
||||
m = array.array('B', [0] * self._maclen)
|
||||
else:
|
||||
m = array.array('B', mac)
|
||||
cop.mac = m.buffer_info()[0]
|
||||
ivbuf = array.array('B', str_to_ascii(iv))
|
||||
cop.iv = ivbuf.buffer_info()[0]
|
||||
|
@ -226,7 +243,10 @@ def _doop(self, op, src, iv):
|
|||
#print('cop:', cop)
|
||||
ioctl(_cryptodev, CIOCCRYPT, bytes(cop))
|
||||
|
||||
s = array_tobytes(s)
|
||||
if src is not None:
|
||||
s = array_tobytes(s)
|
||||
else:
|
||||
s = empty_bytes()
|
||||
if self._maclen is not None:
|
||||
return s, array_tobytes(m)
|
||||
|
||||
|
@ -238,10 +258,11 @@ def _doaead(self, op, src, aad, iv, tag=None):
|
|||
caead.op = op
|
||||
caead.flags = CRD_F_IV_EXPLICIT
|
||||
caead.flags = 0
|
||||
src = str_to_ascii(src)
|
||||
caead.len = len(src)
|
||||
s = array.array('B', src)
|
||||
caead.src = caead.dst = s.buffer_info()[0]
|
||||
if src is not None and len(src) != 0:
|
||||
src = str_to_ascii(src)
|
||||
caead.len = len(src)
|
||||
s = array.array('B', src)
|
||||
caead.src = caead.dst = s.buffer_info()[0]
|
||||
aad = str_to_ascii(aad)
|
||||
caead.aadlen = len(aad)
|
||||
saad = array.array('B', aad)
|
||||
|
@ -266,7 +287,10 @@ def _doaead(self, op, src, aad, iv, tag=None):
|
|||
|
||||
ioctl(_cryptodev, CIOCCRYPTAEAD, bytes(caead))
|
||||
|
||||
s = array_tobytes(s)
|
||||
if src is not None:
|
||||
s = array_tobytes(s)
|
||||
else:
|
||||
s = empty_bytes()
|
||||
|
||||
return s, array_tobytes(tag)
|
||||
|
||||
|
@ -320,7 +344,7 @@ def encrypt(self, data, iv, aad=None):
|
|||
|
||||
def decrypt(self, data, iv, aad=None, tag=None):
|
||||
if aad is None:
|
||||
return self._doop(COP_DECRYPT, data, iv)
|
||||
return self._doop(COP_DECRYPT, data, iv, mac=tag)
|
||||
else:
|
||||
return self._doaead(COP_DECRYPT, data, aad,
|
||||
iv, tag=tag)
|
||||
|
|
|
@ -243,25 +243,26 @@ def runCCMEncrypt(self, fname):
|
|||
def runCCMEncryptWithParser(self, parser):
|
||||
for data in next(parser):
|
||||
Nlen = int(data['Nlen'])
|
||||
if Nlen != 12:
|
||||
# OCF only supports 12 byte IVs
|
||||
continue
|
||||
Tlen = int(data['Tlen'])
|
||||
key = binascii.unhexlify(data['Key'])
|
||||
nonce = binascii.unhexlify(data['Nonce'])
|
||||
Alen = int(data['Alen'])
|
||||
Plen = int(data['Plen'])
|
||||
if Alen != 0:
|
||||
aad = binascii.unhexlify(data['Adata'])
|
||||
else:
|
||||
aad = None
|
||||
payload = binascii.unhexlify(data['Payload'])
|
||||
if Plen != 0:
|
||||
payload = binascii.unhexlify(data['Payload'])
|
||||
else:
|
||||
payload = None
|
||||
ct = binascii.unhexlify(data['CT'])
|
||||
|
||||
try:
|
||||
c = Crypto(crid=crid,
|
||||
cipher=cryptodev.CRYPTO_AES_CCM_16,
|
||||
key=key,
|
||||
mac=cryptodev.CRYPTO_AES_CCM_CBC_MAC,
|
||||
mackey=key, maclen=16)
|
||||
mackey=key, maclen=Tlen, ivlen=Nlen)
|
||||
r, tag = Crypto.encrypt(c, payload,
|
||||
nonce, aad)
|
||||
except EnvironmentError as e:
|
||||
|
@ -280,36 +281,29 @@ def runCCMDecrypt(self, fname):
|
|||
self.runCCMDecryptWithParser(parser)
|
||||
|
||||
def runCCMDecryptWithParser(self, parser):
|
||||
# XXX: Note that all of the current CCM
|
||||
# decryption test vectors use IV and tag sizes
|
||||
# that aren't supported by OCF none of the
|
||||
# tests are actually ran.
|
||||
for data in next(parser):
|
||||
Nlen = int(data['Nlen'])
|
||||
if Nlen != 12:
|
||||
# OCF only supports 12 byte IVs
|
||||
continue
|
||||
Tlen = int(data['Tlen'])
|
||||
if Tlen != 16:
|
||||
# OCF only supports 16 byte tags
|
||||
continue
|
||||
key = binascii.unhexlify(data['Key'])
|
||||
nonce = binascii.unhexlify(data['Nonce'])
|
||||
Alen = int(data['Alen'])
|
||||
Plen = int(data['Plen'])
|
||||
if Alen != 0:
|
||||
aad = binascii.unhexlify(data['Adata'])
|
||||
else:
|
||||
aad = None
|
||||
ct = binascii.unhexlify(data['CT'])
|
||||
tag = ct[-16:]
|
||||
ct = ct[:-16]
|
||||
tag = ct[-Tlen:]
|
||||
if Plen != 0:
|
||||
payload = ct[:-Tlen]
|
||||
else:
|
||||
payload = None
|
||||
|
||||
try:
|
||||
c = Crypto(crid=crid,
|
||||
cipher=cryptodev.CRYPTO_AES_CCM_16,
|
||||
key=key,
|
||||
mac=cryptodev.CRYPTO_AES_CCM_CBC_MAC,
|
||||
mackey=key, maclen=16)
|
||||
mackey=key, maclen=Tlen, ivlen=Nlen)
|
||||
except EnvironmentError as e:
|
||||
if e.errno != errno.EOPNOTSUPP:
|
||||
raise
|
||||
|
@ -319,12 +313,11 @@ def runCCMDecryptWithParser(self, parser):
|
|||
self.assertRaises(IOError,
|
||||
c.decrypt, payload, nonce, aad, tag)
|
||||
else:
|
||||
r = Crypto.decrypt(c, payload, nonce,
|
||||
aad, tag)
|
||||
r, tag = Crypto.decrypt(c, payload, nonce,
|
||||
aad, tag)
|
||||
|
||||
payload = binascii.unhexlify(data['Payload'])
|
||||
plen = int(data('Plen'))
|
||||
payload = payload[:plen]
|
||||
payload = payload[:Plen]
|
||||
self.assertEqual(r, payload,
|
||||
"Count " + data['Count'] + \
|
||||
" Actual: " + repr(binascii.hexlify(r)) + \
|
||||
|
|
Loading…
Reference in a new issue