xref: /freebsd/tests/sys/opencrypto/cryptodev.py (revision 4d846d26)
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 re
42import signal
43from struct import pack as _pack
44import sys
45import time
46
47import dpkt
48
49from cryptodevh import *
50
51__all__ = [ 'Crypto', 'MismatchError', ]
52
53class FindOp(dpkt.Packet):
54    __byte_order__ = '@'
55    __hdr__ = (
56        ('crid', 'i',   0),
57        ('name', '32s', 0),
58    )
59
60class SessionOp(dpkt.Packet):
61    __byte_order__ = '@'
62    __hdr__ = (
63        ('cipher',    'I', 0),
64        ('mac',       'I', 0),
65        ('keylen',    'I', 0),
66        ('key',       'P', 0),
67        ('mackeylen', 'i', 0),
68        ('mackey',    'P', 0),
69        ('ses',       'I', 0),
70    )
71
72class SessionOp2(dpkt.Packet):
73    __byte_order__ = '@'
74    __hdr__ = (
75        ('cipher',    'I', 0),
76        ('mac',       'I', 0),
77        ('keylen',    'I', 0),
78        ('key',       'P', 0),
79        ('mackeylen', 'i', 0),
80        ('mackey',    'P', 0),
81        ('ses',       'I', 0),
82        ('crid',      'i', 0),
83        ('ivlen',     'i', 0),
84        ('maclen',    'i', 0),
85        ('pad0',      'i', 0),
86        ('pad1',      'i', 0),
87    )
88
89class CryptOp(dpkt.Packet):
90    __byte_order__ = '@'
91    __hdr__ = (
92        ('ses',   'I', 0),
93        ('op',    'H', 0),
94        ('flags', 'H', 0),
95        ('len',   'I', 0),
96        ('src',   'P', 0),
97        ('dst',   'P', 0),
98        ('mac',   'P', 0),
99        ('iv',    'P', 0),
100    )
101
102class CryptAEAD(dpkt.Packet):
103    __byte_order__ = '@'
104    __hdr__ = (
105        ('ses',    'I', 0),
106        ('op',     'H', 0),
107        ('flags',  'H', 0),
108        ('len',    'I', 0),
109        ('aadlen', 'I', 0),
110        ('ivlen',  'I', 0),
111        ('src',    'P', 0),
112        ('dst',    'P', 0),
113        ('aad',    'P', 0),
114        ('tag',    'P', 0),
115        ('iv',     'P', 0),
116    )
117
118# h2py.py can't handle multiarg macros
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
134_cryptodev = os.open('/dev/crypto', os.O_RDWR)
135
136def str_to_ascii(val):
137    if sys.version_info[0] >= 3:
138        if isinstance(val, str):
139            return val.encode("ascii")
140    return val
141
142def _findop(crid, name):
143    fop = FindOp()
144    fop.crid = crid
145    fop.name = str_to_ascii(name)
146    s = array.array('B', fop.pack_hdr())
147    ioctl(_cryptodev, CIOCFINDDEV, s, 1)
148    fop.unpack(s)
149
150    try:
151        idx = fop.name.index(b'\x00')
152        name = fop.name[:idx]
153    except ValueError:
154        name = fop.name
155
156    return fop.crid, name
157
158def array_tobytes(array_obj):
159    if sys.version_info[:2] >= (3, 2):
160        return array_obj.tobytes()
161    return array_obj.tostring()
162
163def empty_bytes():
164    if sys.version_info[0] >= 3:
165        return b''
166    return ""
167
168class Crypto:
169    @staticmethod
170    def findcrid(name):
171        return _findop(-1, name)[0]
172
173    @staticmethod
174    def getcridname(crid):
175        return _findop(crid, '')[1]
176
177    def __init__(self, cipher=0, key=None, mac=0, mackey=None,
178        crid=CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE, maclen=None,
179        ivlen=None):
180        self._ses = None
181        self._maclen = maclen
182        ses = SessionOp2()
183        ses.cipher = cipher
184        ses.mac = mac
185
186        if key is not None:
187            ses.keylen = len(key)
188            k = array.array('B', key)
189            ses.key = k.buffer_info()[0]
190        else:
191            self.key = None
192
193        if mackey is not None:
194            ses.mackeylen = len(mackey)
195            mk = array.array('B', mackey)
196            ses.mackey = mk.buffer_info()[0]
197
198        if not cipher and not mac:
199            raise ValueError('one of cipher or mac MUST be specified.')
200        ses.crid = crid
201        if ivlen:
202            ses.ivlen = ivlen
203        if maclen:
204            ses.maclen = maclen
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, mac=None):
224        cop = CryptOp()
225        cop.ses = self._ses
226        cop.op = op
227        cop.flags = 0
228        if src is not None:
229            cop.len = len(src)
230            s = array.array('B', src)
231            cop.src = cop.dst = s.buffer_info()[0]
232        if mac is not None:
233            assert len(mac) == self._maclen, \
234                '%d != %d' % (len(tag), self._maclen)
235        if self._maclen is not None:
236            if mac is None:
237                m = array.array('B', [0] * self._maclen)
238            else:
239                m = array.array('B', mac)
240            cop.mac = m.buffer_info()[0]
241        ivbuf = array.array('B', str_to_ascii(iv))
242        cop.iv = ivbuf.buffer_info()[0]
243
244        #print('cop:', cop)
245        ioctl(_cryptodev, CIOCCRYPT, bytes(cop))
246
247        if src is not None:
248            s = array_tobytes(s)
249        else:
250            s = empty_bytes()
251        if self._maclen is not None:
252            return s, array_tobytes(m)
253
254        return s
255
256    def _doaead(self, op, src, aad, iv, tag=None):
257        caead = CryptAEAD()
258        caead.ses = self._ses
259        caead.op = op
260        caead.flags = CRD_F_IV_EXPLICIT
261        caead.flags = 0
262        if src:
263            src = str_to_ascii(src)
264            caead.len = len(src)
265            s = array.array('B', src)
266            caead.src = caead.dst = s.buffer_info()[0]
267        aad = str_to_ascii(aad)
268        caead.aadlen = len(aad)
269        saad = array.array('B', aad)
270        caead.aad = saad.buffer_info()[0]
271
272        if self._maclen is None:
273            raise ValueError('must have a tag length')
274
275        tag = str_to_ascii(tag)
276        if tag is None:
277            tag = array.array('B', [0] * self._maclen)
278        else:
279            assert len(tag) == self._maclen, \
280                '%d != %d' % (len(tag), self._maclen)
281            tag = array.array('B', tag)
282
283        caead.tag = tag.buffer_info()[0]
284
285        ivbuf = array.array('B', iv)
286        caead.ivlen = len(iv)
287        caead.iv = ivbuf.buffer_info()[0]
288
289        ioctl(_cryptodev, CIOCCRYPTAEAD, bytes(caead))
290
291        if src:
292            s = array_tobytes(s)
293        else:
294            s = empty_bytes()
295
296        return s, array_tobytes(tag)
297
298    def perftest(self, op, size, timeo=3):
299        inp = array.array('B', (random.randint(0, 255) for x in range(size)))
300        inp = str_to_ascii(inp)
301        out = array.array('B', inp)
302
303        # prep ioctl
304        cop = CryptOp()
305        cop.ses = self._ses
306        cop.op = op
307        cop.flags = 0
308        cop.len = len(inp)
309        s = array.array('B', inp)
310        cop.src = s.buffer_info()[0]
311        cop.dst = out.buffer_info()[0]
312        if self._maclen is not None:
313            m = array.array('B', [0] * self._maclen)
314            cop.mac = m.buffer_info()[0]
315        ivbuf = array.array('B', (random.randint(0, 255) for x in range(16)))
316        cop.iv = ivbuf.buffer_info()[0]
317
318        exit = [ False ]
319        def alarmhandle(a, b, exit=exit):
320            exit[0] = True
321
322        oldalarm = signal.signal(signal.SIGALRM, alarmhandle)
323        signal.alarm(timeo)
324
325        start = time.time()
326        reps = 0
327        cop = bytes(cop)
328        while not exit[0]:
329            ioctl(_cryptodev, CIOCCRYPT, cop)
330            reps += 1
331
332        end = time.time()
333
334        signal.signal(signal.SIGALRM, oldalarm)
335
336        print('time:', end - start)
337        print('perf MB/sec:', (reps * size) / (end - start) / 1024 / 1024)
338
339    def encrypt(self, data, iv, aad=None):
340        if aad is None:
341            return self._doop(COP_ENCRYPT, data, iv)
342        else:
343            return self._doaead(COP_ENCRYPT, data, aad,
344                iv)
345
346    def decrypt(self, data, iv, aad=None, tag=None):
347        if aad is None:
348            return self._doop(COP_DECRYPT, data, iv, mac=tag)
349        else:
350            return self._doaead(COP_DECRYPT, data, aad,
351                iv, tag=tag)
352
353class MismatchError(Exception):
354    pass
355
356class KATParser:
357    def __init__(self, fname, fields):
358        self.fields = set(fields)
359        self._pending = None
360        self.fname = fname
361        self.fp = None
362        self.field_re = re.compile(r"\[(?P<field>[^]]+)\]")
363
364    def __enter__(self):
365        self.fp = open(self.fname)
366        return self
367
368    def __exit__(self, exc_type, exc_value, exc_tb):
369        if self.fp is not None:
370            self.fp.close()
371
372    def __iter__(self):
373        return self
374
375    def __next__(self):
376        while True:
377            while True:
378                if self._pending is not None:
379                    i = self._pending
380                    self._pending = None
381                else:
382                    i = self.fp.readline()
383                    if not i:
384                        return
385
386                if not i.startswith('#') and i.strip():
387                    break
388
389            matches = self.field_re.match(i)
390            if matches is None:
391                raise ValueError("Unknown line: %r" % (i))
392            yield matches.group("field"), self.fielditer()
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