xref: /freebsd/tests/sys/opencrypto/cryptodev.py (revision 8881d206f4e68b564c2c5f50fc717086fc3e827a)
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        ('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 is not None and len(src) != 0:
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 is not None:
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
362    def __enter__(self):
363        self.fp = open(self.fname)
364        return self
365
366    def __exit__(self, exc_type, exc_value, exc_tb):
367        if self.fp is not None:
368            self.fp.close()
369
370    def __iter__(self):
371        return self
372
373    def __next__(self):
374        while True:
375            didread = False
376            if self._pending is not None:
377                i = self._pending
378                self._pending = None
379            else:
380                i = self.fp.readline()
381                didread = True
382
383            if didread and not i:
384                return
385
386            if not i.startswith('#') and i.strip():
387                break
388
389        if i[0] == '[':
390            yield i[1:].split(']', 1)[0], self.fielditer()
391        else:
392            raise ValueError('unknown line: %r' % repr(i))
393
394    def eatblanks(self):
395        while True:
396            line = self.fp.readline()
397            if line == '':
398                break
399
400            line = line.strip()
401            if line:
402                break
403
404        return line
405
406    def fielditer(self):
407        while True:
408            values = {}
409
410            line = self.eatblanks()
411            if not line or line[0] == '[':
412                self._pending = line
413                return
414
415            while True:
416                try:
417                    f, v = line.split(' =')
418                except:
419                    if line == 'FAIL':
420                        f, v = 'FAIL', ''
421                    else:
422                        print('line:', repr(line))
423                        raise
424                v = v.strip()
425
426                if f in values:
427                    raise ValueError('already present: %r' % repr(f))
428                values[f] = v
429                line = self.fp.readline().strip()
430                if not line:
431                    break
432
433            # we should have everything
434            remain = self.fields.copy() - set(values.keys())
435            # XXX - special case GCM decrypt
436            if remain and not ('FAIL' in values and 'PT' in remain):
437                raise ValueError('not all fields found: %r' % repr(remain))
438
439            yield values
440
441# The CCM files use a bit of a different syntax that doesn't quite fit
442# the generic KATParser.  In particular, some keys are set globally at
443# the start of the file, and some are set globally at the start of a
444# section.
445class KATCCMParser:
446    def __init__(self, fname):
447        self._pending = None
448        self.fname = fname
449        self.fp = None
450
451    def __enter__(self):
452        self.fp = open(self.fname)
453        self.read_globals()
454        return self
455
456    def __exit__(self, exc_type, exc_value, exc_tb):
457        if self.fp is not None:
458            self.fp.close()
459
460    def read_globals(self):
461        self.global_values = {}
462        while True:
463            line = self.fp.readline()
464            if not line:
465                return
466            if line[0] == '#' or not line.strip():
467                continue
468            if line[0] == '[':
469                self._pending = line
470                return
471
472            try:
473                f, v = line.split(' =')
474            except:
475                print('line:', repr(line))
476                raise
477
478            v = v.strip()
479
480            if f in self.global_values:
481                raise ValueError('already present: %r' % repr(f))
482            self.global_values[f] = v
483
484    def read_section_values(self, kwpairs):
485        self.section_values = self.global_values.copy()
486        for pair in kwpairs.split(', '):
487            f, v = pair.split(' = ')
488            if f in self.section_values:
489                raise ValueError('already present: %r' % repr(f))
490            self.section_values[f] = v
491
492        while True:
493            line = self.fp.readline()
494            if not line:
495                return
496            if line[0] == '#' or not line.strip():
497                continue
498            if line[0] == '[':
499                self._pending = line
500                return
501
502            try:
503                f, v = line.split(' =')
504            except:
505                print('line:', repr(line))
506                raise
507
508            if f == 'Count':
509                self._pending = line
510                return
511
512            v = v.strip()
513
514            if f in self.section_values:
515                raise ValueError('already present: %r' % repr(f))
516            self.section_values[f] = v
517
518    def __iter__(self):
519        return self
520
521    def __next__(self):
522        while True:
523            if self._pending:
524                line = self._pending
525                self._pending = None
526            else:
527                line = self.fp.readline()
528                if not line:
529                    return
530
531            if (line and line[0] == '#') or not line.strip():
532                continue
533
534            if line[0] == '[':
535                section = line[1:].split(']', 1)[0]
536                self.read_section_values(section)
537                continue
538
539            values = self.section_values.copy()
540
541            while True:
542                try:
543                    f, v = line.split(' =')
544                except:
545                    print('line:', repr(line))
546                    raise
547                v = v.strip()
548
549                if f in values:
550                    raise ValueError('already present: %r' % repr(f))
551                values[f] = v
552                line = self.fp.readline().strip()
553                if not line:
554                    break
555
556            yield values
557
558def _spdechex(s):
559    return binascii.hexlify(''.join(s.split()))
560
561if sys.version_info[0] < 3:
562    KATCCMParser.next = KATCCMParser.__next__
563    KATParser.next = KATParser.__next__
564
565if __name__ == '__main__':
566    if True:
567        try:
568            crid = Crypto.findcrid('aesni0')
569            print('aesni:', crid)
570        except IOError:
571            print('aesni0 not found')
572
573        for i in range(10):
574            try:
575                name = Crypto.getcridname(i)
576                print('%2d: %r' % (i, repr(name)))
577            except IOError:
578                pass
579    elif False:
580        columns = [ 'COUNT', 'DataUnitLen', 'Key', 'DataUnitSeqNumber', 'PT', 'CT' ]
581        fname = '/usr/home/jmg/aesni.testing/format tweak value input - data unit seq no/XTSGenAES128.rsp'
582        with KATParser(fname, columns) as kp:
583            for mode, ni in kp:
584                print(i, ni)
585                for j in ni:
586                    print(j)
587    elif False:
588        key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
589        iv = _spdechex('00000000000000000000000000000001')
590        pt = _spdechex('ab3cabed693a32946055524052afe3c9cb49664f09fc8b7da824d924006b7496353b8c1657c5dec564d8f38d7432e1de35aae9d95590e66278d4acce883e51abaf94977fcd3679660109a92bf7b2973ccd547f065ec6cee4cb4a72a5e9f45e615d920d76cb34cba482467b3e21422a7242e7d931330c0fbf465c3a3a46fae943029fd899626dda542750a1eee253df323c6ef1573f1c8c156613e2ea0a6cdbf2ae9701020be2d6a83ecb7f3f9d8e')
591        #pt = _spdechex('00000000000000000000000000000000')
592        ct = _spdechex('f42c33853ecc5ce2949865fdb83de3bff1089e9360c94f830baebfaff72836ab5236f77212f1e7396c8c54ac73d81986375a6e9e299cfeca5ba051ed25e8d1affa5beaf6c1d2b45e90802408f2ced21663497e906de5f29341e5e52ddfea5363d628b3eb7806835e17bae051b3a6da3f8e2941fe44384eac17a9d298d2c331ca8320c775b5d53263a5e905059d891b21dede2d8110fd427c7bd5a9a274ddb47b1945ee79522203b6e297d0e399ef')
593
594        c = Crypto(CRYPTO_AES_ICM, key)
595        enc = c.encrypt(pt, iv)
596
597        print('enc:', binascii.hexlify(enc))
598        print(' ct:', binascii.hexlify(ct))
599
600        assert ct == enc
601
602        dec = c.decrypt(ct, iv)
603
604        print('dec:', binascii.hexlify(dec))
605        print(' pt:', binascii.hexlify(pt))
606
607        assert pt == dec
608    elif False:
609        key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
610        iv = _spdechex('00000000000000000000000000000001')
611        pt = _spdechex('ab3cabed693a32946055524052afe3c9cb49664f09fc8b7da824d924006b7496353b8c1657c5dec564d8f38d7432e1de35aae9d95590e66278d4acce883e51abaf94977fcd3679660109a92bf7b2973ccd547f065ec6cee4cb4a72a5e9f45e615d920d76cb34cba482467b3e21422a7242e7d931330c0fbf465c3a3a46fae943029fd899626dda542750a1eee253df323c6ef1573f1c8c156613e2ea0a6cdbf2ae9701020be2d6a83ecb7f3f9d8e0a3f')
612        #pt = _spdechex('00000000000000000000000000000000')
613        ct = _spdechex('f42c33853ecc5ce2949865fdb83de3bff1089e9360c94f830baebfaff72836ab5236f77212f1e7396c8c54ac73d81986375a6e9e299cfeca5ba051ed25e8d1affa5beaf6c1d2b45e90802408f2ced21663497e906de5f29341e5e52ddfea5363d628b3eb7806835e17bae051b3a6da3f8e2941fe44384eac17a9d298d2c331ca8320c775b5d53263a5e905059d891b21dede2d8110fd427c7bd5a9a274ddb47b1945ee79522203b6e297d0e399ef3768')
614
615        c = Crypto(CRYPTO_AES_ICM, key)
616        enc = c.encrypt(pt, iv)
617
618        print('enc:', binascii.hexlify(enc))
619        print(' ct:', binascii.hexlify(ct))
620
621        assert ct == enc
622
623        dec = c.decrypt(ct, iv)
624
625        print('dec:', binascii.hexlify(dec))
626        print(' pt:', binascii.hexlify(pt))
627
628        assert pt == dec
629    elif False:
630        key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
631        iv = _spdechex('6eba2716ec0bd6fa5cdef5e6d3a795bc')
632        pt = _spdechex('ab3cabed693a32946055524052afe3c9cb49664f09fc8b7da824d924006b7496353b8c1657c5dec564d8f38d7432e1de35aae9d95590e66278d4acce883e51abaf94977fcd3679660109a92bf7b2973ccd547f065ec6cee4cb4a72a5e9f45e615d920d76cb34cba482467b3e21422a7242e7d931330c0fbf465c3a3a46fae943029fd899626dda542750a1eee253df323c6ef1573f1c8c156613e2ea0a6cdbf2ae9701020be2d6a83ecb7f3f9d8e0a3f')
633        ct = _spdechex('f1f81f12e72e992dbdc304032705dc75dc3e4180eff8ee4819906af6aee876d5b00b7c36d282a445ce3620327be481e8e53a8e5a8e5ca9abfeb2281be88d12ffa8f46d958d8224738c1f7eea48bda03edbf9adeb900985f4fa25648b406d13a886c25e70cfdecdde0ad0f2991420eb48a61c64fd797237cf2798c2675b9bb744360b0a3f329ac53bbceb4e3e7456e6514f1a9d2f06c236c31d0f080b79c15dce1096357416602520daa098b17d1af427')
634        c = Crypto(CRYPTO_AES_CBC, key)
635
636        enc = c.encrypt(pt, iv)
637
638        print('enc:', binascii.hexlify(enc))
639        print(' ct:', binascii.hexlify(ct))
640
641        assert ct == enc
642
643        dec = c.decrypt(ct, iv)
644
645        print('dec:', binascii.hexlify(dec))
646        print(' pt:', binascii.hexlify(pt))
647
648        assert pt == dec
649    elif False:
650        key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
651        iv = _spdechex('b3d8cc017cbb89b39e0f67e2')
652        pt = _spdechex('c3b3c41f113a31b73d9a5cd4321030')
653        aad = _spdechex('24825602bd12a984e0092d3e448eda5f')
654        ct = _spdechex('93fe7d9e9bfd10348a5606e5cafa7354')
655        ct = _spdechex('93fe7d9e9bfd10348a5606e5cafa73')
656        tag = _spdechex('0032a1dc85f1c9786925a2e71d8272dd')
657        tag = _spdechex('8d11a0929cb3fbe1fef01a4a38d5f8ea')
658
659        c = Crypto(CRYPTO_AES_NIST_GCM_16, key)
660
661        enc, enctag = c.encrypt(pt, iv, aad=aad)
662
663        print('enc:', binascii.hexlify(enc))
664        print(' ct:', binascii.hexlify(ct))
665
666        assert enc == ct
667
668        print('etg:', binascii.hexlify(enctag))
669        print('tag:', binascii.hexlify(tag))
670        assert enctag == tag
671
672        # Make sure we get EBADMSG
673        #enctag = enctag[:-1] + 'a'
674        dec, dectag = c.decrypt(ct, iv, aad=aad, tag=enctag)
675
676        print('dec:', binascii.hexlify(dec))
677        print(' pt:', binascii.hexlify(pt))
678
679        assert dec == pt
680
681        print('dtg:', binascii.hexlify(dectag))
682        print('tag:', binascii.hexlify(tag))
683
684        assert dectag == tag
685    elif False:
686        key = _spdechex('c939cc13397c1d37de6ae0e1cb7c423c')
687        iv = _spdechex('b3d8cc017cbb89b39e0f67e2')
688        key = key + iv[:4]
689        iv = iv[4:]
690        pt = _spdechex('c3b3c41f113a31b73d9a5cd432103069')
691        aad = _spdechex('24825602bd12a984e0092d3e448eda5f')
692        ct = _spdechex('93fe7d9e9bfd10348a5606e5cafa7354')
693        tag = _spdechex('0032a1dc85f1c9786925a2e71d8272dd')
694
695        c = Crypto(CRYPTO_AES_GCM_16, key)
696
697        enc, enctag = c.encrypt(pt, iv, aad=aad)
698
699        print('enc:', binascii.hexlify(enc))
700        print(' ct:', binascii.hexlify(ct))
701
702        assert enc == ct
703
704        print('etg:', binascii.hexlify(enctag))
705        print('tag:', binascii.hexlify(tag))
706        assert enctag == tag
707    elif False:
708        for i in range(100000):
709            c = Crypto(CRYPTO_AES_XTS, binascii.unhexlify('1bbfeadf539daedcae33ced497343f3ca1f2474ad932b903997d44707db41382'))
710            data = binascii.unhexlify('52a42bca4e9425a25bbc8c8bf6129dec')
711            ct = binascii.unhexlify('517e602becd066b65fa4f4f56ddfe240')
712            iv = _pack('QQ', 71, 0)
713
714            enc = c.encrypt(data, iv)
715            assert enc == ct
716    elif True:
717        c = Crypto(CRYPTO_AES_XTS, binascii.unhexlify('1bbfeadf539daedcae33ced497343f3ca1f2474ad932b903997d44707db41382'))
718        data = binascii.unhexlify('52a42bca4e9425a25bbc8c8bf6129dec')
719        ct = binascii.unhexlify('517e602becd066b65fa4f4f56ddfe240')
720        iv = _pack('QQ', 71, 0)
721
722        enc = c.encrypt(data, iv)
723        assert enc == ct
724
725        dec = c.decrypt(enc, iv)
726        assert dec == data
727
728        #c.perftest(COP_ENCRYPT, 192*1024, reps=30000)
729
730    else:
731        key = binascii.unhexlify('1bbfeadf539daedcae33ced497343f3ca1f2474ad932b903997d44707db41382')
732        print('XTS %d testing:' % (len(key) * 8))
733        c = Crypto(CRYPTO_AES_XTS, key)
734        for i in [ 8192, 192*1024]:
735            print('block size: %d' % i)
736            c.perftest(COP_ENCRYPT, i)
737            c.perftest(COP_DECRYPT, i)
738