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