xref: /freebsd/tests/sys/opencrypto/cryptodev.py (revision d500a85e640d1cd270747c12e17c511b53864436)
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
35import array
36import binascii
37from fcntl import ioctl
38import os
39import platform
40import random
41import signal
42from struct import pack as _pack
43import sys
44import time
45
46import dpkt
47
48from cryptodevh import *
49
50__all__ = [ 'Crypto', 'MismatchError', ]
51
52class FindOp(dpkt.Packet):
53    __byte_order__ = '@'
54    __hdr__ = (
55        ('crid', 'i',   0),
56        ('name', '32s', 0),
57    )
58
59class 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
71class 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
88class 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
101class 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
118CIOCGSESSION = 3224396645
119CIOCFSESSION = 2147771238
120CIOCKEY = 3230688104
121CIOCASYMFEAT = 1074029417
122CIOCKEY2 = 3230688107
123CIOCFINDDEV = 3223610220
124if platform.architecture()[0] == '64bit':
125    CIOCGSESSION2 = 3225445226
126    CIOCCRYPT = 3224396647
127    CIOCCRYPTAEAD = 3225445229
128else:
129    CIOCGSESSION2 = 3224396650
130    CIOCCRYPT = 3223085927
131    CIOCCRYPTAEAD = 3223872365
132
133_cryptodev = os.open('/dev/crypto', os.O_RDWR)
134
135def 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
141def _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
157def array_tobytes(array_obj):
158    if sys.version_info[:2] >= (3, 2):
159        return array_obj.tobytes()
160    return array_obj.tostring()
161
162class 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
328class MismatchError(Exception):
329    pass
330
331class 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.
421class 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
534def _spdechex(s):
535    return binascii.hexlify(''.join(s.split()))
536
537if sys.version_info[0] < 3:
538    KATCCMParser.next = KATCCMParser.__next__
539    KATParser.next = KATParser.__next__
540
541if __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)
714