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