1/* 2 * fips186prf.c An implementation of the FIPS-186-2 SHA1-based PRF. 3 * 4 * The development of the EAP/SIM support was funded by Internet Foundation 5 * Austria (http://www.nic.at/ipa). 6 * 7 * This code was written from scratch by Michael Richardson, and it is 8 * dual licensed under both GPL and BSD. 9 * 10 * Version: $Id: fips186prf.c,v 1.12 2008/06/05 12:17:33 aland Exp $ 11 * 12 * GPL notice: 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, write to the Free Software 26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 27 * 28 * BSD notice: 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions 32 * are met: 33 * 1. Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * 3. Neither the name of The NetBSD Foundation nor the names of its 39 * contributors may be used to endorse or promote products derived 40 * from this software without specific prior written permission. 41 * 42 * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca> 43 * Copyright 2006 The FreeRADIUS server project 44 * 45 */ 46 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50 51#include <sys/types.h> 52#include <stdint.h> 53#include "fr_sha1.h" 54#include "fips186prf.h" 55 56/* 57 * we do it in 8-bit chunks, because we have to keep the numbers 58 * in network byte order (i.e. MSB) 59 * 60 * make it a structure so that we can do structure assignments. 61 */ 62typedef struct onesixty { 63 uint8_t p[20]; 64} onesixty; 65 66static void onesixty_add_mod(onesixty *sum, onesixty *a, onesixty *b) 67{ 68 uint32_t s; 69 int i, carry; 70 71 carry = 0; 72 for(i=19; i>=0; i--) { 73/* for(i=0; i<20; i++) { */ 74 s = a->p[i] + b->p[i] + carry; 75 sum->p[i] = s & 0xff; 76 carry = s >> 8; 77 } 78} 79 80/* 81 * run the FIPS-186-2 PRF on the given Master Key (160 bits) 82 * in order to derive 1280 bits (160 bytes) of keying data from 83 * it. 84 * 85 * Given that in EAP-SIM, this is coming from a 64-bit Kc it seems 86 * like an awful lot of "randomness" to pull out.. (MCR) 87 * 88 */ 89 90__private_extern__ 91void fips186_2prf(uint8_t mk[20], uint8_t finalkey[160]) 92{ 93 fr_SHA1_CTX context; 94 int j; 95 onesixty xval, xkey, w_0, w_1, sum, one; 96 uint8_t *f; 97 uint8_t zeros[64]; 98 99 /* 100 * let XKEY := MK, 101 * 102 * Step 3: For j = 0 to 3 do 103 * a. XVAL = XKEY 104 * b. w_0 = SHA1(XVAL) 105 * c. XKEY = (1 + XKEY + w_0) mod 2^160 106 * d. XVAL = XKEY 107 * e. w_1 = SHA1(XVAL) 108 * f. XKEY = (1 + XKEY + w_1) mod 2^160 109 * 3.3 x_j = w_0|w_1 110 * 111 */ 112 memcpy(&xkey, mk, sizeof(xkey)); 113 114 /* make the value 1 */ 115 memset(&one, 0, sizeof(one)); 116 one.p[19]=1; 117 118 f=finalkey; 119 120 for(j=0; j<4; j++) { 121 /* a. XVAL = XKEY */ 122 xval = xkey; 123 124 /* b. w_0 = SHA1(XVAL) */ 125 fr_SHA1Init(&context); 126 127 memset(zeros, 0, sizeof(zeros)); 128 memcpy(zeros, xval.p, 20); 129 fr_SHA1Transform(&context, zeros); 130 fr_SHA1FinalNoLen(w_0.p, &context); 131 132 /* c. XKEY = (1 + XKEY + w_0) mod 2^160 */ 133 onesixty_add_mod(&sum, &xkey, &w_0); 134 onesixty_add_mod(&xkey, &sum, &one); 135 136 /* d. XVAL = XKEY */ 137 xval = xkey; 138 139 /* e. w_1 = SHA1(XVAL) */ 140 fr_SHA1Init(&context); 141 142 memset(zeros, 0, sizeof(zeros)); 143 memcpy(zeros, xval.p, 20); 144 fr_SHA1Transform(&context, zeros); 145 fr_SHA1FinalNoLen(w_1.p, &context); 146 147 /* f. XKEY = (1 + XKEY + w_1) mod 2^160 */ 148 onesixty_add_mod(&sum, &xkey, &w_1); 149 onesixty_add_mod(&xkey, &sum, &one); 150 151 /* now store it away */ 152 memcpy(f, &w_0, 20); 153 f += 20; 154 155 memcpy(f, &w_1, 20); 156 f += 20; 157 } 158} 159 160#ifdef TEST_FIPS186PRF 161/* 162 from RFC4186: A.5. EAP-Request/SIM/Challenge 163 164 Next, the MK is calculated as specified in Section 7*. 165 166 MK = e576d5ca 332e9930 018bf1ba ee2763c7 95b3c712 167 168 And the other keys are derived using the PRNG: 169 170 K_encr = 536e5ebc 4465582a a6a8ec99 86ebb620 171 K_aut = 25af1942 efcbf4bc 72b39434 21f2a974 172 MSK = 39d45aea f4e30601 983e972b 6cfd46d1 173 c3637733 65690d09 cd44976b 525f47d3 174 a60a985e 955c53b0 90b2e4b7 3719196a 175 40254296 8fd14a88 8f46b9a7 886e4488 176 EMSK = 5949eab0 fff69d52 315c6c63 4fd14a7f 177 0d52023d 56f79698 fa6596ab eed4f93f 178 bb48eb53 4d985414 ceed0d9a 8ed33c38 179 7c9dfdab 92ffbdf2 40fcecf6 5a2c93b9 180 */ 181uint8_t mk[20] = { 0xe5, 0x76, 0xd5, 0xca, 182 0x33, 0x2e, 0x99, 0x30, 183 0x01, 0x8b, 0xf1, 0xba, 184 0xee, 0x27, 0x63, 0xc7, 185 0x95, 0xb3, 0xc7, 0x12 }; 186 187uint8_t final_output[160] = { 188 0x53, 0x6e, 0x5e, 0xbc, 0x44, 0x65, 0x58, 0x2a, 0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20, 189 0x25, 0xaf, 0x19, 0x42, 0xef, 0xcb, 0xf4, 0xbc, 0x72, 0xb3, 0x94, 0x34, 0x21, 0xf2, 0xa9, 0x74, 190 0x39, 0xd4, 0x5a, 0xea, 0xf4, 0xe3, 0x06, 0x01, 0x98, 0x3e, 0x97, 0x2b, 0x6c, 0xfd, 0x46, 0xd1, 191 0xc3, 0x63, 0x77, 0x33, 0x65, 0x69, 0x0d, 0x09, 0xcd, 0x44, 0x97, 0x6b, 0x52, 0x5f, 0x47, 0xd3, 192 0xa6, 0x0a, 0x98, 0x5e, 0x95, 0x5c, 0x53, 0xb0, 0x90, 0xb2, 0xe4, 0xb7, 0x37, 0x19, 0x19, 0x6a, 193 0x40, 0x25, 0x42, 0x96, 0x8f, 0xd1, 0x4a, 0x88, 0x8f, 0x46, 0xb9, 0xa7, 0x88, 0x6e, 0x44, 0x88, 194 0x59, 0x49, 0xea, 0xb0, 0xff, 0xf6, 0x9d, 0x52, 0x31, 0x5c, 0x6c, 0x63, 0x4f, 0xd1, 0x4a, 0x7f, 195 0x0d, 0x52, 0x02, 0x3d, 0x56, 0xf7, 0x96, 0x98, 0xfa, 0x65, 0x96, 0xab, 0xee, 0xd4, 0xf9, 0x3f, 196 0xbb, 0x48, 0xeb, 0x53, 0x4d, 0x98, 0x54, 0x14, 0xce, 0xed, 0x0d, 0x9a, 0x8e, 0xd3, 0x3c, 0x38, 197 0x7c, 0x9d, 0xfd, 0xab, 0x92, 0xff, 0xbd, 0xf2, 0x40, 0xfc, 0xec, 0xf6, 0x5a, 0x2c, 0x93, 0xb9, 198}; 199 200int 201main(int argc, char *argv[]) 202{ 203 uint8_t finalkey[160]; 204 int i, j, k; 205 206 fips186_2prf(mk, finalkey); 207 208 printf("Input was: "); 209 j=0; 210 for (i = 0; i < 20; i++) { 211 if(j==4) { 212 printf(" "); 213 j=0; 214 } 215 j++; 216 217 printf("%02x", mk[i]); 218 } 219 220 printf("\nOutput was: "); 221 j=0; k=0; 222 for (i = 0; i < 160; i++) { 223 if(k==16) { 224 printf("\n "); 225 k=0; 226 j=0; 227 } 228 if(j==4) { 229 printf(" "); 230 j=0; 231 } 232 k++; 233 j++; 234 235 printf("%02x", finalkey[i]); 236 } 237 printf("\n"); 238 239 if (bcmp(finalkey, final_output, sizeof(finalkey)) != 0) { 240 fprintf(stderr, "Calculation FAILED\n"); 241 } 242 else { 243 printf("Calculation is correct!\n"); 244 } 245 exit(0); 246 return (0); 247} 248#endif /* TEST_FIPS186PRF */ 249