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