import from HEAD:
[freeradius.git] / src / modules / rlm_eap / libeap / fips186prf.c
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$
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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  *
44  */
45
46 #include "autoconf.h"
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51
52 #ifdef HAVE_SYS_TYPES_H
53 #include <sys/types.h>
54 #endif
55
56 #ifdef HAVE_STDINT_H
57 #include <stdint.h>
58 #endif
59
60 #ifdef HAVE_INTTYPES_H
61 #include <inttypes.h>
62 #endif
63
64 #include "sha1.h"
65
66 /*
67  * we do it in 8-bit chunks, because we have to keep the numbers
68  * in network byte order (i.e. MSB)
69  *
70  * make it a structure so that we can do structure assignments.
71  */
72 typedef struct onesixty {
73         uint8_t p[20];
74 } onesixty;
75
76 static void onesixty_add_mod(onesixty *sum, onesixty *a, onesixty *b)
77 {
78         uint32_t s;
79         int i, carry;
80
81         carry = 0;
82         for(i=19; i>=0; i--) {
83 /*      for(i=0; i<20; i++) {  */
84                 s = a->p[i] + b->p[i] + carry;
85                 sum->p[i] = s & 0xff;
86                 carry = s >> 8;
87         }
88 }
89
90 /*
91  * run the FIPS-186-2 PRF on the given Master Key (160 bits)
92  * in order to derive 1280 bits (160 bytes) of keying data from
93  * it.
94  *
95  * Given that in EAP-SIM, this is coming from a 64-bit Kc it seems
96  * like an awful lot of "randomness" to pull out.. (MCR)
97  *
98  */
99 void fips186_2prf(uint8_t mk[20], uint8_t finalkey[160])
100 {
101         SHA1_CTX context;
102         int j;
103         onesixty xval, xkey, w_0, w_1, sum, one;
104         uint8_t *f;
105         uint8_t zeros[64];
106
107         /*
108          * let XKEY := MK,
109          *
110          * Step 3: For j = 0 to 3 do
111          *   a. XVAL = XKEY
112          *   b. w_0 = SHA1(XVAL)
113          *   c. XKEY = (1 + XKEY + w_0) mod 2^160
114          *   d. XVAL = XKEY
115          *   e. w_1 = SHA1(XVAL)
116          *   f. XKEY = (1 + XKEY + w_1) mod 2^160
117          * 3.3 x_j = w_0|w_1
118          *
119          */
120         memcpy(&xkey, mk, sizeof(xkey));
121
122         /* make the value 1 */
123         memset(&one,  0, sizeof(one));
124         one.p[19]=1;
125
126         f=finalkey;
127
128         for(j=0; j<4; j++) {
129                 /*   a. XVAL = XKEY  */
130                 xval = xkey;
131
132                 /*   b. w_0 = SHA1(XVAL)  */
133                 SHA1Init(&context);
134
135                 memset(zeros, 0, sizeof(zeros));
136                 memcpy(zeros, xval.p, 20);
137                 SHA1Transform(context.state, zeros);
138                 SHA1FinalNoLen(w_0.p, &context);
139
140                 /*   c. XKEY = (1 + XKEY + w_0) mod 2^160 */
141                 onesixty_add_mod(&sum,  &xkey, &w_0);
142                 onesixty_add_mod(&xkey, &sum,  &one);
143
144                 /*   d. XVAL = XKEY  */
145                 xval = xkey;
146
147                 /*   e. w_1 = SHA1(XVAL)  */
148                 SHA1Init(&context);
149
150                 memset(zeros, 0, sizeof(zeros));
151                 memcpy(zeros, xval.p, 20);
152                 SHA1Transform(context.state, zeros);
153                 SHA1FinalNoLen(w_1.p, &context);
154
155                 /*   f. XKEY = (1 + XKEY + w_1) mod 2^160 */
156                 onesixty_add_mod(&sum,  &xkey, &w_1);
157                 onesixty_add_mod(&xkey, &sum,  &one);
158
159                 /* now store it away */
160                 memcpy(f, &w_0, 20);
161                 f += 20;
162
163                 memcpy(f, &w_1, 20);
164                 f += 20;
165         }
166 }
167
168 /*
169  * test vectors
170  * from http://csrc.nist.gov/CryptoToolkit/dss/Examples-1024bit.pdf
171  *
172  * page 5
173  *
174  * XKEY=     bd029bbe 7f51960b cf9edb2b 61f06f0f eb5a38b6
175  * XSEED=    00000000 00000000 00000000 00000000 00000000
176  *
177  *
178  * The first loop through step 3.2 provides:
179  *
180  * XVAL=     bd029bbe 7f51960b cf9edb2b 61f06f0f eb5a38b6
181  *
182  * Using the routine in Appendix 3.3, Constructing The Function G From SHA-1,
183  * in step 3.2.b of the Change Notice algorithm for computing values of x
184  * provides:
185  *
186  * w[0]=     2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614
187  *
188  *
189  * The following value is the updated XKEY value from step 3.2.c:
190  *
191  * XKEY=     dd734ee0 bd0bcd3b adbaeb27 dd1eaa59 76803ecb
192  *
193  * The second loop through step 3.2 provides:
194  *
195  * XVAL=     dd734ee0 bd0bcd3b adbaeb27 dd1eaa59 76803ecb
196  *
197  * Using the routine in Appendix 3.3, Constructing The Function G From SHA-1,
198  * in step 3.2.b of the Change Notice algorithm for computing values of x
199  * provides:
200  *
201  * w[1]=     3c6c18ba cb0f6c55 babb1378 8e20d737 a3275116
202  *
203  * The following value is the updated XKEY value from step 3.2.c:
204  *
205  *
206  * XKEY=     19df679b 881b3991 6875fea0 6b3f8191 19a78fe2
207  *
208  * Step 3.3 provides the following values:
209  *
210  * w[0] || w[1]=  2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614
211  *                3c6c18ba cb0f6c55 babb1378 8e20d737 a3275116
212  *
213  */
214
215 #ifdef TEST_CASE
216
217 #include <assert.h>
218
219 uint8_t mk[20]={ 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
220                   0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
221                   0xeb, 0x5a, 0x38, 0xb6 };
222
223 main(int argc, char *argv[])
224 {
225         uint8_t finalkey[160];
226         int i, j, k;
227
228         fips186_2prf(mk, finalkey);
229
230         printf("Input was: |");
231         j=0;
232         for (i = 0; i < 20; i++) {
233                 if(j==4) {
234                         printf("_");
235                         j=0;
236                 }
237                 j++;
238
239                 printf("%02x", mk[i]);
240         }
241
242         printf("|\nOutput was: ");
243         j=0; k=0;
244         for (i = 0; i < 160; i++) {
245                 if(k==20) {
246                         printf("\n            ");
247                         k=0;
248                         j=0;
249                 }
250                 if(j==4) {
251                         printf("_");
252                         j=0;
253                 }
254                 k++;
255                 j++;
256
257                 printf("%02x", finalkey[i]);
258         }
259         printf("\n");
260 }
261 #endif
262
263
264
265 /*
266  * $Log$
267  * Revision 1.3.2.1.2.1  2006-05-19 14:19:15  nbk
268  *      Don't use rad_assert in libeap, it's a server-only function.
269  *
270  * Revision 1.3.2.1  2005/08/24 14:37:52  nbk
271  *      Fix compilation warnings with gcc 4.0
272  *
273  *      Patch from Steven Simon <simon.s@apple.com>
274  *
275  * Revision 1.3  2004/02/26 19:04:30  aland
276  *      perl -i -npe "s/[ \t]+$//g" `find src -name "*.[ch]" -print`
277  *
278  *      Whitespace changes only, from a fresh checkout.
279  *
280  *      For bug # 13
281  *
282  * Revision 1.2  2003/11/06 15:37:24  aland
283  *      Update includes to work a little better
284  *
285  * Revision 1.1  2003/10/29 02:49:19  mcr
286  *      initial commit of eap-sim
287  *
288  *
289  * Local Variables:
290  * c-style: bsd
291  * End:
292  */