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