/* * fips186prf.c An implementation of the FIPS-186-2 SHA1-based PRF. * * The development of the EAP/SIM support was funded by Internet Foundation * Austria (http://www.nic.at/ipa). * * This code was written from scratch by Michael Richardson, and it is * dual licensed under both GPL and BSD. * * Version: $Id: fips186prf.c,v 1.12 2008/06/05 12:17:33 aland Exp $ * * GPL notice: * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * BSD notice: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca> * Copyright 2006 The FreeRADIUS server project * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <stdint.h> #include "fr_sha1.h" #include "fips186prf.h" /* * we do it in 8-bit chunks, because we have to keep the numbers * in network byte order (i.e. MSB) * * make it a structure so that we can do structure assignments. */ typedef struct onesixty { uint8_t p[20]; } onesixty; static void onesixty_add_mod(onesixty *sum, onesixty *a, onesixty *b) { uint32_t s; int i, carry; carry = 0; for(i=19; i>=0; i--) { /* for(i=0; i<20; i++) { */ s = a->p[i] + b->p[i] + carry; sum->p[i] = s & 0xff; carry = s >> 8; } } /* * run the FIPS-186-2 PRF on the given Master Key (160 bits) * in order to derive 1280 bits (160 bytes) of keying data from * it. * * Given that in EAP-SIM, this is coming from a 64-bit Kc it seems * like an awful lot of "randomness" to pull out.. (MCR) * */ __private_extern__ void fips186_2prf(uint8_t mk[20], uint8_t finalkey[160]) { fr_SHA1_CTX context; int j; onesixty xval, xkey, w_0, w_1, sum, one; uint8_t *f; uint8_t zeros[64]; /* * let XKEY := MK, * * Step 3: For j = 0 to 3 do * a. XVAL = XKEY * b. w_0 = SHA1(XVAL) * c. XKEY = (1 + XKEY + w_0) mod 2^160 * d. XVAL = XKEY * e. w_1 = SHA1(XVAL) * f. XKEY = (1 + XKEY + w_1) mod 2^160 * 3.3 x_j = w_0|w_1 * */ memcpy(&xkey, mk, sizeof(xkey)); /* make the value 1 */ memset(&one, 0, sizeof(one)); one.p[19]=1; f=finalkey; for(j=0; j<4; j++) { /* a. XVAL = XKEY */ xval = xkey; /* b. w_0 = SHA1(XVAL) */ fr_SHA1Init(&context); memset(zeros, 0, sizeof(zeros)); memcpy(zeros, xval.p, 20); fr_SHA1Transform(&context, zeros); fr_SHA1FinalNoLen(w_0.p, &context); /* c. XKEY = (1 + XKEY + w_0) mod 2^160 */ onesixty_add_mod(&sum, &xkey, &w_0); onesixty_add_mod(&xkey, &sum, &one); /* d. XVAL = XKEY */ xval = xkey; /* e. w_1 = SHA1(XVAL) */ fr_SHA1Init(&context); memset(zeros, 0, sizeof(zeros)); memcpy(zeros, xval.p, 20); fr_SHA1Transform(&context, zeros); fr_SHA1FinalNoLen(w_1.p, &context); /* f. XKEY = (1 + XKEY + w_1) mod 2^160 */ onesixty_add_mod(&sum, &xkey, &w_1); onesixty_add_mod(&xkey, &sum, &one); /* now store it away */ memcpy(f, &w_0, 20); f += 20; memcpy(f, &w_1, 20); f += 20; } } #ifdef TEST_FIPS186PRF /* from RFC4186: A.5. EAP-Request/SIM/Challenge Next, the MK is calculated as specified in Section 7*. MK = e576d5ca 332e9930 018bf1ba ee2763c7 95b3c712 And the other keys are derived using the PRNG: K_encr = 536e5ebc 4465582a a6a8ec99 86ebb620 K_aut = 25af1942 efcbf4bc 72b39434 21f2a974 MSK = 39d45aea f4e30601 983e972b 6cfd46d1 c3637733 65690d09 cd44976b 525f47d3 a60a985e 955c53b0 90b2e4b7 3719196a 40254296 8fd14a88 8f46b9a7 886e4488 EMSK = 5949eab0 fff69d52 315c6c63 4fd14a7f 0d52023d 56f79698 fa6596ab eed4f93f bb48eb53 4d985414 ceed0d9a 8ed33c38 7c9dfdab 92ffbdf2 40fcecf6 5a2c93b9 */ uint8_t mk[20] = { 0xe5, 0x76, 0xd5, 0xca, 0x33, 0x2e, 0x99, 0x30, 0x01, 0x8b, 0xf1, 0xba, 0xee, 0x27, 0x63, 0xc7, 0x95, 0xb3, 0xc7, 0x12 }; uint8_t final_output[160] = { 0x53, 0x6e, 0x5e, 0xbc, 0x44, 0x65, 0x58, 0x2a, 0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20, 0x25, 0xaf, 0x19, 0x42, 0xef, 0xcb, 0xf4, 0xbc, 0x72, 0xb3, 0x94, 0x34, 0x21, 0xf2, 0xa9, 0x74, 0x39, 0xd4, 0x5a, 0xea, 0xf4, 0xe3, 0x06, 0x01, 0x98, 0x3e, 0x97, 0x2b, 0x6c, 0xfd, 0x46, 0xd1, 0xc3, 0x63, 0x77, 0x33, 0x65, 0x69, 0x0d, 0x09, 0xcd, 0x44, 0x97, 0x6b, 0x52, 0x5f, 0x47, 0xd3, 0xa6, 0x0a, 0x98, 0x5e, 0x95, 0x5c, 0x53, 0xb0, 0x90, 0xb2, 0xe4, 0xb7, 0x37, 0x19, 0x19, 0x6a, 0x40, 0x25, 0x42, 0x96, 0x8f, 0xd1, 0x4a, 0x88, 0x8f, 0x46, 0xb9, 0xa7, 0x88, 0x6e, 0x44, 0x88, 0x59, 0x49, 0xea, 0xb0, 0xff, 0xf6, 0x9d, 0x52, 0x31, 0x5c, 0x6c, 0x63, 0x4f, 0xd1, 0x4a, 0x7f, 0x0d, 0x52, 0x02, 0x3d, 0x56, 0xf7, 0x96, 0x98, 0xfa, 0x65, 0x96, 0xab, 0xee, 0xd4, 0xf9, 0x3f, 0xbb, 0x48, 0xeb, 0x53, 0x4d, 0x98, 0x54, 0x14, 0xce, 0xed, 0x0d, 0x9a, 0x8e, 0xd3, 0x3c, 0x38, 0x7c, 0x9d, 0xfd, 0xab, 0x92, 0xff, 0xbd, 0xf2, 0x40, 0xfc, 0xec, 0xf6, 0x5a, 0x2c, 0x93, 0xb9, }; int main(int argc, char *argv[]) { uint8_t finalkey[160]; int i, j, k; fips186_2prf(mk, finalkey); printf("Input was: "); j=0; for (i = 0; i < 20; i++) { if(j==4) { printf(" "); j=0; } j++; printf("%02x", mk[i]); } printf("\nOutput was: "); j=0; k=0; for (i = 0; i < 160; i++) { if(k==16) { printf("\n "); k=0; j=0; } if(j==4) { printf(" "); j=0; } k++; j++; printf("%02x", finalkey[i]); } printf("\n"); if (bcmp(finalkey, final_output, sizeof(finalkey)) != 0) { fprintf(stderr, "Calculation FAILED\n"); } else { printf("Calculation is correct!\n"); } exit(0); return (0); } #endif /* TEST_FIPS186PRF */