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