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