xref: /freebsd/tests/sys/opencrypto/cryptotest.py (revision 6720b890459dccaf6da00d7a30fe63d01b0eac7b)
108fca7a5SJohn-Mark Gurney#!/usr/bin/env python
208fca7a5SJohn-Mark Gurney#
308fca7a5SJohn-Mark Gurney# Copyright (c) 2014 The FreeBSD Foundation
408fca7a5SJohn-Mark Gurney# All rights reserved.
508fca7a5SJohn-Mark Gurney#
608fca7a5SJohn-Mark Gurney# This software was developed by John-Mark Gurney under
708fca7a5SJohn-Mark Gurney# the sponsorship from the FreeBSD Foundation.
808fca7a5SJohn-Mark Gurney# Redistribution and use in source and binary forms, with or without
908fca7a5SJohn-Mark Gurney# modification, are permitted provided that the following conditions
1008fca7a5SJohn-Mark Gurney# are met:
1108fca7a5SJohn-Mark Gurney# 1.  Redistributions of source code must retain the above copyright
1208fca7a5SJohn-Mark Gurney#     notice, this list of conditions and the following disclaimer.
1308fca7a5SJohn-Mark Gurney# 2.  Redistributions in binary form must reproduce the above copyright
1408fca7a5SJohn-Mark Gurney#     notice, this list of conditions and the following disclaimer in the
1508fca7a5SJohn-Mark Gurney#     documentation and/or other materials provided with the distribution.
1608fca7a5SJohn-Mark Gurney#
1708fca7a5SJohn-Mark Gurney# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1808fca7a5SJohn-Mark Gurney# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1908fca7a5SJohn-Mark Gurney# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2008fca7a5SJohn-Mark Gurney# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2108fca7a5SJohn-Mark Gurney# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2208fca7a5SJohn-Mark Gurney# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2308fca7a5SJohn-Mark Gurney# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2408fca7a5SJohn-Mark Gurney# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2508fca7a5SJohn-Mark Gurney# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2608fca7a5SJohn-Mark Gurney# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2708fca7a5SJohn-Mark Gurney# SUCH DAMAGE.
2808fca7a5SJohn-Mark Gurney#
2908fca7a5SJohn-Mark Gurney# $FreeBSD$
3008fca7a5SJohn-Mark Gurney#
3108fca7a5SJohn-Mark Gurney
3208fca7a5SJohn-Mark Gurneyimport cryptodev
3308fca7a5SJohn-Mark Gurneyimport itertools
3408fca7a5SJohn-Mark Gurneyimport os
3508fca7a5SJohn-Mark Gurneyimport struct
3608fca7a5SJohn-Mark Gurneyimport unittest
3708fca7a5SJohn-Mark Gurneyfrom cryptodev import *
3808fca7a5SJohn-Mark Gurneyfrom glob import iglob
3908fca7a5SJohn-Mark Gurney
4008fca7a5SJohn-Mark Gurneykatdir = '/usr/local/share/nist-kat'
4108fca7a5SJohn-Mark Gurney
4208fca7a5SJohn-Mark Gurneydef katg(base, glob):
4308fca7a5SJohn-Mark Gurney	return iglob(os.path.join(katdir, base, glob))
4408fca7a5SJohn-Mark Gurney
45*6720b890SJohn Baldwinaesmodules = [ 'cryptosoft0', 'aesni0', 'ccr0' ]
4608fca7a5SJohn-Mark Gurneydesmodules = [ 'cryptosoft0', ]
47*6720b890SJohn Baldwinshamodules = [ 'cryptosoft0', 'ccr0' ]
4808fca7a5SJohn-Mark Gurney
4908fca7a5SJohn-Mark Gurneydef GenTestCase(cname):
5008fca7a5SJohn-Mark Gurney	try:
5108fca7a5SJohn-Mark Gurney		crid = cryptodev.Crypto.findcrid(cname)
5208fca7a5SJohn-Mark Gurney	except IOError:
5308fca7a5SJohn-Mark Gurney		return None
5408fca7a5SJohn-Mark Gurney
5508fca7a5SJohn-Mark Gurney	class GendCryptoTestCase(unittest.TestCase):
5608fca7a5SJohn-Mark Gurney		###############
5708fca7a5SJohn-Mark Gurney		##### AES #####
5808fca7a5SJohn-Mark Gurney		###############
5908fca7a5SJohn-Mark Gurney		@unittest.skipIf(cname not in aesmodules, 'skipping AES on %s' % `cname`)
6008fca7a5SJohn-Mark Gurney		def test_xts(self):
6108fca7a5SJohn-Mark Gurney			for i in katg('XTSTestVectors/format tweak value input - data unit seq no', '*.rsp'):
6208fca7a5SJohn-Mark Gurney				self.runXTS(i, cryptodev.CRYPTO_AES_XTS)
6308fca7a5SJohn-Mark Gurney
6408fca7a5SJohn-Mark Gurney		def test_cbc(self):
6508fca7a5SJohn-Mark Gurney			for i in katg('KAT_AES', 'CBC[GKV]*.rsp'):
6608fca7a5SJohn-Mark Gurney				self.runCBC(i)
6708fca7a5SJohn-Mark Gurney
6808fca7a5SJohn-Mark Gurney		def test_gcm(self):
6908fca7a5SJohn-Mark Gurney			for i in katg('gcmtestvectors', 'gcmEncrypt*'):
7008fca7a5SJohn-Mark Gurney				self.runGCM(i, 'ENCRYPT')
7108fca7a5SJohn-Mark Gurney
7208fca7a5SJohn-Mark Gurney			for i in katg('gcmtestvectors', 'gcmDecrypt*'):
7308fca7a5SJohn-Mark Gurney				self.runGCM(i, 'DECRYPT')
7408fca7a5SJohn-Mark Gurney
7508fca7a5SJohn-Mark Gurney		_gmacsizes = { 32: cryptodev.CRYPTO_AES_256_NIST_GMAC,
7608fca7a5SJohn-Mark Gurney			24: cryptodev.CRYPTO_AES_192_NIST_GMAC,
7708fca7a5SJohn-Mark Gurney			16: cryptodev.CRYPTO_AES_128_NIST_GMAC,
7808fca7a5SJohn-Mark Gurney		}
7908fca7a5SJohn-Mark Gurney		def runGCM(self, fname, mode):
8008fca7a5SJohn-Mark Gurney			curfun = None
8108fca7a5SJohn-Mark Gurney			if mode == 'ENCRYPT':
8208fca7a5SJohn-Mark Gurney				swapptct = False
8308fca7a5SJohn-Mark Gurney				curfun = Crypto.encrypt
8408fca7a5SJohn-Mark Gurney			elif mode == 'DECRYPT':
8508fca7a5SJohn-Mark Gurney				swapptct = True
8608fca7a5SJohn-Mark Gurney				curfun = Crypto.decrypt
8708fca7a5SJohn-Mark Gurney			else:
8808fca7a5SJohn-Mark Gurney				raise RuntimeError('unknown mode: %s' % `mode`)
8908fca7a5SJohn-Mark Gurney
9008fca7a5SJohn-Mark Gurney			for bogusmode, lines in cryptodev.KATParser(fname,
9108fca7a5SJohn-Mark Gurney			    [ 'Count', 'Key', 'IV', 'CT', 'AAD', 'Tag', 'PT', ]):
9208fca7a5SJohn-Mark Gurney				for data in lines:
9308fca7a5SJohn-Mark Gurney					curcnt = int(data['Count'])
9408fca7a5SJohn-Mark Gurney					cipherkey = data['Key'].decode('hex')
9508fca7a5SJohn-Mark Gurney					iv = data['IV'].decode('hex')
9608fca7a5SJohn-Mark Gurney					aad = data['AAD'].decode('hex')
9708fca7a5SJohn-Mark Gurney					tag = data['Tag'].decode('hex')
9808fca7a5SJohn-Mark Gurney					if 'FAIL' not in data:
9908fca7a5SJohn-Mark Gurney						pt = data['PT'].decode('hex')
10008fca7a5SJohn-Mark Gurney					ct = data['CT'].decode('hex')
10108fca7a5SJohn-Mark Gurney
10208fca7a5SJohn-Mark Gurney					if len(iv) != 12:
10308fca7a5SJohn-Mark Gurney						# XXX - isn't supported
10408fca7a5SJohn-Mark Gurney						continue
10508fca7a5SJohn-Mark Gurney
10608fca7a5SJohn-Mark Gurney					c = Crypto(cryptodev.CRYPTO_AES_NIST_GCM_16,
10708fca7a5SJohn-Mark Gurney					    cipherkey,
10808fca7a5SJohn-Mark Gurney					    mac=self._gmacsizes[len(cipherkey)],
10908fca7a5SJohn-Mark Gurney					    mackey=cipherkey, crid=crid)
11008fca7a5SJohn-Mark Gurney
11108fca7a5SJohn-Mark Gurney					if mode == 'ENCRYPT':
11208fca7a5SJohn-Mark Gurney						rct, rtag = c.encrypt(pt, iv, aad)
11308fca7a5SJohn-Mark Gurney						rtag = rtag[:len(tag)]
11408fca7a5SJohn-Mark Gurney						data['rct'] = rct.encode('hex')
11508fca7a5SJohn-Mark Gurney						data['rtag'] = rtag.encode('hex')
11608fca7a5SJohn-Mark Gurney						self.assertEqual(rct, ct, `data`)
11708fca7a5SJohn-Mark Gurney						self.assertEqual(rtag, tag, `data`)
11808fca7a5SJohn-Mark Gurney					else:
11908fca7a5SJohn-Mark Gurney						if len(tag) != 16:
12008fca7a5SJohn-Mark Gurney							continue
12108fca7a5SJohn-Mark Gurney						args = (ct, iv, aad, tag)
12208fca7a5SJohn-Mark Gurney						if 'FAIL' in data:
12308fca7a5SJohn-Mark Gurney							self.assertRaises(IOError,
12408fca7a5SJohn-Mark Gurney								c.decrypt, *args)
12508fca7a5SJohn-Mark Gurney						else:
12608fca7a5SJohn-Mark Gurney							rpt, rtag = c.decrypt(*args)
12708fca7a5SJohn-Mark Gurney							data['rpt'] = rpt.encode('hex')
12808fca7a5SJohn-Mark Gurney							data['rtag'] = rtag.encode('hex')
12908fca7a5SJohn-Mark Gurney							self.assertEqual(rpt, pt,
13008fca7a5SJohn-Mark Gurney							    `data`)
13108fca7a5SJohn-Mark Gurney
13208fca7a5SJohn-Mark Gurney		def runCBC(self, fname):
13308fca7a5SJohn-Mark Gurney			curfun = None
13408fca7a5SJohn-Mark Gurney			for mode, lines in cryptodev.KATParser(fname,
13508fca7a5SJohn-Mark Gurney			    [ 'COUNT', 'KEY', 'IV', 'PLAINTEXT', 'CIPHERTEXT', ]):
13608fca7a5SJohn-Mark Gurney				if mode == 'ENCRYPT':
13708fca7a5SJohn-Mark Gurney					swapptct = False
13808fca7a5SJohn-Mark Gurney					curfun = Crypto.encrypt
13908fca7a5SJohn-Mark Gurney				elif mode == 'DECRYPT':
14008fca7a5SJohn-Mark Gurney					swapptct = True
14108fca7a5SJohn-Mark Gurney					curfun = Crypto.decrypt
14208fca7a5SJohn-Mark Gurney				else:
14308fca7a5SJohn-Mark Gurney					raise RuntimeError('unknown mode: %s' % `mode`)
14408fca7a5SJohn-Mark Gurney
14508fca7a5SJohn-Mark Gurney				for data in lines:
14608fca7a5SJohn-Mark Gurney					curcnt = int(data['COUNT'])
14708fca7a5SJohn-Mark Gurney					cipherkey = data['KEY'].decode('hex')
14808fca7a5SJohn-Mark Gurney					iv = data['IV'].decode('hex')
14908fca7a5SJohn-Mark Gurney					pt = data['PLAINTEXT'].decode('hex')
15008fca7a5SJohn-Mark Gurney					ct = data['CIPHERTEXT'].decode('hex')
15108fca7a5SJohn-Mark Gurney
15208fca7a5SJohn-Mark Gurney					if swapptct:
15308fca7a5SJohn-Mark Gurney						pt, ct = ct, pt
15408fca7a5SJohn-Mark Gurney					# run the fun
15508fca7a5SJohn-Mark Gurney					c = Crypto(cryptodev.CRYPTO_AES_CBC, cipherkey, crid=crid)
15608fca7a5SJohn-Mark Gurney					r = curfun(c, pt, iv)
15708fca7a5SJohn-Mark Gurney					self.assertEqual(r, ct)
15808fca7a5SJohn-Mark Gurney
15908fca7a5SJohn-Mark Gurney		def runXTS(self, fname, meth):
16008fca7a5SJohn-Mark Gurney			curfun = None
16108fca7a5SJohn-Mark Gurney			for mode, lines in cryptodev.KATParser(fname,
16208fca7a5SJohn-Mark Gurney			    [ 'COUNT', 'DataUnitLen', 'Key', 'DataUnitSeqNumber', 'PT',
16308fca7a5SJohn-Mark Gurney			    'CT' ]):
16408fca7a5SJohn-Mark Gurney				if mode == 'ENCRYPT':
16508fca7a5SJohn-Mark Gurney					swapptct = False
16608fca7a5SJohn-Mark Gurney					curfun = Crypto.encrypt
16708fca7a5SJohn-Mark Gurney				elif mode == 'DECRYPT':
16808fca7a5SJohn-Mark Gurney					swapptct = True
16908fca7a5SJohn-Mark Gurney					curfun = Crypto.decrypt
17008fca7a5SJohn-Mark Gurney				else:
17108fca7a5SJohn-Mark Gurney					raise RuntimeError('unknown mode: %s' % `mode`)
17208fca7a5SJohn-Mark Gurney
17308fca7a5SJohn-Mark Gurney				for data in lines:
17408fca7a5SJohn-Mark Gurney					curcnt = int(data['COUNT'])
17508fca7a5SJohn-Mark Gurney					nbits = int(data['DataUnitLen'])
17608fca7a5SJohn-Mark Gurney					cipherkey = data['Key'].decode('hex')
17708fca7a5SJohn-Mark Gurney					iv = struct.pack('QQ', int(data['DataUnitSeqNumber']), 0)
17808fca7a5SJohn-Mark Gurney					pt = data['PT'].decode('hex')
17908fca7a5SJohn-Mark Gurney					ct = data['CT'].decode('hex')
18008fca7a5SJohn-Mark Gurney
18108fca7a5SJohn-Mark Gurney					if nbits % 128 != 0:
18208fca7a5SJohn-Mark Gurney						# XXX - mark as skipped
18308fca7a5SJohn-Mark Gurney						continue
18408fca7a5SJohn-Mark Gurney					if swapptct:
18508fca7a5SJohn-Mark Gurney						pt, ct = ct, pt
18608fca7a5SJohn-Mark Gurney					# run the fun
18708fca7a5SJohn-Mark Gurney					c = Crypto(meth, cipherkey, crid=crid)
18808fca7a5SJohn-Mark Gurney					r = curfun(c, pt, iv)
18908fca7a5SJohn-Mark Gurney					self.assertEqual(r, ct)
19008fca7a5SJohn-Mark Gurney
19108fca7a5SJohn-Mark Gurney		###############
19208fca7a5SJohn-Mark Gurney		##### DES #####
19308fca7a5SJohn-Mark Gurney		###############
19408fca7a5SJohn-Mark Gurney		@unittest.skipIf(cname not in desmodules, 'skipping DES on %s' % `cname`)
19508fca7a5SJohn-Mark Gurney		def test_tdes(self):
19608fca7a5SJohn-Mark Gurney			for i in katg('KAT_TDES', 'TCBC[a-z]*.rsp'):
19708fca7a5SJohn-Mark Gurney				self.runTDES(i)
19808fca7a5SJohn-Mark Gurney
19908fca7a5SJohn-Mark Gurney		def runTDES(self, fname):
20008fca7a5SJohn-Mark Gurney			curfun = None
20108fca7a5SJohn-Mark Gurney			for mode, lines in cryptodev.KATParser(fname,
20208fca7a5SJohn-Mark Gurney			    [ 'COUNT', 'KEYs', 'IV', 'PLAINTEXT', 'CIPHERTEXT', ]):
20308fca7a5SJohn-Mark Gurney				if mode == 'ENCRYPT':
20408fca7a5SJohn-Mark Gurney					swapptct = False
20508fca7a5SJohn-Mark Gurney					curfun = Crypto.encrypt
20608fca7a5SJohn-Mark Gurney				elif mode == 'DECRYPT':
20708fca7a5SJohn-Mark Gurney					swapptct = True
20808fca7a5SJohn-Mark Gurney					curfun = Crypto.decrypt
20908fca7a5SJohn-Mark Gurney				else:
21008fca7a5SJohn-Mark Gurney					raise RuntimeError('unknown mode: %s' % `mode`)
21108fca7a5SJohn-Mark Gurney
21208fca7a5SJohn-Mark Gurney				for data in lines:
21308fca7a5SJohn-Mark Gurney					curcnt = int(data['COUNT'])
21408fca7a5SJohn-Mark Gurney					key = data['KEYs'] * 3
21508fca7a5SJohn-Mark Gurney					cipherkey = key.decode('hex')
21608fca7a5SJohn-Mark Gurney					iv = data['IV'].decode('hex')
21708fca7a5SJohn-Mark Gurney					pt = data['PLAINTEXT'].decode('hex')
21808fca7a5SJohn-Mark Gurney					ct = data['CIPHERTEXT'].decode('hex')
21908fca7a5SJohn-Mark Gurney
22008fca7a5SJohn-Mark Gurney					if swapptct:
22108fca7a5SJohn-Mark Gurney						pt, ct = ct, pt
22208fca7a5SJohn-Mark Gurney					# run the fun
22308fca7a5SJohn-Mark Gurney					c = Crypto(cryptodev.CRYPTO_3DES_CBC, cipherkey, crid=crid)
22408fca7a5SJohn-Mark Gurney					r = curfun(c, pt, iv)
22508fca7a5SJohn-Mark Gurney					self.assertEqual(r, ct)
22608fca7a5SJohn-Mark Gurney
22708fca7a5SJohn-Mark Gurney		###############
22808fca7a5SJohn-Mark Gurney		##### SHA #####
22908fca7a5SJohn-Mark Gurney		###############
23008fca7a5SJohn-Mark Gurney		@unittest.skipIf(cname not in shamodules, 'skipping SHA on %s' % `cname`)
23108fca7a5SJohn-Mark Gurney		def test_sha(self):
23208fca7a5SJohn-Mark Gurney			# SHA not available in software
23308fca7a5SJohn-Mark Gurney			pass
23408fca7a5SJohn-Mark Gurney			#for i in iglob('SHA1*'):
23508fca7a5SJohn-Mark Gurney			#	self.runSHA(i)
23608fca7a5SJohn-Mark Gurney
23708fca7a5SJohn-Mark Gurney		def test_sha1hmac(self):
23808fca7a5SJohn-Mark Gurney			for i in katg('hmactestvectors', 'HMAC.rsp'):
23908fca7a5SJohn-Mark Gurney				self.runSHA1HMAC(i)
24008fca7a5SJohn-Mark Gurney
24108fca7a5SJohn-Mark Gurney		def runSHA1HMAC(self, fname):
24208fca7a5SJohn-Mark Gurney			for bogusmode, lines in cryptodev.KATParser(fname,
24308fca7a5SJohn-Mark Gurney			    [ 'Count', 'Klen', 'Tlen', 'Key', 'Msg', 'Mac' ]):
24408fca7a5SJohn-Mark Gurney				for data in lines:
24508fca7a5SJohn-Mark Gurney					key = data['Key'].decode('hex')
24608fca7a5SJohn-Mark Gurney					msg = data['Msg'].decode('hex')
24708fca7a5SJohn-Mark Gurney					mac = data['Mac'].decode('hex')
24808fca7a5SJohn-Mark Gurney
24908fca7a5SJohn-Mark Gurney					if len(key) != 20:
25008fca7a5SJohn-Mark Gurney						# XXX - implementation bug
25108fca7a5SJohn-Mark Gurney						continue
25208fca7a5SJohn-Mark Gurney
25308fca7a5SJohn-Mark Gurney					c = Crypto(mac=cryptodev.CRYPTO_SHA1_HMAC,
25408fca7a5SJohn-Mark Gurney					    mackey=key, crid=crid)
25508fca7a5SJohn-Mark Gurney
25608fca7a5SJohn-Mark Gurney					r = c.encrypt(msg)
25708fca7a5SJohn-Mark Gurney					self.assertEqual(r, mac, `data`)
25808fca7a5SJohn-Mark Gurney
25908fca7a5SJohn-Mark Gurney	return GendCryptoTestCase
26008fca7a5SJohn-Mark Gurney
26108fca7a5SJohn-Mark Gurneycryptosoft = GenTestCase('cryptosoft0')
26208fca7a5SJohn-Mark Gurneyaesni = GenTestCase('aesni0')
263*6720b890SJohn Baldwinccr = GenTestCase('ccr0')
26408fca7a5SJohn-Mark Gurney
26508fca7a5SJohn-Mark Gurneyif __name__ == '__main__':
26608fca7a5SJohn-Mark Gurney	unittest.main()
267