]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/opencrypto/cryptodev.py
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / tests / sys / opencrypto / cryptodev.py
1 #!/usr/local/bin/python3
2 #
3 # Copyright (c) 2014 The FreeBSD Foundation
4 # Copyright 2014 John-Mark Gurney
5 # All rights reserved.
6 # Copyright 2019 Enji Cooper
7 #
8 # This software was developed by John-Mark Gurney under
9 # the sponsorship from the FreeBSD Foundation.
10 # Redistribution and use in source and binary forms, with or without
11 # modification, are permitted provided that the following conditions
12 # are met:
13 # 1.  Redistributions of source code must retain the above copyright
14 #     notice, this list of conditions and the following disclaimer.
15 # 2.  Redistributions in binary form must reproduce the above copyright
16 #     notice, this list of conditions and the following disclaimer in the
17 #     documentation and/or other materials provided with the distribution.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 # SUCH DAMAGE.
30 #
31 # $FreeBSD$
32 #
33
34
35 import array
36 import binascii
37 from fcntl import ioctl
38 import os
39 import platform
40 import random
41 import signal
42 from struct import pack as _pack
43 import sys
44 import time
45
46 import dpkt
47
48 from cryptodevh import *
49
50 __all__ = [ 'Crypto', 'MismatchError', ]
51
52 class FindOp(dpkt.Packet):
53     __byte_order__ = '@'
54     __hdr__ = (
55         ('crid', 'i',   0),
56         ('name', '32s', 0),
57     )
58
59 class SessionOp(dpkt.Packet):
60     __byte_order__ = '@'
61     __hdr__ = (
62         ('cipher',    'I', 0),
63         ('mac',       'I', 0),
64         ('keylen',    'I', 0),
65         ('key',       'P', 0),
66         ('mackeylen', 'i', 0),
67         ('mackey',    'P', 0),
68         ('ses',       'I', 0),
69     )
70
71 class SessionOp2(dpkt.Packet):
72     __byte_order__ = '@'
73     __hdr__ = (
74         ('cipher',    'I', 0),
75         ('mac',       'I', 0),
76         ('keylen',    'I', 0),
77         ('key',       'P', 0),
78         ('mackeylen', 'i', 0),
79         ('mackey',    'P', 0),
80         ('ses',       'I', 0),
81         ('crid',      'i', 0),
82         ('pad0',      'i', 0),
83         ('pad1',      'i', 0),
84         ('pad2',      'i', 0),
85         ('pad3',      'i', 0),
86     )
87
88 class CryptOp(dpkt.Packet):
89     __byte_order__ = '@'
90     __hdr__ = (
91         ('ses',   'I', 0),
92         ('op',    'H', 0),
93         ('flags', 'H', 0),
94         ('len',   'I', 0),
95         ('src',   'P', 0),
96         ('dst',   'P', 0),
97         ('mac',   'P', 0),
98         ('iv',    'P', 0),
99     )
100
101 class CryptAEAD(dpkt.Packet):
102     __byte_order__ = '@'
103     __hdr__ = (
104         ('ses',    'I', 0),
105         ('op',     'H', 0),
106         ('flags',  'H', 0),
107         ('len',    'I', 0),
108         ('aadlen', 'I', 0),
109         ('ivlen',  'I', 0),
110         ('src',    'P', 0),
111         ('dst',    'P', 0),
112         ('aad',    'P', 0),
113         ('tag',    'P', 0),
114         ('iv',     'P', 0),
115     )
116
117 # h2py.py can't handle multiarg macros
118 CIOCGSESSION = 3224396645
119 CIOCFSESSION = 2147771238
120 CIOCKEY = 3230688104
121 CIOCASYMFEAT = 1074029417
122 CIOCKEY2 = 3230688107
123 CIOCFINDDEV = 3223610220
124 if platform.architecture()[0] == '64bit':
125     CIOCGSESSION2 = 3225445226
126     CIOCCRYPT = 3224396647
127     CIOCCRYPTAEAD = 3225445229
128 else:
129     CIOCGSESSION2 = 3224396650
130     CIOCCRYPT = 3223085927
131     CIOCCRYPTAEAD = 3223872365
132
133 _cryptodev = os.open('/dev/crypto', os.O_RDWR)
134
135 def str_to_ascii(val):
136     if sys.version_info[0] >= 3:
137         if isinstance(val, str):
138             return val.encode("ascii")
139     return val
140
141 def _findop(crid, name):
142     fop = FindOp()
143     fop.crid = crid
144     fop.name = str_to_ascii(name)
145     s = array.array('B', fop.pack_hdr())
146     ioctl(_cryptodev, CIOCFINDDEV, s, 1)
147     fop.unpack(s)
148
149     try:
150         idx = fop.name.index(b'\x00')
151         name = fop.name[:idx]
152     except ValueError:
153         name = fop.name
154
155     return fop.crid, name
156
157 def array_tobytes(array_obj):
158     if sys.version_info[:2] >= (3, 2):
159         return array_obj.tobytes()
160     return array_obj.tostring()
161
162 class Crypto:
163     @staticmethod
164     def findcrid(name):
165         return _findop(-1, name)[0]
166
167     @staticmethod
168     def getcridname(crid):
169         return _findop(crid, '')[1]
170
171     def __init__(self, cipher=0, key=None, mac=0, mackey=None,
172         crid=CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE, maclen=None):
173         self._ses = None
174         self._maclen = maclen
175         ses = SessionOp2()
176         ses.cipher = cipher
177         ses.mac = mac
178
179         if key is not None:
180             ses.keylen = len(key)
181             k = array.array('B', key)
182             ses.key = k.buffer_info()[0]
183         else:
184             self.key = None
185
186         if mackey is not None:
187             ses.mackeylen = len(mackey)
188             mk = array.array('B', mackey)
189             ses.mackey = mk.buffer_info()[0]
190
191         if not cipher and not mac:
192             raise ValueError('one of cipher or mac MUST be specified.')
193         ses.crid = crid
194         #print(ses)
195         s = array.array('B', ses.pack_hdr())
196         #print(s)
197         ioctl(_cryptodev, CIOCGSESSION2, s, 1)
198         ses.unpack(s)
199
200         self._ses = ses.ses
201
202     def __del__(self):
203         if self._ses is None:
204             return
205
206         try:
207             ioctl(_cryptodev, CIOCFSESSION, _pack('I', self._ses))
208         except TypeError:
209             pass
210         self._ses = None
211
212     def _doop(self, op, src, iv):
213         cop = CryptOp()
214         cop.ses = self._ses
215         cop.op = op
216         cop.flags = 0
217         cop.len = len(src)
218         s = array.array('B', src)
219         cop.src = cop.dst = s.buffer_info()[0]
220         if self._maclen is not None:
221             m = array.array('B', [0] * self._maclen)
222             cop.mac = m.buffer_info()[0]
223         ivbuf = array.array('B', str_to_ascii(iv))
224         cop.iv = ivbuf.buffer_info()[0]
225
226         #print('cop:', cop)
227         ioctl(_cryptodev, CIOCCRYPT, bytes(cop))
228
229         s = array_tobytes(s)
230         if self._maclen is not None:
231             return s, array_tobytes(m)
232
233         return s
234
235     def _doaead(self, op, src, aad, iv, tag=None):
236         caead = CryptAEAD()
237         caead.ses = self._ses
238         caead.op = op
239         caead.flags = CRD_F_IV_EXPLICIT
240         caead.flags = 0
241         src = str_to_ascii(src)
242         caead.len = len(src)
243         s = array.array('B', src)
244         caead.src = caead.dst = s.buffer_info()[0]
245         aad = str_to_ascii(aad)
246         caead.aadlen = len(aad)
247         saad = array.array('B', aad)
248         caead.aad = saad.buffer_info()[0]
249
250         if self._maclen is None:
251             raise ValueError('must have a tag length')
252
253         tag = str_to_ascii(tag)
254         if tag is None:
255             tag = array.array('B', [0] * self._maclen)
256         else:
257             assert len(tag) == self._maclen, \
258                 '%d != %d' % (len(tag), self._maclen)
259             tag = array.array('B', tag)
260
261         caead.tag = tag.buffer_info()[0]
262
263         ivbuf = array.array('B', iv)
264         caead.ivlen = len(iv)
265         caead.iv = ivbuf.buffer_info()[0]
266
267         ioctl(_cryptodev, CIOCCRYPTAEAD, bytes(caead))
268
269         s = array_tobytes(s)
270
271         return s, array_tobytes(tag)
272
273     def perftest(self, op, size, timeo=3):
274         inp = array.array('B', (random.randint(0, 255) for x in range(size)))
275         inp = str_to_ascii(inp)
276         out = array.array('B', inp)
277
278         # prep ioctl
279         cop = CryptOp()
280         cop.ses = self._ses
281         cop.op = op
282         cop.flags = 0
283         cop.len = len(inp)
284         s = array.array('B', inp)
285         cop.src = s.buffer_info()[0]
286         cop.dst = out.buffer_info()[0]
287         if self._maclen is not None:
288             m = array.array('B', [0] * self._maclen)
289             cop.mac = m.buffer_info()[0]
290         ivbuf = array.array('B', (random.randint(0, 255) for x in range(16)))
291         cop.iv = ivbuf.buffer_info()[0]
292
293         exit = [ False ]
294         def alarmhandle(a, b, exit=exit):
295             exit[0] = True
296
297         oldalarm = signal.signal(signal.SIGALRM, alarmhandle)
298         signal.alarm(timeo)
299
300         start = time.time()
301         reps = 0
302         cop = bytes(cop)
303         while not exit[0]:
304             ioctl(_cryptodev, CIOCCRYPT, cop)
305             reps += 1
306
307         end = time.time()
308
309         signal.signal(signal.SIGALRM, oldalarm)
310
311         print('time:', end - start)
312         print('perf MB/sec:', (reps * size) / (end - start) / 1024 / 1024)
313
314     def encrypt(self, data, iv, aad=None):
315         if aad is None:
316             return self._doop(COP_ENCRYPT, data, iv)
317         else:
318             return self._doaead(COP_ENCRYPT, data, aad,
319                 iv)
320
321     def decrypt(self, data, iv, aad=None, tag=None):
322         if aad is None:
323             return self._doop(COP_DECRYPT, data, iv)
324         else:
325             return self._doaead(COP_DECRYPT, data, aad,
326                 iv, tag=tag)
327
328 class MismatchError(Exception):
329     pass
330
331 class KATParser:
332     def __init__(self, fname, fields):
333         self.fields = set(fields)
334         self._pending = None
335         self.fname = fname
336         self.fp = None
337
338     def __enter__(self):
339         self.fp = open(self.fname)
340         return self
341
342     def __exit__(self, exc_type, exc_value, exc_tb):
343         if self.fp is not None:
344             self.fp.close()
345
346     def __iter__(self):
347         return self
348
349     def __next__(self):
350         while True:
351             didread = False
352             if self._pending is not None:
353                 i = self._pending
354                 self._pending = None
355             else:
356                 i = self.fp.readline()
357                 didread = True
358
359             if didread and not i:
360                 return
361
362             if not i.startswith('#') and i.strip():
363                 break
364
365         if i[0] == '[':
366             yield i[1:].split(']', 1)[0], self.fielditer()
367         else:
368             raise ValueError('unknown line: %r' % repr(i))
369
370     def eatblanks(self):
371         while True:
372             line = self.fp.readline()
373             if line == '':
374                 break
375
376             line = line.strip()
377             if line:
378                 break
379
380         return line
381
382     def fielditer(self):
383         while True:
384             values = {}
385
386             line = self.eatblanks()
387             if not line or line[0] == '[':
388                 self._pending = line
389                 return
390
391             while True:
392                 try:
393                     f, v = line.split(' =')
394                 except:
395                     if line == 'FAIL':
396                         f, v = 'FAIL', ''
397                     else:
398                         print('line:', repr(line))
399                         raise
400                 v = v.strip()
401
402                 if f in values:
403                     raise ValueError('already present: %r' % repr(f))
404                 values[f] = v
405                 line = self.fp.readline().strip()
406                 if not line:
407                     break
408
409             # we should have everything
410             remain = self.fields.copy() - set(values.keys())
411             # XXX - special case GCM decrypt
412             if remain and not ('FAIL' in values and 'PT' in remain):
413                 raise ValueError('not all fields found: %r' % repr(remain))
414
415             yield values
416
417 # The CCM files use a bit of a different syntax that doesn't quite fit
418 # the generic KATParser.  In particular, some keys are set globally at
419 # the start of the file, and some are set globally at the start of a
420 # section.
421 class KATCCMParser:
422     def __init__(self, fname):
423         self._pending = None
424         self.fname = fname
425         self.fp = None
426
427     def __enter__(self):
428         self.fp = open(self.fname)
429         self.read_globals()
430         return self
431
432     def __exit__(self, exc_type, exc_value, exc_tb):
433         if self.fp is not None:
434             self.fp.close()
435
436     def read_globals(self):
437         self.global_values = {}
438         while True:
439             line = self.fp.readline()
440             if not line:
441                 return
442             if line[0] == '#' or not line.strip():
443                 continue
444             if line[0] == '[':
445                 self._pending = line
446                 return
447
448             try:
449                 f, v = line.split(' =')
450             except:
451                 print('line:', repr(line))
452                 raise
453
454             v = v.strip()
455
456             if f in self.global_values:
457                 raise ValueError('already present: %r' % repr(f))
458             self.global_values[f] = v
459
460     def read_section_values(self, kwpairs):
461         self.section_values = self.global_values.copy()
462         for pair in kwpairs.split(', '):
463             f, v = pair.split(' = ')
464             if f in self.section_values:
465                 raise ValueError('already present: %r' % repr(f))
466             self.section_values[f] = v
467
468         while True:
469             line = self.fp.readline()
470             if not line:
471                 return
472             if line[0] == '#' or not line.strip():
473                 continue
474             if line[0] == '[':
475                 self._pending = line
476                 return
477
478             try:
479                 f, v = line.split(' =')
480             except:
481                 print('line:', repr(line))
482                 raise
483
484             if f == 'Count':
485                 self._pending = line
486                 return
487
488             v = v.strip()
489
490             if f in self.section_values:
491                 raise ValueError('already present: %r' % repr(f))
492             self.section_values[f] = v
493
494     def __iter__(self):
495         return self
496
497     def __next__(self):
498         while True:
499             if self._pending:
500                 line = self._pending
501                 self._pending = None
502             else:
503                 line = self.fp.readline()
504                 if not line:
505                     return
506
507             if (line and line[0] == '#') or not line.strip():
508                 continue
509
510             if line[0] == '[':
511                 section = line[1:].split(']', 1)[0]
512                 self.read_section_values(section)
513                 continue
514
515             values = self.section_values.copy()
516
517             while True:
518                 try:
519                     f, v = line.split(' =')
520                 except:
521                     print('line:', repr(line))
522                     raise
523                 v = v.strip()
524
525                 if f in values:
526                     raise ValueError('already present: %r' % repr(f))
527                 values[f] = v
528                 line = self.fp.readline().strip()
529                 if not line:
530                     break
531
532             yield values
533
534 def _spdechex(s):
535     return binascii.hexlify(''.join(s.split()))
536
537 if sys.version_info[0] < 3:
538     KATCCMParser.next = KATCCMParser.__next__
539     KATParser.next = KATParser.__next__
540
541 if __name__ == '__main__':
542     if True:
543         try:
544             crid = Crypto.findcrid('aesni0')
545             print('aesni:', crid)
546         except IOError:
547             print('aesni0 not found')
548
549         for i in range(10):
550             try:
551                 name = Crypto.getcridname(i)
552                 print('%2d: %r' % (i, repr(name)))
553             except IOError:
554                 pass
555     elif False:
556         columns = [ 'COUNT', 'DataUnitLen', 'Key', 'DataUnitSeqNumber', 'PT', 'CT' ]
557         fname = '/usr/home/jmg/aesni.testing/format tweak value input - data unit seq no/XTSGenAES128.rsp'
558         with KATParser(fname, columns) as kp:
559             for mode, ni in kp:
560                 print(i, ni)
561                 for j in ni:
562                     print(j)
563     elif False:
564         key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
565         iv = _spdechex('00000000000000000000000000000001')
566         pt = _spdechex('ab3cabed693a32946055524052afe3c9cb49664f09fc8b7da824d924006b7496353b8c1657c5dec564d8f38d7432e1de35aae9d95590e66278d4acce883e51abaf94977fcd3679660109a92bf7b2973ccd547f065ec6cee4cb4a72a5e9f45e615d920d76cb34cba482467b3e21422a7242e7d931330c0fbf465c3a3a46fae943029fd899626dda542750a1eee253df323c6ef1573f1c8c156613e2ea0a6cdbf2ae9701020be2d6a83ecb7f3f9d8e')
567         #pt = _spdechex('00000000000000000000000000000000')
568         ct = _spdechex('f42c33853ecc5ce2949865fdb83de3bff1089e9360c94f830baebfaff72836ab5236f77212f1e7396c8c54ac73d81986375a6e9e299cfeca5ba051ed25e8d1affa5beaf6c1d2b45e90802408f2ced21663497e906de5f29341e5e52ddfea5363d628b3eb7806835e17bae051b3a6da3f8e2941fe44384eac17a9d298d2c331ca8320c775b5d53263a5e905059d891b21dede2d8110fd427c7bd5a9a274ddb47b1945ee79522203b6e297d0e399ef')
569
570         c = Crypto(CRYPTO_AES_ICM, key)
571         enc = c.encrypt(pt, iv)
572
573         print('enc:', binascii.hexlify(enc))
574         print(' ct:', binascii.hexlify(ct))
575
576         assert ct == enc
577
578         dec = c.decrypt(ct, iv)
579
580         print('dec:', binascii.hexlify(dec))
581         print(' pt:', binascii.hexlify(pt))
582
583         assert pt == dec
584     elif False:
585         key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
586         iv = _spdechex('00000000000000000000000000000001')
587         pt = _spdechex('ab3cabed693a32946055524052afe3c9cb49664f09fc8b7da824d924006b7496353b8c1657c5dec564d8f38d7432e1de35aae9d95590e66278d4acce883e51abaf94977fcd3679660109a92bf7b2973ccd547f065ec6cee4cb4a72a5e9f45e615d920d76cb34cba482467b3e21422a7242e7d931330c0fbf465c3a3a46fae943029fd899626dda542750a1eee253df323c6ef1573f1c8c156613e2ea0a6cdbf2ae9701020be2d6a83ecb7f3f9d8e0a3f')
588         #pt = _spdechex('00000000000000000000000000000000')
589         ct = _spdechex('f42c33853ecc5ce2949865fdb83de3bff1089e9360c94f830baebfaff72836ab5236f77212f1e7396c8c54ac73d81986375a6e9e299cfeca5ba051ed25e8d1affa5beaf6c1d2b45e90802408f2ced21663497e906de5f29341e5e52ddfea5363d628b3eb7806835e17bae051b3a6da3f8e2941fe44384eac17a9d298d2c331ca8320c775b5d53263a5e905059d891b21dede2d8110fd427c7bd5a9a274ddb47b1945ee79522203b6e297d0e399ef3768')
590
591         c = Crypto(CRYPTO_AES_ICM, key)
592         enc = c.encrypt(pt, iv)
593
594         print('enc:', binascii.hexlify(enc))
595         print(' ct:', binascii.hexlify(ct))
596
597         assert ct == enc
598
599         dec = c.decrypt(ct, iv)
600
601         print('dec:', binascii.hexlify(dec))
602         print(' pt:', binascii.hexlify(pt))
603
604         assert pt == dec
605     elif False:
606         key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
607         iv = _spdechex('6eba2716ec0bd6fa5cdef5e6d3a795bc')
608         pt = _spdechex('ab3cabed693a32946055524052afe3c9cb49664f09fc8b7da824d924006b7496353b8c1657c5dec564d8f38d7432e1de35aae9d95590e66278d4acce883e51abaf94977fcd3679660109a92bf7b2973ccd547f065ec6cee4cb4a72a5e9f45e615d920d76cb34cba482467b3e21422a7242e7d931330c0fbf465c3a3a46fae943029fd899626dda542750a1eee253df323c6ef1573f1c8c156613e2ea0a6cdbf2ae9701020be2d6a83ecb7f3f9d8e0a3f')
609         ct = _spdechex('f1f81f12e72e992dbdc304032705dc75dc3e4180eff8ee4819906af6aee876d5b00b7c36d282a445ce3620327be481e8e53a8e5a8e5ca9abfeb2281be88d12ffa8f46d958d8224738c1f7eea48bda03edbf9adeb900985f4fa25648b406d13a886c25e70cfdecdde0ad0f2991420eb48a61c64fd797237cf2798c2675b9bb744360b0a3f329ac53bbceb4e3e7456e6514f1a9d2f06c236c31d0f080b79c15dce1096357416602520daa098b17d1af427')
610         c = Crypto(CRYPTO_AES_CBC, key)
611
612         enc = c.encrypt(pt, iv)
613
614         print('enc:', binascii.hexlify(enc))
615         print(' ct:', binascii.hexlify(ct))
616
617         assert ct == enc
618
619         dec = c.decrypt(ct, iv)
620
621         print('dec:', binascii.hexlify(dec))
622         print(' pt:', binascii.hexlify(pt))
623
624         assert pt == dec
625     elif False:
626         key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
627         iv = _spdechex('b3d8cc017cbb89b39e0f67e2')
628         pt = _spdechex('c3b3c41f113a31b73d9a5cd4321030')
629         aad = _spdechex('24825602bd12a984e0092d3e448eda5f')
630         ct = _spdechex('93fe7d9e9bfd10348a5606e5cafa7354')
631         ct = _spdechex('93fe7d9e9bfd10348a5606e5cafa73')
632         tag = _spdechex('0032a1dc85f1c9786925a2e71d8272dd')
633         tag = _spdechex('8d11a0929cb3fbe1fef01a4a38d5f8ea')
634
635         c = Crypto(CRYPTO_AES_NIST_GCM_16, key)
636
637         enc, enctag = c.encrypt(pt, iv, aad=aad)
638
639         print('enc:', binascii.hexlify(enc))
640         print(' ct:', binascii.hexlify(ct))
641
642         assert enc == ct
643
644         print('etg:', binascii.hexlify(enctag))
645         print('tag:', binascii.hexlify(tag))
646         assert enctag == tag
647
648         # Make sure we get EBADMSG
649         #enctag = enctag[:-1] + 'a'
650         dec, dectag = c.decrypt(ct, iv, aad=aad, tag=enctag)
651
652         print('dec:', binascii.hexlify(dec))
653         print(' pt:', binascii.hexlify(pt))
654
655         assert dec == pt
656
657         print('dtg:', binascii.hexlify(dectag))
658         print('tag:', binascii.hexlify(tag))
659
660         assert dectag == tag
661     elif False:
662         key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
663         iv = _spdechex('b3d8cc017cbb89b39e0f67e2')
664         key = key + iv[:4]
665         iv = iv[4:]
666         pt = _spdechex('c3b3c41f113a31b73d9a5cd432103069')
667         aad = _spdechex('24825602bd12a984e0092d3e448eda5f')
668         ct = _spdechex('93fe7d9e9bfd10348a5606e5cafa7354')
669         tag = _spdechex('0032a1dc85f1c9786925a2e71d8272dd')
670
671         c = Crypto(CRYPTO_AES_GCM_16, key)
672
673         enc, enctag = c.encrypt(pt, iv, aad=aad)
674
675         print('enc:', binascii.hexlify(enc))
676         print(' ct:', binascii.hexlify(ct))
677
678         assert enc == ct
679
680         print('etg:', binascii.hexlify(enctag))
681         print('tag:', binascii.hexlify(tag))
682         assert enctag == tag
683     elif False:
684         for i in range(100000):
685             c = Crypto(CRYPTO_AES_XTS, binascii.unhexlify('1bbfeadf539daedcae33ced497343f3ca1f2474ad932b903997d44707db41382'))
686             data = binascii.unhexlify('52a42bca4e9425a25bbc8c8bf6129dec')
687             ct = binascii.unhexlify('517e602becd066b65fa4f4f56ddfe240')
688             iv = _pack('QQ', 71, 0)
689
690             enc = c.encrypt(data, iv)
691             assert enc == ct
692     elif True:
693         c = Crypto(CRYPTO_AES_XTS, binascii.unhexlify('1bbfeadf539daedcae33ced497343f3ca1f2474ad932b903997d44707db41382'))
694         data = binascii.unhexlify('52a42bca4e9425a25bbc8c8bf6129dec')
695         ct = binascii.unhexlify('517e602becd066b65fa4f4f56ddfe240')
696         iv = _pack('QQ', 71, 0)
697
698         enc = c.encrypt(data, iv)
699         assert enc == ct
700
701         dec = c.decrypt(enc, iv)
702         assert dec == data
703
704         #c.perftest(COP_ENCRYPT, 192*1024, reps=30000)
705
706     else:
707         key = binascii.unhexlify('1bbfeadf539daedcae33ced497343f3ca1f2474ad932b903997d44707db41382')
708         print('XTS %d testing:' % (len(key) * 8))
709         c = Crypto(CRYPTO_AES_XTS, key)
710         for i in [ 8192, 192*1024]:
711             print('block size: %d' % i)
712             c.perftest(COP_ENCRYPT, i)
713             c.perftest(COP_DECRYPT, i)