]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/opencrypto/cryptotest.py
tests/sys/opencrypto: fix whitespace per PEP8
[FreeBSD/FreeBSD.git] / tests / sys / opencrypto / cryptotest.py
1 #!/usr/local/bin/python2
2 #
3 # Copyright (c) 2014 The FreeBSD Foundation
4 # All rights reserved.
5 #
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
10 # are met:
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.
16 #
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
27 # SUCH DAMAGE.
28 #
29 # $FreeBSD$
30 #
31
32 from __future__ import print_function
33 import errno
34 import cryptodev
35 import itertools
36 import os
37 import struct
38 import unittest
39 from cryptodev import *
40 from glob import iglob
41
42 katdir = '/usr/local/share/nist-kat'
43
44 def katg(base, glob):
45     assert os.path.exists(os.path.join(katdir, base)), "Please 'pkg install nist-kat'"
46     return iglob(os.path.join(katdir, base, glob))
47
48 aesmodules = [ 'cryptosoft0', 'aesni0', 'ccr0', 'ccp0' ]
49 desmodules = [ 'cryptosoft0', ]
50 shamodules = [ 'cryptosoft0', 'aesni0', 'ccr0', 'ccp0' ]
51
52 def GenTestCase(cname):
53     try:
54         crid = cryptodev.Crypto.findcrid(cname)
55     except IOError:
56         return None
57
58     class GendCryptoTestCase(unittest.TestCase):
59         ###############
60         ##### AES #####
61         ###############
62         @unittest.skipIf(cname not in aesmodules, 'skipping AES on %s' % (cname))
63         def test_xts(self):
64             for i in katg('XTSTestVectors/format tweak value input - data unit seq no', '*.rsp'):
65                 self.runXTS(i, cryptodev.CRYPTO_AES_XTS)
66
67         @unittest.skipIf(cname not in aesmodules, 'skipping AES on %s' % (cname))
68         def test_cbc(self):
69             for i in katg('KAT_AES', 'CBC[GKV]*.rsp'):
70                 self.runCBC(i)
71
72         @unittest.skipIf(cname not in aesmodules, 'skipping AES on %s' % (cname))
73         def test_gcm(self):
74             for i in katg('gcmtestvectors', 'gcmEncrypt*'):
75                 self.runGCM(i, 'ENCRYPT')
76
77             for i in katg('gcmtestvectors', 'gcmDecrypt*'):
78                 self.runGCM(i, 'DECRYPT')
79
80         _gmacsizes = { 32: cryptodev.CRYPTO_AES_256_NIST_GMAC,
81             24: cryptodev.CRYPTO_AES_192_NIST_GMAC,
82             16: cryptodev.CRYPTO_AES_128_NIST_GMAC,
83         }
84         def runGCM(self, fname, mode):
85             curfun = None
86             if mode == 'ENCRYPT':
87                 swapptct = False
88                 curfun = Crypto.encrypt
89             elif mode == 'DECRYPT':
90                 swapptct = True
91                 curfun = Crypto.decrypt
92             else:
93                 raise RuntimeError('unknown mode: %r' % repr(mode))
94
95             for bogusmode, lines in cryptodev.KATParser(fname,
96                 [ 'Count', 'Key', 'IV', 'CT', 'AAD', 'Tag', 'PT', ]):
97                 for data in lines:
98                     curcnt = int(data['Count'])
99                     cipherkey = data['Key'].decode('hex')
100                     iv = data['IV'].decode('hex')
101                     aad = data['AAD'].decode('hex')
102                     tag = data['Tag'].decode('hex')
103                     if 'FAIL' not in data:
104                         pt = data['PT'].decode('hex')
105                     ct = data['CT'].decode('hex')
106
107                     if len(iv) != 12:
108                         # XXX - isn't supported
109                         continue
110
111                     try:
112                         c = Crypto(cryptodev.CRYPTO_AES_NIST_GCM_16,
113                             cipherkey,
114                             mac=self._gmacsizes[len(cipherkey)],
115                             mackey=cipherkey, crid=crid)
116                     except EnvironmentError, e:
117                         # Can't test algorithms the driver does not support.
118                         if e.errno != errno.EOPNOTSUPP:
119                             raise
120                         continue
121
122                     if mode == 'ENCRYPT':
123                         try:
124                             rct, rtag = c.encrypt(pt, iv, aad)
125                         except EnvironmentError, e:
126                             # Can't test inputs the driver does not support.
127                             if e.errno != errno.EINVAL:
128                                 raise
129                             continue
130                         rtag = rtag[:len(tag)]
131                         data['rct'] = rct.encode('hex')
132                         data['rtag'] = rtag.encode('hex')
133                         self.assertEqual(rct, ct, repr(data))
134                         self.assertEqual(rtag, tag, repr(data))
135                     else:
136                         if len(tag) != 16:
137                             continue
138                         args = (ct, iv, aad, tag)
139                         if 'FAIL' in data:
140                             self.assertRaises(IOError,
141                                 c.decrypt, *args)
142                         else:
143                             try:
144                                 rpt, rtag = c.decrypt(*args)
145                             except EnvironmentError, e:
146                                 # Can't test inputs the driver does not support.
147                                 if e.errno != errno.EINVAL:
148                                     raise
149                                 continue
150                             data['rpt'] = rpt.encode('hex')
151                             data['rtag'] = rtag.encode('hex')
152                             self.assertEqual(rpt, pt,
153                                 repr(data))
154
155         def runCBC(self, fname):
156             curfun = None
157             for mode, lines in cryptodev.KATParser(fname,
158                 [ 'COUNT', 'KEY', 'IV', 'PLAINTEXT', 'CIPHERTEXT', ]):
159                 if mode == 'ENCRYPT':
160                     swapptct = False
161                     curfun = Crypto.encrypt
162                 elif mode == 'DECRYPT':
163                     swapptct = True
164                     curfun = Crypto.decrypt
165                 else:
166                     raise RuntimeError('unknown mode: %r' % repr(mode))
167
168                 for data in lines:
169                     curcnt = int(data['COUNT'])
170                     cipherkey = data['KEY'].decode('hex')
171                     iv = data['IV'].decode('hex')
172                     pt = data['PLAINTEXT'].decode('hex')
173                     ct = data['CIPHERTEXT'].decode('hex')
174
175                     if swapptct:
176                         pt, ct = ct, pt
177                     # run the fun
178                     c = Crypto(cryptodev.CRYPTO_AES_CBC, cipherkey, crid=crid)
179                     r = curfun(c, pt, iv)
180                     self.assertEqual(r, ct)
181
182         def runXTS(self, fname, meth):
183             curfun = None
184             for mode, lines in cryptodev.KATParser(fname,
185                 [ 'COUNT', 'DataUnitLen', 'Key', 'DataUnitSeqNumber', 'PT',
186                 'CT' ]):
187                 if mode == 'ENCRYPT':
188                     swapptct = False
189                     curfun = Crypto.encrypt
190                 elif mode == 'DECRYPT':
191                     swapptct = True
192                     curfun = Crypto.decrypt
193                 else:
194                     raise RuntimeError('unknown mode: %r' % repr(mode))
195
196                 for data in lines:
197                     curcnt = int(data['COUNT'])
198                     nbits = int(data['DataUnitLen'])
199                     cipherkey = data['Key'].decode('hex')
200                     iv = struct.pack('QQ', int(data['DataUnitSeqNumber']), 0)
201                     pt = data['PT'].decode('hex')
202                     ct = data['CT'].decode('hex')
203
204                     if nbits % 128 != 0:
205                         # XXX - mark as skipped
206                         continue
207                     if swapptct:
208                         pt, ct = ct, pt
209                     # run the fun
210                     try:
211                         c = Crypto(meth, cipherkey, crid=crid)
212                         r = curfun(c, pt, iv)
213                     except EnvironmentError, e:
214                         # Can't test hashes the driver does not support.
215                         if e.errno != errno.EOPNOTSUPP:
216                             raise
217                         continue
218                     self.assertEqual(r, ct)
219
220         ###############
221         ##### DES #####
222         ###############
223         @unittest.skipIf(cname not in desmodules, 'skipping DES on %s' % (cname))
224         def test_tdes(self):
225             for i in katg('KAT_TDES', 'TCBC[a-z]*.rsp'):
226                 self.runTDES(i)
227
228         def runTDES(self, fname):
229             curfun = None
230             for mode, lines in cryptodev.KATParser(fname,
231                 [ 'COUNT', 'KEYs', 'IV', 'PLAINTEXT', 'CIPHERTEXT', ]):
232                 if mode == 'ENCRYPT':
233                     swapptct = False
234                     curfun = Crypto.encrypt
235                 elif mode == 'DECRYPT':
236                     swapptct = True
237                     curfun = Crypto.decrypt
238                 else:
239                     raise RuntimeError('unknown mode: %r' % repr(mode))
240
241                 for data in lines:
242                     curcnt = int(data['COUNT'])
243                     key = data['KEYs'] * 3
244                     cipherkey = key.decode('hex')
245                     iv = data['IV'].decode('hex')
246                     pt = data['PLAINTEXT'].decode('hex')
247                     ct = data['CIPHERTEXT'].decode('hex')
248
249                     if swapptct:
250                         pt, ct = ct, pt
251                     # run the fun
252                     c = Crypto(cryptodev.CRYPTO_3DES_CBC, cipherkey, crid=crid)
253                     r = curfun(c, pt, iv)
254                     self.assertEqual(r, ct)
255
256         ###############
257         ##### SHA #####
258         ###############
259         @unittest.skipIf(cname not in shamodules, 'skipping SHA on %s' % str(cname))
260         def test_sha(self):
261             # SHA not available in software
262             pass
263             #for i in iglob('SHA1*'):
264             #    self.runSHA(i)
265
266         @unittest.skipIf(cname not in shamodules, 'skipping SHA on %s' % str(cname))
267         def test_sha1hmac(self):
268             for i in katg('hmactestvectors', 'HMAC.rsp'):
269                 self.runSHA1HMAC(i)
270
271         def runSHA1HMAC(self, fname):
272             for hashlength, lines in cryptodev.KATParser(fname,
273                 [ 'Count', 'Klen', 'Tlen', 'Key', 'Msg', 'Mac' ]):
274                 # E.g., hashlength will be "L=20" (bytes)
275                 hashlen = int(hashlength.split("=")[1])
276
277                 blocksize = None
278                 if hashlen == 20:
279                     alg = cryptodev.CRYPTO_SHA1_HMAC
280                     blocksize = 64
281                 elif hashlen == 28:
282                     alg = cryptodev.CRYPTO_SHA2_224_HMAC
283                     blocksize = 64
284                 elif hashlen == 32:
285                     alg = cryptodev.CRYPTO_SHA2_256_HMAC
286                     blocksize = 64
287                 elif hashlen == 48:
288                     alg = cryptodev.CRYPTO_SHA2_384_HMAC
289                     blocksize = 128
290                 elif hashlen == 64:
291                     alg = cryptodev.CRYPTO_SHA2_512_HMAC
292                     blocksize = 128
293                 else:
294                     # Skip unsupported hashes
295                     # Slurp remaining input in section
296                     for data in lines:
297                         continue
298                     continue
299
300                 for data in lines:
301                     key = data['Key'].decode('hex')
302                     msg = data['Msg'].decode('hex')
303                     mac = data['Mac'].decode('hex')
304                     tlen = int(data['Tlen'])
305
306                     if len(key) > blocksize:
307                         continue
308
309                     try:
310                         c = Crypto(mac=alg, mackey=key,
311                             crid=crid)
312                     except EnvironmentError, e:
313                         # Can't test hashes the driver does not support.
314                         if e.errno != errno.EOPNOTSUPP:
315                             raise
316                         continue
317
318                     _, r = c.encrypt(msg, iv="")
319
320                     # A limitation in cryptodev.py means we
321                     # can only store MACs up to 16 bytes.
322                     # That's good enough to validate the
323                     # correct behavior, more or less.
324                     maclen = min(tlen, 16)
325                     self.assertEqual(r[:maclen], mac[:maclen], "Actual: " + \
326                         repr(r[:maclen].encode("hex")) + " Expected: " + repr(data))
327
328     return GendCryptoTestCase
329
330 cryptosoft = GenTestCase('cryptosoft0')
331 aesni = GenTestCase('aesni0')
332 ccr = GenTestCase('ccr0')
333 ccp = GenTestCase('ccp0')
334
335 if __name__ == '__main__':
336     unittest.main()