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
39 from cryptodev import *
40 from glob import iglob
42 katdir = '/usr/local/share/nist-kat'
45 assert os.path.exists(katdir), "Please 'pkg install nist-kat'"
46 if not os.path.exists(os.path.join(katdir, base)):
47 raise unittest.SkipTest("Missing %s test vectors" % (base))
48 return iglob(os.path.join(katdir, base, glob))
50 aesmodules = [ 'cryptosoft0', 'aesni0', 'ccr0', 'ccp0' ]
51 desmodules = [ 'cryptosoft0', ]
52 shamodules = [ 'cryptosoft0', 'aesni0', 'ccr0', 'ccp0' ]
54 def GenTestCase(cname):
56 crid = cryptodev.Crypto.findcrid(cname)
60 class GendCryptoTestCase(unittest.TestCase):
64 @unittest.skipIf(cname not in aesmodules, 'skipping AES-XTS on %s' % (cname))
66 for i in katg('XTSTestVectors/format tweak value input - data unit seq no', '*.rsp'):
67 self.runXTS(i, cryptodev.CRYPTO_AES_XTS)
69 @unittest.skipIf(cname not in aesmodules, 'skipping AES-CBC on %s' % (cname))
71 for i in katg('KAT_AES', 'CBC[GKV]*.rsp'):
74 @unittest.skipIf(cname not in aesmodules, 'skipping AES-CCM on %s' % (cname))
76 for i in katg('ccmtestvectors', 'V*.rsp'):
79 for i in katg('ccmtestvectors', 'D*.rsp'):
82 @unittest.skipIf(cname not in aesmodules, 'skipping AES-GCM on %s' % (cname))
84 for i in katg('gcmtestvectors', 'gcmEncrypt*'):
85 self.runGCM(i, 'ENCRYPT')
87 for i in katg('gcmtestvectors', 'gcmDecrypt*'):
88 self.runGCM(i, 'DECRYPT')
90 _gmacsizes = { 32: cryptodev.CRYPTO_AES_256_NIST_GMAC,
91 24: cryptodev.CRYPTO_AES_192_NIST_GMAC,
92 16: cryptodev.CRYPTO_AES_128_NIST_GMAC,
94 def runGCM(self, fname, mode):
98 curfun = Crypto.encrypt
99 elif mode == 'DECRYPT':
101 curfun = Crypto.decrypt
103 raise RuntimeError('unknown mode: %r' % repr(mode))
105 for bogusmode, lines in cryptodev.KATParser(fname,
106 [ 'Count', 'Key', 'IV', 'CT', 'AAD', 'Tag', 'PT', ]):
108 curcnt = int(data['Count'])
109 cipherkey = data['Key'].decode('hex')
110 iv = data['IV'].decode('hex')
111 aad = data['AAD'].decode('hex')
112 tag = data['Tag'].decode('hex')
113 if 'FAIL' not in data:
114 pt = data['PT'].decode('hex')
115 ct = data['CT'].decode('hex')
118 # XXX - isn't supported
122 c = Crypto(cryptodev.CRYPTO_AES_NIST_GCM_16,
124 mac=self._gmacsizes[len(cipherkey)],
125 mackey=cipherkey, crid=crid,
127 except EnvironmentError, e:
128 # Can't test algorithms the driver does not support.
129 if e.errno != errno.EOPNOTSUPP:
133 if mode == 'ENCRYPT':
135 rct, rtag = c.encrypt(pt, iv, aad)
136 except EnvironmentError, e:
137 # Can't test inputs the driver does not support.
138 if e.errno != errno.EINVAL:
141 rtag = rtag[:len(tag)]
142 data['rct'] = rct.encode('hex')
143 data['rtag'] = rtag.encode('hex')
144 self.assertEqual(rct, ct, repr(data))
145 self.assertEqual(rtag, tag, repr(data))
149 args = (ct, iv, aad, tag)
151 self.assertRaises(IOError,
155 rpt, rtag = c.decrypt(*args)
156 except EnvironmentError, e:
157 # Can't test inputs the driver does not support.
158 if e.errno != errno.EINVAL:
161 data['rpt'] = rpt.encode('hex')
162 data['rtag'] = rtag.encode('hex')
163 self.assertEqual(rpt, pt,
166 def runCBC(self, fname):
168 for mode, lines in cryptodev.KATParser(fname,
169 [ 'COUNT', 'KEY', 'IV', 'PLAINTEXT', 'CIPHERTEXT', ]):
170 if mode == 'ENCRYPT':
172 curfun = Crypto.encrypt
173 elif mode == 'DECRYPT':
175 curfun = Crypto.decrypt
177 raise RuntimeError('unknown mode: %r' % repr(mode))
180 curcnt = int(data['COUNT'])
181 cipherkey = data['KEY'].decode('hex')
182 iv = data['IV'].decode('hex')
183 pt = data['PLAINTEXT'].decode('hex')
184 ct = data['CIPHERTEXT'].decode('hex')
189 c = Crypto(cryptodev.CRYPTO_AES_CBC, cipherkey, crid=crid)
190 r = curfun(c, pt, iv)
191 self.assertEqual(r, ct)
193 def runXTS(self, fname, meth):
195 for mode, lines in cryptodev.KATParser(fname,
196 [ 'COUNT', 'DataUnitLen', 'Key', 'DataUnitSeqNumber', 'PT',
198 if mode == 'ENCRYPT':
200 curfun = Crypto.encrypt
201 elif mode == 'DECRYPT':
203 curfun = Crypto.decrypt
205 raise RuntimeError('unknown mode: %r' % repr(mode))
208 curcnt = int(data['COUNT'])
209 nbits = int(data['DataUnitLen'])
210 cipherkey = data['Key'].decode('hex')
211 iv = struct.pack('QQ', int(data['DataUnitSeqNumber']), 0)
212 pt = data['PT'].decode('hex')
213 ct = data['CT'].decode('hex')
216 # XXX - mark as skipped
222 c = Crypto(meth, cipherkey, crid=crid)
223 r = curfun(c, pt, iv)
224 except EnvironmentError, e:
225 # Can't test hashes the driver does not support.
226 if e.errno != errno.EOPNOTSUPP:
229 self.assertEqual(r, ct)
231 def runCCMEncrypt(self, fname):
232 for data in cryptodev.KATCCMParser(fname):
233 Nlen = int(data['Nlen'])
235 # OCF only supports 12 byte IVs
237 key = data['Key'].decode('hex')
238 nonce = data['Nonce'].decode('hex')
239 Alen = int(data['Alen'])
241 aad = data['Adata'].decode('hex')
244 payload = data['Payload'].decode('hex')
245 ct = data['CT'].decode('hex')
248 c = Crypto(crid=crid,
249 cipher=cryptodev.CRYPTO_AES_CCM_16,
251 mac=cryptodev.CRYPTO_AES_CCM_CBC_MAC,
252 mackey=key, maclen=16)
253 r, tag = Crypto.encrypt(c, payload,
255 except EnvironmentError, e:
256 if e.errno != errno.EOPNOTSUPP:
261 self.assertEqual(out, ct,
262 "Count " + data['Count'] + " Actual: " + \
263 repr(out.encode("hex")) + " Expected: " + \
264 repr(data) + " on " + cname)
266 def runCCMDecrypt(self, fname):
267 # XXX: Note that all of the current CCM
268 # decryption test vectors use IV and tag sizes
269 # that aren't supported by OCF none of the
270 # tests are actually ran.
271 for data in cryptodev.KATCCMParser(fname):
272 Nlen = int(data['Nlen'])
274 # OCF only supports 12 byte IVs
276 Tlen = int(data['Tlen'])
278 # OCF only supports 16 byte tags
280 key = data['Key'].decode('hex')
281 nonce = data['Nonce'].decode('hex')
282 Alen = int(data['Alen'])
284 aad = data['Adata'].decode('hex')
287 ct = data['CT'].decode('hex')
292 c = Crypto(crid=crid,
293 cipher=cryptodev.CRYPTO_AES_CCM_16,
295 mac=cryptodev.CRYPTO_AES_CCM_CBC_MAC,
296 mackey=key, maclen=16)
297 except EnvironmentError, e:
298 if e.errno != errno.EOPNOTSUPP:
302 if data['Result'] == 'Fail':
303 self.assertRaises(IOError,
304 c.decrypt, payload, nonce, aad, tag)
306 r = Crypto.decrypt(c, payload, nonce,
309 payload = data['Payload'].decode('hex')
310 Plen = int(data('Plen'))
311 payload = payload[:plen]
312 self.assertEqual(r, payload,
313 "Count " + data['Count'] + \
314 " Actual: " + repr(r.encode("hex")) + \
315 " Expected: " + repr(data) + \
321 @unittest.skipIf(cname not in desmodules, 'skipping DES on %s' % (cname))
323 for i in katg('KAT_TDES', 'TCBC[a-z]*.rsp'):
326 def runTDES(self, fname):
328 for mode, lines in cryptodev.KATParser(fname,
329 [ 'COUNT', 'KEYs', 'IV', 'PLAINTEXT', 'CIPHERTEXT', ]):
330 if mode == 'ENCRYPT':
332 curfun = Crypto.encrypt
333 elif mode == 'DECRYPT':
335 curfun = Crypto.decrypt
337 raise RuntimeError('unknown mode: %r' % repr(mode))
340 curcnt = int(data['COUNT'])
341 key = data['KEYs'] * 3
342 cipherkey = key.decode('hex')
343 iv = data['IV'].decode('hex')
344 pt = data['PLAINTEXT'].decode('hex')
345 ct = data['CIPHERTEXT'].decode('hex')
350 c = Crypto(cryptodev.CRYPTO_3DES_CBC, cipherkey, crid=crid)
351 r = curfun(c, pt, iv)
352 self.assertEqual(r, ct)
357 @unittest.skipIf(cname not in shamodules, 'skipping SHA on %s' % str(cname))
359 for i in katg('shabytetestvectors', 'SHA*Msg.rsp'):
362 def runSHA(self, fname):
363 # Skip SHA512_(224|256) tests
364 if fname.find('SHA512_') != -1:
367 for hashlength, lines in cryptodev.KATParser(fname,
368 [ 'Len', 'Msg', 'MD' ]):
369 # E.g., hashlength will be "L=20" (bytes)
370 hashlen = int(hashlength.split("=")[1])
373 alg = cryptodev.CRYPTO_SHA1
375 alg = cryptodev.CRYPTO_SHA2_224
377 alg = cryptodev.CRYPTO_SHA2_256
379 alg = cryptodev.CRYPTO_SHA2_384
381 alg = cryptodev.CRYPTO_SHA2_512
383 # Skip unsupported hashes
384 # Slurp remaining input in section
390 msg = data['Msg'].decode('hex')
391 msg = msg[:int(data['Len'])]
392 md = data['MD'].decode('hex')
395 c = Crypto(mac=alg, crid=crid,
397 except EnvironmentError, e:
398 # Can't test hashes the driver does not support.
399 if e.errno != errno.EOPNOTSUPP:
403 _, r = c.encrypt(msg, iv="")
405 self.assertEqual(r, md, "Actual: " + \
406 repr(r.encode("hex")) + " Expected: " + repr(data) + " on " + cname)
408 @unittest.skipIf(cname not in shamodules, 'skipping SHA-HMAC on %s' % str(cname))
409 def test_sha1hmac(self):
410 for i in katg('hmactestvectors', 'HMAC.rsp'):
413 def runSHA1HMAC(self, fname):
414 for hashlength, lines in cryptodev.KATParser(fname,
415 [ 'Count', 'Klen', 'Tlen', 'Key', 'Msg', 'Mac' ]):
416 # E.g., hashlength will be "L=20" (bytes)
417 hashlen = int(hashlength.split("=")[1])
421 alg = cryptodev.CRYPTO_SHA1_HMAC
424 alg = cryptodev.CRYPTO_SHA2_224_HMAC
427 alg = cryptodev.CRYPTO_SHA2_256_HMAC
430 alg = cryptodev.CRYPTO_SHA2_384_HMAC
433 alg = cryptodev.CRYPTO_SHA2_512_HMAC
436 # Skip unsupported hashes
437 # Slurp remaining input in section
443 key = data['Key'].decode('hex')
444 msg = data['Msg'].decode('hex')
445 mac = data['Mac'].decode('hex')
446 tlen = int(data['Tlen'])
448 if len(key) > blocksize:
452 c = Crypto(mac=alg, mackey=key,
453 crid=crid, maclen=hashlen)
454 except EnvironmentError, e:
455 # Can't test hashes the driver does not support.
456 if e.errno != errno.EOPNOTSUPP:
460 _, r = c.encrypt(msg, iv="")
462 self.assertEqual(r[:tlen], mac, "Actual: " + \
463 repr(r.encode("hex")) + " Expected: " + repr(data))
465 return GendCryptoTestCase
467 cryptosoft = GenTestCase('cryptosoft0')
468 aesni = GenTestCase('aesni0')
469 ccr = GenTestCase('ccr0')
470 ccp = GenTestCase('ccp0')
472 if __name__ == '__main__':