xref: /freebsd/tests/sys/opencrypto/cryptodev.py (revision f6d7fcda2762f9593dfd2f8547a98fe696808a1d)
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
33from __future__ import print_function
34import array
35import binascii
36from fcntl import ioctl
37import os
38import random
39import signal
40from struct import pack as _pack
41import sys
42import time
43
44import dpkt
45
46from cryptodevh import *
47
48__all__ = [ 'Crypto', 'MismatchError', ]
49
50class FindOp(dpkt.Packet):
51    __byte_order__ = '@'
52    __hdr__ = (
53        ('crid', 'i',   0),
54        ('name', '32s', 0),
55    )
56
57class 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
69class 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
86class 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
99class 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
116CRIOGET = 3221513060
117CIOCGSESSION = 3224396645
118CIOCGSESSION2 = 3225445226
119CIOCFSESSION = 2147771238
120CIOCCRYPT = 3224396647
121CIOCKEY = 3230688104
122CIOCASYMFEAT = 1074029417
123CIOCKEY2 = 3230688107
124CIOCFINDDEV = 3223610220
125CIOCCRYPTAEAD = 3225445229
126
127def _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
139def _findop(crid, name):
140    fop = FindOp()
141    fop.crid = crid
142    fop.name = name
143    s = array.array('B', fop.pack_hdr())
144    ioctl(_cryptodev, CIOCFINDDEV, s, 1)
145    fop.unpack(s)
146
147    try:
148        idx = fop.name.index('\x00')
149        name = fop.name[:idx]
150    except ValueError:
151        name = fop.name
152
153    return fop.crid, name
154
155def array_tobytes(array_obj):
156    if sys.version_info[:2] >= (3, 2):
157        return array_obj.tobytes()
158    return array_obj.tostring()
159
160class Crypto:
161    @staticmethod
162    def findcrid(name):
163        return _findop(-1, name)[0]
164
165    @staticmethod
166    def getcridname(crid):
167        return _findop(crid, '')[1]
168
169    def __init__(self, cipher=0, key=None, mac=0, mackey=None,
170        crid=CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE, maclen=None):
171        self._ses = None
172        self._maclen = maclen
173        ses = SessionOp2()
174        ses.cipher = cipher
175        ses.mac = mac
176
177        if key is not None:
178            ses.keylen = len(key)
179            k = array.array('B', key)
180            ses.key = k.buffer_info()[0]
181        else:
182            self.key = None
183
184        if mackey is not None:
185            ses.mackeylen = len(mackey)
186            mk = array.array('B', mackey)
187            ses.mackey = mk.buffer_info()[0]
188
189        if not cipher and not mac:
190            raise ValueError('one of cipher or mac MUST be specified.')
191        ses.crid = crid
192        #print(ses)
193        s = array.array('B', ses.pack_hdr())
194        #print(s)
195        ioctl(_cryptodev, CIOCGSESSION2, s, 1)
196        ses.unpack(s)
197
198        self._ses = ses.ses
199
200    def __del__(self):
201        if self._ses is None:
202            return
203
204        try:
205            ioctl(_cryptodev, CIOCFSESSION, _pack('I', self._ses))
206        except TypeError:
207            pass
208        self._ses = None
209
210    def _doop(self, op, src, iv):
211        cop = CryptOp()
212        cop.ses = self._ses
213        cop.op = op
214        cop.flags = 0
215        cop.len = len(src)
216        s = array.array('B', src)
217        cop.src = cop.dst = s.buffer_info()[0]
218        if self._maclen is not None:
219            m = array.array('B', [0] * self._maclen)
220            cop.mac = m.buffer_info()[0]
221        ivbuf = array.array('B', iv)
222        cop.iv = ivbuf.buffer_info()[0]
223
224        #print('cop:', cop)
225        ioctl(_cryptodev, CIOCCRYPT, str(cop))
226
227        s = array_tobytes(s)
228        if self._maclen is not None:
229            return s, array_tobytes(m)
230
231        return s
232
233    def _doaead(self, op, src, aad, iv, tag=None):
234        caead = CryptAEAD()
235        caead.ses = self._ses
236        caead.op = op
237        caead.flags = CRD_F_IV_EXPLICIT
238        caead.flags = 0
239        caead.len = len(src)
240        s = array.array('B', src)
241        caead.src = caead.dst = s.buffer_info()[0]
242        caead.aadlen = len(aad)
243        saad = array.array('B', aad)
244        caead.aad = saad.buffer_info()[0]
245
246        if self._maclen is None:
247            raise ValueError('must have a tag length')
248
249        if tag is None:
250            tag = array.array('B', [0] * self._maclen)
251        else:
252            assert len(tag) == self._maclen, \
253                '%d != %d' % (len(tag), self._maclen)
254            tag = array.array('B', tag)
255
256        caead.tag = tag.buffer_info()[0]
257
258        ivbuf = array.array('B', iv)
259        caead.ivlen = len(iv)
260        caead.iv = ivbuf.buffer_info()[0]
261
262        ioctl(_cryptodev, CIOCCRYPTAEAD, str(caead))
263
264        s = array_tobytes(s)
265
266        return s, array_tobytes(tag)
267
268    def perftest(self, op, size, timeo=3):
269        inp = array.array('B', (random.randint(0, 255) for x in range(size)))
270        out = array.array('B', inp)
271
272        # prep ioctl
273        cop = CryptOp()
274        cop.ses = self._ses
275        cop.op = op
276        cop.flags = 0
277        cop.len = len(inp)
278        s = array.array('B', inp)
279        cop.src = s.buffer_info()[0]
280        cop.dst = out.buffer_info()[0]
281        if self._maclen is not None:
282            m = array.array('B', [0] * self._maclen)
283            cop.mac = m.buffer_info()[0]
284        ivbuf = array.array('B', (random.randint(0, 255) for x in range(16)))
285        cop.iv = ivbuf.buffer_info()[0]
286
287        exit = [ False ]
288        def alarmhandle(a, b, exit=exit):
289            exit[0] = True
290
291        oldalarm = signal.signal(signal.SIGALRM, alarmhandle)
292        signal.alarm(timeo)
293
294        start = time.time()
295        reps = 0
296        while not exit[0]:
297            ioctl(_cryptodev, CIOCCRYPT, str(cop))
298            reps += 1
299
300        end = time.time()
301
302        signal.signal(signal.SIGALRM, oldalarm)
303
304        print('time:', end - start)
305        print('perf MB/sec:', (reps * size) / (end - start) / 1024 / 1024)
306
307    def encrypt(self, data, iv, aad=None):
308        if aad is None:
309            return self._doop(COP_ENCRYPT, data, iv)
310        else:
311            return self._doaead(COP_ENCRYPT, data, aad,
312                iv)
313
314    def decrypt(self, data, iv, aad=None, tag=None):
315        if aad is None:
316            return self._doop(COP_DECRYPT, data, iv)
317        else:
318            return self._doaead(COP_DECRYPT, data, aad,
319                iv, tag=tag)
320
321class MismatchError(Exception):
322    pass
323
324class KATParser:
325    def __init__(self, fname, fields):
326        self.fields = set(fields)
327        self._pending = None
328        self.fname = fname
329        self.fp = None
330
331    def __enter__(self):
332        self.fp = open(self.fname)
333        return self
334
335    def __exit__(self, exc_type, exc_value, exc_tb):
336        if self.fp is not None:
337            self.fp.close()
338
339    def __iter__(self):
340        return self
341
342    def __next__(self):
343        while True:
344            didread = False
345            if self._pending is not None:
346                i = self._pending
347                self._pending = None
348            else:
349                i = self.fp.readline()
350                didread = True
351
352            if didread and not i:
353                return
354
355            if not i.startswith('#') and i.strip():
356                break
357
358        if i[0] == '[':
359            yield i[1:].split(']', 1)[0], self.fielditer()
360        else:
361            raise ValueError('unknown line: %r' % repr(i))
362
363    def eatblanks(self):
364        while True:
365            line = self.fp.readline()
366            if line == '':
367                break
368
369            line = line.strip()
370            if line:
371                break
372
373        return line
374
375    def fielditer(self):
376        while True:
377            values = {}
378
379            line = self.eatblanks()
380            if not line or line[0] == '[':
381                self._pending = line
382                return
383
384            while True:
385                try:
386                    f, v = line.split(' =')
387                except:
388                    if line == 'FAIL':
389                        f, v = 'FAIL', ''
390                    else:
391                        print('line:', repr(line))
392                        raise
393                v = v.strip()
394
395                if f in values:
396                    raise ValueError('already present: %r' % repr(f))
397                values[f] = v
398                line = self.fp.readline().strip()
399                if not line:
400                    break
401
402            # we should have everything
403            remain = self.fields.copy() - set(values.keys())
404            # XXX - special case GCM decrypt
405            if remain and not ('FAIL' in values and 'PT' in remain):
406                raise ValueError('not all fields found: %r' % repr(remain))
407
408            yield values
409
410# The CCM files use a bit of a different syntax that doesn't quite fit
411# the generic KATParser.  In particular, some keys are set globally at
412# the start of the file, and some are set globally at the start of a
413# section.
414class KATCCMParser:
415    def __init__(self, fname):
416        self._pending = None
417        self.fname = fname
418        self.fp = None
419
420    def __enter__(self):
421        self.fp = open(self.fname)
422        self.read_globals()
423        return self
424
425    def __exit__(self, exc_type, exc_value, exc_tb):
426        if self.fp is not None:
427            self.fp.close()
428
429    def read_globals(self):
430        self.global_values = {}
431        while True:
432            line = self.fp.readline()
433            if not line:
434                return
435            if line[0] == '#' or not line.strip():
436                continue
437            if line[0] == '[':
438                self._pending = line
439                return
440
441            try:
442                f, v = line.split(' =')
443            except:
444                print('line:', repr(line))
445                raise
446
447            v = v.strip()
448
449            if f in self.global_values:
450                raise ValueError('already present: %r' % repr(f))
451            self.global_values[f] = v
452
453    def read_section_values(self, kwpairs):
454        self.section_values = self.global_values.copy()
455        for pair in kwpairs.split(', '):
456            f, v = pair.split(' = ')
457            if f in self.section_values:
458                raise ValueError('already present: %r' % repr(f))
459            self.section_values[f] = v
460
461        while True:
462            line = self.fp.readline()
463            if not line:
464                return
465            if line[0] == '#' or not line.strip():
466                continue
467            if line[0] == '[':
468                self._pending = line
469                return
470
471            try:
472                f, v = line.split(' =')
473            except:
474                print('line:', repr(line))
475                raise
476
477            if f == 'Count':
478                self._pending = line
479                return
480
481            v = v.strip()
482
483            if f in self.section_values:
484                raise ValueError('already present: %r' % repr(f))
485            self.section_values[f] = v
486
487    def __iter__(self):
488        return self
489
490    def __next__(self):
491        while True:
492            if self._pending:
493                line = self._pending
494                self._pending = None
495            else:
496                line = self.fp.readline()
497                if not line:
498                    return
499
500            if (line and line[0] == '#') or not line.strip():
501                continue
502
503            if line[0] == '[':
504                section = line[1:].split(']', 1)[0]
505                self.read_section_values(section)
506                continue
507
508            values = self.section_values.copy()
509
510            while True:
511                try:
512                    f, v = line.split(' =')
513                except:
514                    print('line:', repr(line))
515                    raise
516                v = v.strip()
517
518                if f in values:
519                    raise ValueError('already present: %r' % repr(f))
520                values[f] = v
521                line = self.fp.readline().strip()
522                if not line:
523                    break
524
525            yield values
526
527def _spdechex(s):
528    return binascii.hexlify(''.join(s.split()))
529
530if sys.version_info[0] < 3:
531    KATCCMParser.next = KATCCMParser.__next__
532    KATParser.next = KATParser.__next__
533
534if __name__ == '__main__':
535    if True:
536        try:
537            crid = Crypto.findcrid('aesni0')
538            print('aesni:', crid)
539        except IOError:
540            print('aesni0 not found')
541
542        for i in range(10):
543            try:
544                name = Crypto.getcridname(i)
545                print('%2d: %r' % (i, repr(name)))
546            except IOError:
547                pass
548    elif False:
549        columns = [ 'COUNT', 'DataUnitLen', 'Key', 'DataUnitSeqNumber', 'PT', 'CT' ]
550        fname = '/usr/home/jmg/aesni.testing/format tweak value input - data unit seq no/XTSGenAES128.rsp'
551        with KATParser(fname, columns) as kp:
552            for mode, ni in kp:
553                print(i, ni)
554                for j in ni:
555                    print(j)
556    elif False:
557        key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
558        iv = _spdechex('00000000000000000000000000000001')
559        pt = _spdechex('ab3cabed693a32946055524052afe3c9cb49664f09fc8b7da824d924006b7496353b8c1657c5dec564d8f38d7432e1de35aae9d95590e66278d4acce883e51abaf94977fcd3679660109a92bf7b2973ccd547f065ec6cee4cb4a72a5e9f45e615d920d76cb34cba482467b3e21422a7242e7d931330c0fbf465c3a3a46fae943029fd899626dda542750a1eee253df323c6ef1573f1c8c156613e2ea0a6cdbf2ae9701020be2d6a83ecb7f3f9d8e')
560        #pt = _spdechex('00000000000000000000000000000000')
561        ct = _spdechex('f42c33853ecc5ce2949865fdb83de3bff1089e9360c94f830baebfaff72836ab5236f77212f1e7396c8c54ac73d81986375a6e9e299cfeca5ba051ed25e8d1affa5beaf6c1d2b45e90802408f2ced21663497e906de5f29341e5e52ddfea5363d628b3eb7806835e17bae051b3a6da3f8e2941fe44384eac17a9d298d2c331ca8320c775b5d53263a5e905059d891b21dede2d8110fd427c7bd5a9a274ddb47b1945ee79522203b6e297d0e399ef')
562
563        c = Crypto(CRYPTO_AES_ICM, key)
564        enc = c.encrypt(pt, iv)
565
566        print('enc:', binascii.hexlify(enc))
567        print(' ct:', binascii.hexlify(ct))
568
569        assert ct == enc
570
571        dec = c.decrypt(ct, iv)
572
573        print('dec:', binascii.hexlify(dec))
574        print(' pt:', binascii.hexlify(pt))
575
576        assert pt == dec
577    elif False:
578        key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
579        iv = _spdechex('00000000000000000000000000000001')
580        pt = _spdechex('ab3cabed693a32946055524052afe3c9cb49664f09fc8b7da824d924006b7496353b8c1657c5dec564d8f38d7432e1de35aae9d95590e66278d4acce883e51abaf94977fcd3679660109a92bf7b2973ccd547f065ec6cee4cb4a72a5e9f45e615d920d76cb34cba482467b3e21422a7242e7d931330c0fbf465c3a3a46fae943029fd899626dda542750a1eee253df323c6ef1573f1c8c156613e2ea0a6cdbf2ae9701020be2d6a83ecb7f3f9d8e0a3f')
581        #pt = _spdechex('00000000000000000000000000000000')
582        ct = _spdechex('f42c33853ecc5ce2949865fdb83de3bff1089e9360c94f830baebfaff72836ab5236f77212f1e7396c8c54ac73d81986375a6e9e299cfeca5ba051ed25e8d1affa5beaf6c1d2b45e90802408f2ced21663497e906de5f29341e5e52ddfea5363d628b3eb7806835e17bae051b3a6da3f8e2941fe44384eac17a9d298d2c331ca8320c775b5d53263a5e905059d891b21dede2d8110fd427c7bd5a9a274ddb47b1945ee79522203b6e297d0e399ef3768')
583
584        c = Crypto(CRYPTO_AES_ICM, key)
585        enc = c.encrypt(pt, iv)
586
587        print('enc:', binascii.hexlify(enc))
588        print(' ct:', binascii.hexlify(ct))
589
590        assert ct == enc
591
592        dec = c.decrypt(ct, iv)
593
594        print('dec:', binascii.hexlify(dec))
595        print(' pt:', binascii.hexlify(pt))
596
597        assert pt == dec
598    elif False:
599        key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
600        iv = _spdechex('6eba2716ec0bd6fa5cdef5e6d3a795bc')
601        pt = _spdechex('ab3cabed693a32946055524052afe3c9cb49664f09fc8b7da824d924006b7496353b8c1657c5dec564d8f38d7432e1de35aae9d95590e66278d4acce883e51abaf94977fcd3679660109a92bf7b2973ccd547f065ec6cee4cb4a72a5e9f45e615d920d76cb34cba482467b3e21422a7242e7d931330c0fbf465c3a3a46fae943029fd899626dda542750a1eee253df323c6ef1573f1c8c156613e2ea0a6cdbf2ae9701020be2d6a83ecb7f3f9d8e0a3f')
602        ct = _spdechex('f1f81f12e72e992dbdc304032705dc75dc3e4180eff8ee4819906af6aee876d5b00b7c36d282a445ce3620327be481e8e53a8e5a8e5ca9abfeb2281be88d12ffa8f46d958d8224738c1f7eea48bda03edbf9adeb900985f4fa25648b406d13a886c25e70cfdecdde0ad0f2991420eb48a61c64fd797237cf2798c2675b9bb744360b0a3f329ac53bbceb4e3e7456e6514f1a9d2f06c236c31d0f080b79c15dce1096357416602520daa098b17d1af427')
603        c = Crypto(CRYPTO_AES_CBC, key)
604
605        enc = c.encrypt(pt, iv)
606
607        print('enc:', binascii.hexlify(enc))
608        print(' ct:', binascii.hexlify(ct))
609
610        assert ct == enc
611
612        dec = c.decrypt(ct, iv)
613
614        print('dec:', binascii.hexlify(dec))
615        print(' pt:', binascii.hexlify(pt))
616
617        assert pt == dec
618    elif False:
619        key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
620        iv = _spdechex('b3d8cc017cbb89b39e0f67e2')
621        pt = _spdechex('c3b3c41f113a31b73d9a5cd4321030')
622        aad = _spdechex('24825602bd12a984e0092d3e448eda5f')
623        ct = _spdechex('93fe7d9e9bfd10348a5606e5cafa7354')
624        ct = _spdechex('93fe7d9e9bfd10348a5606e5cafa73')
625        tag = _spdechex('0032a1dc85f1c9786925a2e71d8272dd')
626        tag = _spdechex('8d11a0929cb3fbe1fef01a4a38d5f8ea')
627
628        c = Crypto(CRYPTO_AES_NIST_GCM_16, key,
629            mac=CRYPTO_AES_128_NIST_GMAC, mackey=key)
630
631        enc, enctag = c.encrypt(pt, iv, aad=aad)
632
633        print('enc:', binascii.hexlify(enc))
634        print(' ct:', binascii.hexlify(ct))
635
636        assert enc == ct
637
638        print('etg:', binascii.hexlify(enctag))
639        print('tag:', binascii.hexlify(tag))
640        assert enctag == tag
641
642        # Make sure we get EBADMSG
643        #enctag = enctag[:-1] + 'a'
644        dec, dectag = c.decrypt(ct, iv, aad=aad, tag=enctag)
645
646        print('dec:', binascii.hexlify(dec))
647        print(' pt:', binascii.hexlify(pt))
648
649        assert dec == pt
650
651        print('dtg:', binascii.hexlify(dectag))
652        print('tag:', binascii.hexlify(tag))
653
654        assert dectag == tag
655    elif False:
656        key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
657        iv = _spdechex('b3d8cc017cbb89b39e0f67e2')
658        key = key + iv[:4]
659        iv = iv[4:]
660        pt = _spdechex('c3b3c41f113a31b73d9a5cd432103069')
661        aad = _spdechex('24825602bd12a984e0092d3e448eda5f')
662        ct = _spdechex('93fe7d9e9bfd10348a5606e5cafa7354')
663        tag = _spdechex('0032a1dc85f1c9786925a2e71d8272dd')
664
665        c = Crypto(CRYPTO_AES_GCM_16, key, mac=CRYPTO_AES_128_GMAC, mackey=key)
666
667        enc, enctag = c.encrypt(pt, iv, aad=aad)
668
669        print('enc:', binascii.hexlify(enc))
670        print(' ct:', binascii.hexlify(ct))
671
672        assert enc == ct
673
674        print('etg:', binascii.hexlify(enctag))
675        print('tag:', binascii.hexlify(tag))
676        assert enctag == tag
677    elif False:
678        for i in range(100000):
679            c = Crypto(CRYPTO_AES_XTS, binascii.unhexlify('1bbfeadf539daedcae33ced497343f3ca1f2474ad932b903997d44707db41382'))
680            data = binascii.unhexlify('52a42bca4e9425a25bbc8c8bf6129dec')
681            ct = binascii.unhexlify('517e602becd066b65fa4f4f56ddfe240')
682            iv = _pack('QQ', 71, 0)
683
684            enc = c.encrypt(data, iv)
685            assert enc == ct
686    elif True:
687        c = Crypto(CRYPTO_AES_XTS, binascii.unhexlify('1bbfeadf539daedcae33ced497343f3ca1f2474ad932b903997d44707db41382'))
688        data = binascii.unhexlify('52a42bca4e9425a25bbc8c8bf6129dec')
689        ct = binascii.unhexlify('517e602becd066b65fa4f4f56ddfe240')
690        iv = _pack('QQ', 71, 0)
691
692        enc = c.encrypt(data, iv)
693        assert enc == ct
694
695        dec = c.decrypt(enc, iv)
696        assert dec == data
697
698        #c.perftest(COP_ENCRYPT, 192*1024, reps=30000)
699
700    else:
701        key = binascii.unhexlify('1bbfeadf539daedcae33ced497343f3ca1f2474ad932b903997d44707db41382')
702        print('XTS %d testing:' % (len(key) * 8))
703        c = Crypto(CRYPTO_AES_XTS, key)
704        for i in [ 8192, 192*1024]:
705            print('block size: %d' % i)
706            c.perftest(COP_ENCRYPT, i)
707            c.perftest(COP_DECRYPT, i)
708