1 #!/usr/local/bin/python2
3 # Copyright (c) 2014 The FreeBSD Foundation
6 # This software was developed by John-Mark Gurney under
7 # the sponsorship from the FreeBSD Foundation.
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions
11 # 1. Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
13 # 2. Redistributions in binary form must reproduce the above copyright
14 # notice, this list of conditions and the following disclaimer in the
15 # documentation and/or other materials provided with the distribution.
17 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 from __future__ import print_function
41 from cryptodev import *
42 from glob import iglob
44 katdir = '/usr/local/share/nist-kat'
47 assert os.path.exists(katdir), "Please 'pkg install nist-kat'"
48 if not os.path.exists(os.path.join(katdir, base)):
49 raise unittest.SkipTest("Missing %s test vectors" % (base))
50 return iglob(os.path.join(katdir, base, glob))
52 aesmodules = [ 'cryptosoft0', 'aesni0', 'ccr0', 'ccp0' ]
53 desmodules = [ 'cryptosoft0', ]
54 shamodules = [ 'cryptosoft0', 'aesni0', 'ccr0', 'ccp0' ]
56 def GenTestCase(cname):
58 crid = cryptodev.Crypto.findcrid(cname)
62 class GendCryptoTestCase(unittest.TestCase):
66 @unittest.skipIf(cname not in aesmodules, 'skipping AES-XTS on %s' % (cname))
68 for i in katg('XTSTestVectors/format tweak value input - data unit seq no', '*.rsp'):
69 self.runXTS(i, cryptodev.CRYPTO_AES_XTS)
71 @unittest.skipIf(cname not in aesmodules, 'skipping AES-CBC on %s' % (cname))
73 for i in katg('KAT_AES', 'CBC[GKV]*.rsp'):
76 @unittest.skipIf(cname not in aesmodules, 'skipping AES-CCM on %s' % (cname))
78 for i in katg('ccmtestvectors', 'V*.rsp'):
81 for i in katg('ccmtestvectors', 'D*.rsp'):
84 @unittest.skipIf(cname not in aesmodules, 'skipping AES-GCM on %s' % (cname))
86 for i in katg('gcmtestvectors', 'gcmEncrypt*'):
87 self.runGCM(i, 'ENCRYPT')
89 for i in katg('gcmtestvectors', 'gcmDecrypt*'):
90 self.runGCM(i, 'DECRYPT')
92 _gmacsizes = { 32: cryptodev.CRYPTO_AES_256_NIST_GMAC,
93 24: cryptodev.CRYPTO_AES_192_NIST_GMAC,
94 16: cryptodev.CRYPTO_AES_128_NIST_GMAC,
96 def runGCM(self, fname, mode):
100 curfun = Crypto.encrypt
101 elif mode == 'DECRYPT':
103 curfun = Crypto.decrypt
105 raise RuntimeError('unknown mode: %r' % repr(mode))
107 columns = [ 'Count', 'Key', 'IV', 'CT', 'AAD', 'Tag', 'PT', ]
108 with cryptodev.KATParser(fname, columns) as parser:
109 self.runGCMWithParser(parser, mode)
111 def runGCMWithParser(self, parser, mode):
112 for _, lines in next(parser):
114 curcnt = int(data['Count'])
115 cipherkey = binascii.unhexlify(data['Key'])
116 iv = binascii.unhexlify(data['IV'])
117 aad = binascii.unhexlify(data['AAD'])
118 tag = binascii.unhexlify(data['Tag'])
119 if 'FAIL' not in data:
120 pt = binascii.unhexlify(data['PT'])
121 ct = binascii.unhexlify(data['CT'])
124 # XXX - isn't supported
128 c = Crypto(cryptodev.CRYPTO_AES_NIST_GCM_16,
130 mac=self._gmacsizes[len(cipherkey)],
131 mackey=cipherkey, crid=crid,
133 except EnvironmentError as e:
134 # Can't test algorithms the driver does not support.
135 if e.errno != errno.EOPNOTSUPP:
139 if mode == 'ENCRYPT':
141 rct, rtag = c.encrypt(pt, iv, aad)
142 except EnvironmentError as e:
143 # Can't test inputs the driver does not support.
144 if e.errno != errno.EINVAL:
147 rtag = rtag[:len(tag)]
148 data['rct'] = binascii.hexlify(rct)
149 data['rtag'] = binascii.hexlify(rtag)
150 self.assertEqual(rct, ct, repr(data))
151 self.assertEqual(rtag, tag, repr(data))
155 args = (ct, iv, aad, tag)
157 self.assertRaises(IOError,
161 rpt, rtag = c.decrypt(*args)
162 except EnvironmentError as e:
163 # Can't test inputs the driver does not support.
164 if e.errno != errno.EINVAL:
167 data['rpt'] = binascii.hexlify(rpt)
168 data['rtag'] = binascii.hexlify(rtag)
169 self.assertEqual(rpt, pt,
172 def runCBC(self, fname):
173 columns = [ 'COUNT', 'KEY', 'IV', 'PLAINTEXT', 'CIPHERTEXT', ]
174 with cryptodev.KATParser(fname, columns) as parser:
175 self.runCBCWithParser(parser)
177 def runCBCWithParser(self, parser):
179 for mode, lines in next(parser):
180 if mode == 'ENCRYPT':
182 curfun = Crypto.encrypt
183 elif mode == 'DECRYPT':
185 curfun = Crypto.decrypt
187 raise RuntimeError('unknown mode: %r' % repr(mode))
190 curcnt = int(data['COUNT'])
191 cipherkey = binascii.unhexlify(data['KEY'])
192 iv = binascii.unhexlify(data['IV'])
193 pt = binascii.unhexlify(data['PLAINTEXT'])
194 ct = binascii.unhexlify(data['CIPHERTEXT'])
199 c = Crypto(cryptodev.CRYPTO_AES_CBC, cipherkey, crid=crid)
200 r = curfun(c, pt, iv)
201 self.assertEqual(r, ct)
203 def runXTS(self, fname, meth):
204 columns = [ 'COUNT', 'DataUnitLen', 'Key', 'DataUnitSeqNumber', 'PT',
206 with cryptodev.KATParser(fname, columns) as parser:
207 self.runXTSWithParser(parser, meth)
209 def runXTSWithParser(self, parser, meth):
211 for mode, lines in next(parser):
212 if mode == 'ENCRYPT':
214 curfun = Crypto.encrypt
215 elif mode == 'DECRYPT':
217 curfun = Crypto.decrypt
219 raise RuntimeError('unknown mode: %r' % repr(mode))
222 curcnt = int(data['COUNT'])
223 nbits = int(data['DataUnitLen'])
224 cipherkey = binascii.unhexlify(data['Key'])
225 iv = struct.pack('QQ', int(data['DataUnitSeqNumber']), 0)
226 pt = binascii.unhexlify(data['PT'])
227 ct = binascii.unhexlify(data['CT'])
230 # XXX - mark as skipped
236 c = Crypto(meth, cipherkey, crid=crid)
237 r = curfun(c, pt, iv)
238 except EnvironmentError as e:
239 # Can't test hashes the driver does not support.
240 if e.errno != errno.EOPNOTSUPP:
243 self.assertEqual(r, ct)
245 def runCCMEncrypt(self, fname):
246 with cryptodev.KATCCMParser(fname) as parser:
247 self.runCCMEncryptWithParser(parser)
249 def runCCMEncryptWithParser(self, parser):
250 for data in next(parser):
251 Nlen = int(data['Nlen'])
253 # OCF only supports 12 byte IVs
255 key = binascii.unhexlify(data['Key'])
256 nonce = binascii.unhexlify(data['Nonce'])
257 Alen = int(data['Alen'])
259 aad = binascii.unhexlify(data['Adata'])
262 payload = binascii.unhexlify(data['Payload'])
263 ct = binascii.unhexlify(data['CT'])
266 c = Crypto(crid=crid,
267 cipher=cryptodev.CRYPTO_AES_CCM_16,
269 mac=cryptodev.CRYPTO_AES_CCM_CBC_MAC,
270 mackey=key, maclen=16)
271 r, tag = Crypto.encrypt(c, payload,
273 except EnvironmentError as e:
274 if e.errno != errno.EOPNOTSUPP:
279 self.assertEqual(out, ct,
280 "Count " + data['Count'] + " Actual: " + \
281 repr(binascii.hexlify(out)) + " Expected: " + \
282 repr(data) + " on " + cname)
284 def runCCMDecrypt(self, fname):
285 with cryptodev.KATCCMParser(fname) as parser:
286 self.runCCMDecryptWithParser(parser)
288 def runCCMDecryptWithParser(self, parser):
289 # XXX: Note that all of the current CCM
290 # decryption test vectors use IV and tag sizes
291 # that aren't supported by OCF none of the
292 # tests are actually ran.
293 for data in next(parser):
294 Nlen = int(data['Nlen'])
296 # OCF only supports 12 byte IVs
298 Tlen = int(data['Tlen'])
300 # OCF only supports 16 byte tags
302 key = binascii.unhexlify(data['Key'])
303 nonce = binascii.unhexlify(data['Nonce'])
304 Alen = int(data['Alen'])
306 aad = binascii.unhexlify(data['Adata'])
309 ct = binascii.unhexlify(data['CT'])
314 c = Crypto(crid=crid,
315 cipher=cryptodev.CRYPTO_AES_CCM_16,
317 mac=cryptodev.CRYPTO_AES_CCM_CBC_MAC,
318 mackey=key, maclen=16)
319 except EnvironmentError as e:
320 if e.errno != errno.EOPNOTSUPP:
324 if data['Result'] == 'Fail':
325 self.assertRaises(IOError,
326 c.decrypt, payload, nonce, aad, tag)
328 r = Crypto.decrypt(c, payload, nonce,
331 payload = binascii.unhexlify(data['Payload'])
332 plen = int(data('Plen'))
333 payload = payload[:plen]
334 self.assertEqual(r, payload,
335 "Count " + data['Count'] + \
336 " Actual: " + repr(binascii.hexlify(r)) + \
337 " Expected: " + repr(data) + \
343 @unittest.skipIf(cname not in desmodules, 'skipping DES on %s' % (cname))
345 for i in katg('KAT_TDES', 'TCBC[a-z]*.rsp'):
348 def runTDES(self, fname):
349 columns = [ 'COUNT', 'KEYs', 'IV', 'PLAINTEXT', 'CIPHERTEXT', ]
350 with cryptodev.KATParser(fname, columns) as parser:
351 self.runTDESWithParser(parser)
353 def runTDESWithParser(self, parser):
355 for mode, lines in next(parser):
356 if mode == 'ENCRYPT':
358 curfun = Crypto.encrypt
359 elif mode == 'DECRYPT':
361 curfun = Crypto.decrypt
363 raise RuntimeError('unknown mode: %r' % repr(mode))
366 curcnt = int(data['COUNT'])
367 key = data['KEYs'] * 3
368 cipherkey = binascii.unhexlify(key)
369 iv = binascii.unhexlify(data['IV'])
370 pt = binascii.unhexlify(data['PLAINTEXT'])
371 ct = binascii.unhexlify(data['CIPHERTEXT'])
376 c = Crypto(cryptodev.CRYPTO_3DES_CBC, cipherkey, crid=crid)
377 r = curfun(c, pt, iv)
378 self.assertEqual(r, ct)
383 @unittest.skipIf(cname not in shamodules, 'skipping SHA on %s' % str(cname))
385 for i in katg('shabytetestvectors', 'SHA*Msg.rsp'):
388 def runSHA(self, fname):
389 # Skip SHA512_(224|256) tests
390 if fname.find('SHA512_') != -1:
392 columns = [ 'Len', 'Msg', 'MD' ]
393 with cryptodev.KATParser(fname, columns) as parser:
394 self.runSHAWithParser(parser)
396 def runSHAWithParser(self, parser):
397 for hashlength, lines in next(parser):
398 # E.g., hashlength will be "L=20" (bytes)
399 hashlen = int(hashlength.split("=")[1])
402 alg = cryptodev.CRYPTO_SHA1
404 alg = cryptodev.CRYPTO_SHA2_224
406 alg = cryptodev.CRYPTO_SHA2_256
408 alg = cryptodev.CRYPTO_SHA2_384
410 alg = cryptodev.CRYPTO_SHA2_512
412 # Skip unsupported hashes
413 # Slurp remaining input in section
419 msg = binascii.unhexlify(data['Msg'])
420 msg = msg[:int(data['Len'])]
421 md = binascii.unhexlify(data['MD'])
424 c = Crypto(mac=alg, crid=crid,
426 except EnvironmentError as e:
427 # Can't test hashes the driver does not support.
428 if e.errno != errno.EOPNOTSUPP:
432 _, r = c.encrypt(msg, iv="")
434 self.assertEqual(r, md, "Actual: " + \
435 repr(binascii.hexlify(r)) + " Expected: " + repr(data) + " on " + cname)
437 @unittest.skipIf(cname not in shamodules, 'skipping SHA-HMAC on %s' % str(cname))
438 def test_sha1hmac(self):
439 for i in katg('hmactestvectors', 'HMAC.rsp'):
442 def runSHA1HMAC(self, fname):
443 columns = [ 'Count', 'Klen', 'Tlen', 'Key', 'Msg', 'Mac' ]
444 with cryptodev.KATParser(fname, columns) as parser:
445 self.runSHA1HMACWithParser(parser)
447 def runSHA1HMACWithParser(self, parser):
448 for hashlength, lines in next(parser):
449 # E.g., hashlength will be "L=20" (bytes)
450 hashlen = int(hashlength.split("=")[1])
454 alg = cryptodev.CRYPTO_SHA1_HMAC
457 alg = cryptodev.CRYPTO_SHA2_224_HMAC
460 alg = cryptodev.CRYPTO_SHA2_256_HMAC
463 alg = cryptodev.CRYPTO_SHA2_384_HMAC
466 alg = cryptodev.CRYPTO_SHA2_512_HMAC
469 # Skip unsupported hashes
470 # Slurp remaining input in section
476 key = binascii.unhexlify(data['Key'])
477 msg = binascii.unhexlify(data['Msg'])
478 mac = binascii.unhexlify(data['Mac'])
479 tlen = int(data['Tlen'])
481 if len(key) > blocksize:
485 c = Crypto(mac=alg, mackey=key,
486 crid=crid, maclen=hashlen)
487 except EnvironmentError as e:
488 # Can't test hashes the driver does not support.
489 if e.errno != errno.EOPNOTSUPP:
493 _, r = c.encrypt(msg, iv="")
495 self.assertEqual(r[:tlen], mac, "Actual: " + \
496 repr(binascii.hexlify(r)) + " Expected: " + repr(data))
498 return GendCryptoTestCase
500 cryptosoft = GenTestCase('cryptosoft0')
501 aesni = GenTestCase('aesni0')
502 ccr = GenTestCase('ccr0')
503 ccp = GenTestCase('ccp0')
505 if __name__ == '__main__':