xref: /freebsd/tests/sys/opencrypto/cryptotest.py (revision 08fca7a56b5834a87bc3c04e57f74d6ce09f2563)
1*08fca7a5SJohn-Mark Gurney#!/usr/bin/env python
2*08fca7a5SJohn-Mark Gurney#
3*08fca7a5SJohn-Mark Gurney# Copyright (c) 2014 The FreeBSD Foundation
4*08fca7a5SJohn-Mark Gurney# All rights reserved.
5*08fca7a5SJohn-Mark Gurney#
6*08fca7a5SJohn-Mark Gurney# This software was developed by John-Mark Gurney under
7*08fca7a5SJohn-Mark Gurney# the sponsorship from the FreeBSD Foundation.
8*08fca7a5SJohn-Mark Gurney# Redistribution and use in source and binary forms, with or without
9*08fca7a5SJohn-Mark Gurney# modification, are permitted provided that the following conditions
10*08fca7a5SJohn-Mark Gurney# are met:
11*08fca7a5SJohn-Mark Gurney# 1.  Redistributions of source code must retain the above copyright
12*08fca7a5SJohn-Mark Gurney#     notice, this list of conditions and the following disclaimer.
13*08fca7a5SJohn-Mark Gurney# 2.  Redistributions in binary form must reproduce the above copyright
14*08fca7a5SJohn-Mark Gurney#     notice, this list of conditions and the following disclaimer in the
15*08fca7a5SJohn-Mark Gurney#     documentation and/or other materials provided with the distribution.
16*08fca7a5SJohn-Mark Gurney#
17*08fca7a5SJohn-Mark Gurney# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*08fca7a5SJohn-Mark Gurney# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*08fca7a5SJohn-Mark Gurney# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*08fca7a5SJohn-Mark Gurney# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*08fca7a5SJohn-Mark Gurney# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*08fca7a5SJohn-Mark Gurney# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*08fca7a5SJohn-Mark Gurney# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*08fca7a5SJohn-Mark Gurney# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*08fca7a5SJohn-Mark Gurney# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*08fca7a5SJohn-Mark Gurney# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*08fca7a5SJohn-Mark Gurney# SUCH DAMAGE.
28*08fca7a5SJohn-Mark Gurney#
29*08fca7a5SJohn-Mark Gurney# $FreeBSD$
30*08fca7a5SJohn-Mark Gurney#
31*08fca7a5SJohn-Mark Gurney
32*08fca7a5SJohn-Mark Gurneyimport cryptodev
33*08fca7a5SJohn-Mark Gurneyimport itertools
34*08fca7a5SJohn-Mark Gurneyimport os
35*08fca7a5SJohn-Mark Gurneyimport struct
36*08fca7a5SJohn-Mark Gurneyimport unittest
37*08fca7a5SJohn-Mark Gurneyfrom cryptodev import *
38*08fca7a5SJohn-Mark Gurneyfrom glob import iglob
39*08fca7a5SJohn-Mark Gurney
40*08fca7a5SJohn-Mark Gurneykatdir = '/usr/local/share/nist-kat'
41*08fca7a5SJohn-Mark Gurney
42*08fca7a5SJohn-Mark Gurneydef katg(base, glob):
43*08fca7a5SJohn-Mark Gurney	return iglob(os.path.join(katdir, base, glob))
44*08fca7a5SJohn-Mark Gurney
45*08fca7a5SJohn-Mark Gurneyaesmodules = [ 'cryptosoft0', 'aesni0', ]
46*08fca7a5SJohn-Mark Gurneydesmodules = [ 'cryptosoft0', ]
47*08fca7a5SJohn-Mark Gurneyshamodules = [ 'cryptosoft0', ]
48*08fca7a5SJohn-Mark Gurney
49*08fca7a5SJohn-Mark Gurneydef GenTestCase(cname):
50*08fca7a5SJohn-Mark Gurney	try:
51*08fca7a5SJohn-Mark Gurney		crid = cryptodev.Crypto.findcrid(cname)
52*08fca7a5SJohn-Mark Gurney	except IOError:
53*08fca7a5SJohn-Mark Gurney		return None
54*08fca7a5SJohn-Mark Gurney
55*08fca7a5SJohn-Mark Gurney	class GendCryptoTestCase(unittest.TestCase):
56*08fca7a5SJohn-Mark Gurney		###############
57*08fca7a5SJohn-Mark Gurney		##### AES #####
58*08fca7a5SJohn-Mark Gurney		###############
59*08fca7a5SJohn-Mark Gurney		@unittest.skipIf(cname not in aesmodules, 'skipping AES on %s' % `cname`)
60*08fca7a5SJohn-Mark Gurney		def test_xts(self):
61*08fca7a5SJohn-Mark Gurney			for i in katg('XTSTestVectors/format tweak value input - data unit seq no', '*.rsp'):
62*08fca7a5SJohn-Mark Gurney				self.runXTS(i, cryptodev.CRYPTO_AES_XTS)
63*08fca7a5SJohn-Mark Gurney
64*08fca7a5SJohn-Mark Gurney		def test_cbc(self):
65*08fca7a5SJohn-Mark Gurney			for i in katg('KAT_AES', 'CBC[GKV]*.rsp'):
66*08fca7a5SJohn-Mark Gurney				self.runCBC(i)
67*08fca7a5SJohn-Mark Gurney
68*08fca7a5SJohn-Mark Gurney		def test_gcm(self):
69*08fca7a5SJohn-Mark Gurney			for i in katg('gcmtestvectors', 'gcmEncrypt*'):
70*08fca7a5SJohn-Mark Gurney				self.runGCM(i, 'ENCRYPT')
71*08fca7a5SJohn-Mark Gurney
72*08fca7a5SJohn-Mark Gurney			for i in katg('gcmtestvectors', 'gcmDecrypt*'):
73*08fca7a5SJohn-Mark Gurney				self.runGCM(i, 'DECRYPT')
74*08fca7a5SJohn-Mark Gurney
75*08fca7a5SJohn-Mark Gurney		_gmacsizes = { 32: cryptodev.CRYPTO_AES_256_NIST_GMAC,
76*08fca7a5SJohn-Mark Gurney			24: cryptodev.CRYPTO_AES_192_NIST_GMAC,
77*08fca7a5SJohn-Mark Gurney			16: cryptodev.CRYPTO_AES_128_NIST_GMAC,
78*08fca7a5SJohn-Mark Gurney		}
79*08fca7a5SJohn-Mark Gurney		def runGCM(self, fname, mode):
80*08fca7a5SJohn-Mark Gurney			curfun = None
81*08fca7a5SJohn-Mark Gurney			if mode == 'ENCRYPT':
82*08fca7a5SJohn-Mark Gurney				swapptct = False
83*08fca7a5SJohn-Mark Gurney				curfun = Crypto.encrypt
84*08fca7a5SJohn-Mark Gurney			elif mode == 'DECRYPT':
85*08fca7a5SJohn-Mark Gurney				swapptct = True
86*08fca7a5SJohn-Mark Gurney				curfun = Crypto.decrypt
87*08fca7a5SJohn-Mark Gurney			else:
88*08fca7a5SJohn-Mark Gurney				raise RuntimeError('unknown mode: %s' % `mode`)
89*08fca7a5SJohn-Mark Gurney
90*08fca7a5SJohn-Mark Gurney			for bogusmode, lines in cryptodev.KATParser(fname,
91*08fca7a5SJohn-Mark Gurney			    [ 'Count', 'Key', 'IV', 'CT', 'AAD', 'Tag', 'PT', ]):
92*08fca7a5SJohn-Mark Gurney				for data in lines:
93*08fca7a5SJohn-Mark Gurney					curcnt = int(data['Count'])
94*08fca7a5SJohn-Mark Gurney					cipherkey = data['Key'].decode('hex')
95*08fca7a5SJohn-Mark Gurney					iv = data['IV'].decode('hex')
96*08fca7a5SJohn-Mark Gurney					aad = data['AAD'].decode('hex')
97*08fca7a5SJohn-Mark Gurney					tag = data['Tag'].decode('hex')
98*08fca7a5SJohn-Mark Gurney					if 'FAIL' not in data:
99*08fca7a5SJohn-Mark Gurney						pt = data['PT'].decode('hex')
100*08fca7a5SJohn-Mark Gurney					ct = data['CT'].decode('hex')
101*08fca7a5SJohn-Mark Gurney
102*08fca7a5SJohn-Mark Gurney					if len(iv) != 12:
103*08fca7a5SJohn-Mark Gurney						# XXX - isn't supported
104*08fca7a5SJohn-Mark Gurney						continue
105*08fca7a5SJohn-Mark Gurney
106*08fca7a5SJohn-Mark Gurney					c = Crypto(cryptodev.CRYPTO_AES_NIST_GCM_16,
107*08fca7a5SJohn-Mark Gurney					    cipherkey,
108*08fca7a5SJohn-Mark Gurney					    mac=self._gmacsizes[len(cipherkey)],
109*08fca7a5SJohn-Mark Gurney					    mackey=cipherkey, crid=crid)
110*08fca7a5SJohn-Mark Gurney
111*08fca7a5SJohn-Mark Gurney					if mode == 'ENCRYPT':
112*08fca7a5SJohn-Mark Gurney						rct, rtag = c.encrypt(pt, iv, aad)
113*08fca7a5SJohn-Mark Gurney						rtag = rtag[:len(tag)]
114*08fca7a5SJohn-Mark Gurney						data['rct'] = rct.encode('hex')
115*08fca7a5SJohn-Mark Gurney						data['rtag'] = rtag.encode('hex')
116*08fca7a5SJohn-Mark Gurney						self.assertEqual(rct, ct, `data`)
117*08fca7a5SJohn-Mark Gurney						self.assertEqual(rtag, tag, `data`)
118*08fca7a5SJohn-Mark Gurney					else:
119*08fca7a5SJohn-Mark Gurney						if len(tag) != 16:
120*08fca7a5SJohn-Mark Gurney							continue
121*08fca7a5SJohn-Mark Gurney						args = (ct, iv, aad, tag)
122*08fca7a5SJohn-Mark Gurney						if 'FAIL' in data:
123*08fca7a5SJohn-Mark Gurney							self.assertRaises(IOError,
124*08fca7a5SJohn-Mark Gurney								c.decrypt, *args)
125*08fca7a5SJohn-Mark Gurney						else:
126*08fca7a5SJohn-Mark Gurney							rpt, rtag = c.decrypt(*args)
127*08fca7a5SJohn-Mark Gurney							data['rpt'] = rpt.encode('hex')
128*08fca7a5SJohn-Mark Gurney							data['rtag'] = rtag.encode('hex')
129*08fca7a5SJohn-Mark Gurney							self.assertEqual(rpt, pt,
130*08fca7a5SJohn-Mark Gurney							    `data`)
131*08fca7a5SJohn-Mark Gurney
132*08fca7a5SJohn-Mark Gurney		def runCBC(self, fname):
133*08fca7a5SJohn-Mark Gurney			curfun = None
134*08fca7a5SJohn-Mark Gurney			for mode, lines in cryptodev.KATParser(fname,
135*08fca7a5SJohn-Mark Gurney			    [ 'COUNT', 'KEY', 'IV', 'PLAINTEXT', 'CIPHERTEXT', ]):
136*08fca7a5SJohn-Mark Gurney				if mode == 'ENCRYPT':
137*08fca7a5SJohn-Mark Gurney					swapptct = False
138*08fca7a5SJohn-Mark Gurney					curfun = Crypto.encrypt
139*08fca7a5SJohn-Mark Gurney				elif mode == 'DECRYPT':
140*08fca7a5SJohn-Mark Gurney					swapptct = True
141*08fca7a5SJohn-Mark Gurney					curfun = Crypto.decrypt
142*08fca7a5SJohn-Mark Gurney				else:
143*08fca7a5SJohn-Mark Gurney					raise RuntimeError('unknown mode: %s' % `mode`)
144*08fca7a5SJohn-Mark Gurney
145*08fca7a5SJohn-Mark Gurney				for data in lines:
146*08fca7a5SJohn-Mark Gurney					curcnt = int(data['COUNT'])
147*08fca7a5SJohn-Mark Gurney					cipherkey = data['KEY'].decode('hex')
148*08fca7a5SJohn-Mark Gurney					iv = data['IV'].decode('hex')
149*08fca7a5SJohn-Mark Gurney					pt = data['PLAINTEXT'].decode('hex')
150*08fca7a5SJohn-Mark Gurney					ct = data['CIPHERTEXT'].decode('hex')
151*08fca7a5SJohn-Mark Gurney
152*08fca7a5SJohn-Mark Gurney					if swapptct:
153*08fca7a5SJohn-Mark Gurney						pt, ct = ct, pt
154*08fca7a5SJohn-Mark Gurney					# run the fun
155*08fca7a5SJohn-Mark Gurney					c = Crypto(cryptodev.CRYPTO_AES_CBC, cipherkey, crid=crid)
156*08fca7a5SJohn-Mark Gurney					r = curfun(c, pt, iv)
157*08fca7a5SJohn-Mark Gurney					self.assertEqual(r, ct)
158*08fca7a5SJohn-Mark Gurney
159*08fca7a5SJohn-Mark Gurney		def runXTS(self, fname, meth):
160*08fca7a5SJohn-Mark Gurney			curfun = None
161*08fca7a5SJohn-Mark Gurney			for mode, lines in cryptodev.KATParser(fname,
162*08fca7a5SJohn-Mark Gurney			    [ 'COUNT', 'DataUnitLen', 'Key', 'DataUnitSeqNumber', 'PT',
163*08fca7a5SJohn-Mark Gurney			    'CT' ]):
164*08fca7a5SJohn-Mark Gurney				if mode == 'ENCRYPT':
165*08fca7a5SJohn-Mark Gurney					swapptct = False
166*08fca7a5SJohn-Mark Gurney					curfun = Crypto.encrypt
167*08fca7a5SJohn-Mark Gurney				elif mode == 'DECRYPT':
168*08fca7a5SJohn-Mark Gurney					swapptct = True
169*08fca7a5SJohn-Mark Gurney					curfun = Crypto.decrypt
170*08fca7a5SJohn-Mark Gurney				else:
171*08fca7a5SJohn-Mark Gurney					raise RuntimeError('unknown mode: %s' % `mode`)
172*08fca7a5SJohn-Mark Gurney
173*08fca7a5SJohn-Mark Gurney				for data in lines:
174*08fca7a5SJohn-Mark Gurney					curcnt = int(data['COUNT'])
175*08fca7a5SJohn-Mark Gurney					nbits = int(data['DataUnitLen'])
176*08fca7a5SJohn-Mark Gurney					cipherkey = data['Key'].decode('hex')
177*08fca7a5SJohn-Mark Gurney					iv = struct.pack('QQ', int(data['DataUnitSeqNumber']), 0)
178*08fca7a5SJohn-Mark Gurney					pt = data['PT'].decode('hex')
179*08fca7a5SJohn-Mark Gurney					ct = data['CT'].decode('hex')
180*08fca7a5SJohn-Mark Gurney
181*08fca7a5SJohn-Mark Gurney					if nbits % 128 != 0:
182*08fca7a5SJohn-Mark Gurney						# XXX - mark as skipped
183*08fca7a5SJohn-Mark Gurney						continue
184*08fca7a5SJohn-Mark Gurney					if swapptct:
185*08fca7a5SJohn-Mark Gurney						pt, ct = ct, pt
186*08fca7a5SJohn-Mark Gurney					# run the fun
187*08fca7a5SJohn-Mark Gurney					c = Crypto(meth, cipherkey, crid=crid)
188*08fca7a5SJohn-Mark Gurney					r = curfun(c, pt, iv)
189*08fca7a5SJohn-Mark Gurney					self.assertEqual(r, ct)
190*08fca7a5SJohn-Mark Gurney
191*08fca7a5SJohn-Mark Gurney		###############
192*08fca7a5SJohn-Mark Gurney		##### DES #####
193*08fca7a5SJohn-Mark Gurney		###############
194*08fca7a5SJohn-Mark Gurney		@unittest.skipIf(cname not in desmodules, 'skipping DES on %s' % `cname`)
195*08fca7a5SJohn-Mark Gurney		def test_tdes(self):
196*08fca7a5SJohn-Mark Gurney			for i in katg('KAT_TDES', 'TCBC[a-z]*.rsp'):
197*08fca7a5SJohn-Mark Gurney				self.runTDES(i)
198*08fca7a5SJohn-Mark Gurney
199*08fca7a5SJohn-Mark Gurney		def runTDES(self, fname):
200*08fca7a5SJohn-Mark Gurney			curfun = None
201*08fca7a5SJohn-Mark Gurney			for mode, lines in cryptodev.KATParser(fname,
202*08fca7a5SJohn-Mark Gurney			    [ 'COUNT', 'KEYs', 'IV', 'PLAINTEXT', 'CIPHERTEXT', ]):
203*08fca7a5SJohn-Mark Gurney				if mode == 'ENCRYPT':
204*08fca7a5SJohn-Mark Gurney					swapptct = False
205*08fca7a5SJohn-Mark Gurney					curfun = Crypto.encrypt
206*08fca7a5SJohn-Mark Gurney				elif mode == 'DECRYPT':
207*08fca7a5SJohn-Mark Gurney					swapptct = True
208*08fca7a5SJohn-Mark Gurney					curfun = Crypto.decrypt
209*08fca7a5SJohn-Mark Gurney				else:
210*08fca7a5SJohn-Mark Gurney					raise RuntimeError('unknown mode: %s' % `mode`)
211*08fca7a5SJohn-Mark Gurney
212*08fca7a5SJohn-Mark Gurney				for data in lines:
213*08fca7a5SJohn-Mark Gurney					curcnt = int(data['COUNT'])
214*08fca7a5SJohn-Mark Gurney					key = data['KEYs'] * 3
215*08fca7a5SJohn-Mark Gurney					cipherkey = key.decode('hex')
216*08fca7a5SJohn-Mark Gurney					iv = data['IV'].decode('hex')
217*08fca7a5SJohn-Mark Gurney					pt = data['PLAINTEXT'].decode('hex')
218*08fca7a5SJohn-Mark Gurney					ct = data['CIPHERTEXT'].decode('hex')
219*08fca7a5SJohn-Mark Gurney
220*08fca7a5SJohn-Mark Gurney					if swapptct:
221*08fca7a5SJohn-Mark Gurney						pt, ct = ct, pt
222*08fca7a5SJohn-Mark Gurney					# run the fun
223*08fca7a5SJohn-Mark Gurney					c = Crypto(cryptodev.CRYPTO_3DES_CBC, cipherkey, crid=crid)
224*08fca7a5SJohn-Mark Gurney					r = curfun(c, pt, iv)
225*08fca7a5SJohn-Mark Gurney					self.assertEqual(r, ct)
226*08fca7a5SJohn-Mark Gurney
227*08fca7a5SJohn-Mark Gurney		###############
228*08fca7a5SJohn-Mark Gurney		##### SHA #####
229*08fca7a5SJohn-Mark Gurney		###############
230*08fca7a5SJohn-Mark Gurney		@unittest.skipIf(cname not in shamodules, 'skipping SHA on %s' % `cname`)
231*08fca7a5SJohn-Mark Gurney		def test_sha(self):
232*08fca7a5SJohn-Mark Gurney			# SHA not available in software
233*08fca7a5SJohn-Mark Gurney			pass
234*08fca7a5SJohn-Mark Gurney			#for i in iglob('SHA1*'):
235*08fca7a5SJohn-Mark Gurney			#	self.runSHA(i)
236*08fca7a5SJohn-Mark Gurney
237*08fca7a5SJohn-Mark Gurney		def test_sha1hmac(self):
238*08fca7a5SJohn-Mark Gurney			for i in katg('hmactestvectors', 'HMAC.rsp'):
239*08fca7a5SJohn-Mark Gurney				self.runSHA1HMAC(i)
240*08fca7a5SJohn-Mark Gurney
241*08fca7a5SJohn-Mark Gurney		def runSHA1HMAC(self, fname):
242*08fca7a5SJohn-Mark Gurney			for bogusmode, lines in cryptodev.KATParser(fname,
243*08fca7a5SJohn-Mark Gurney			    [ 'Count', 'Klen', 'Tlen', 'Key', 'Msg', 'Mac' ]):
244*08fca7a5SJohn-Mark Gurney				for data in lines:
245*08fca7a5SJohn-Mark Gurney					key = data['Key'].decode('hex')
246*08fca7a5SJohn-Mark Gurney					msg = data['Msg'].decode('hex')
247*08fca7a5SJohn-Mark Gurney					mac = data['Mac'].decode('hex')
248*08fca7a5SJohn-Mark Gurney
249*08fca7a5SJohn-Mark Gurney					if len(key) != 20:
250*08fca7a5SJohn-Mark Gurney						# XXX - implementation bug
251*08fca7a5SJohn-Mark Gurney						continue
252*08fca7a5SJohn-Mark Gurney
253*08fca7a5SJohn-Mark Gurney					c = Crypto(mac=cryptodev.CRYPTO_SHA1_HMAC,
254*08fca7a5SJohn-Mark Gurney					    mackey=key, crid=crid)
255*08fca7a5SJohn-Mark Gurney
256*08fca7a5SJohn-Mark Gurney					r = c.encrypt(msg)
257*08fca7a5SJohn-Mark Gurney					self.assertEqual(r, mac, `data`)
258*08fca7a5SJohn-Mark Gurney
259*08fca7a5SJohn-Mark Gurney	return GendCryptoTestCase
260*08fca7a5SJohn-Mark Gurney
261*08fca7a5SJohn-Mark Gurneycryptosoft = GenTestCase('cryptosoft0')
262*08fca7a5SJohn-Mark Gurneyaesni = GenTestCase('aesni0')
263*08fca7a5SJohn-Mark Gurney
264*08fca7a5SJohn-Mark Gurneyif __name__ == '__main__':
265*08fca7a5SJohn-Mark Gurney	unittest.main()
266