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