Resync with broadcom drivers 5.100.138.20 and utilities.
[tomato.git] / release / src-rt / bcmcrypto / prf.c
blob90c265d44d0162121202f8acd557faaa999a7972
1 /*
2 * prf.c
3 * Pseudo-ranom function used by WPA and TGi
5 * Original implementation of hmac_sha1(), PRF(), and test vectors data are
6 * from "SSN for 802.11-0.21.doc"
8 * Copyright (C) 2010, Broadcom Corporation
9 * All Rights Reserved.
11 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
12 * the contents of this file may not be disclosed to third parties, copied
13 * or duplicated in any form, in whole or in part, without the prior
14 * written permission of Broadcom Corporation.
16 * $Id: prf.c,v 1.18 2006-06-15 02:17:55 Exp $
19 #include <typedefs.h>
20 #include <bcmcrypto/sha1.h>
21 #include <bcmcrypto/prf.h>
25 #ifdef BCMDRIVER
26 #include <osl.h>
27 #else
28 #if defined(__GNUC__)
29 extern void bcopy(const void *src, void *dst, int len);
30 extern int bcmp(const void *b1, const void *b2, int len);
31 extern void bzero(void *b, int len);
32 #else
33 #define bcopy(src, dst, len) memcpy((dst), (src), (len))
34 #define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
35 #define bzero(b, len) memset((b), 0, (len))
36 #endif /* __GNUC__ */
37 #endif /* BCMDRIVER */
39 void
40 BCMROMFN(hmac_sha1)(unsigned char *text, int text_len, unsigned char *key,
41 int key_len, unsigned char *digest)
43 SHA1Context icontext, ocontext;
44 uint32 pki[(PRF_MAX_KEY_LEN / sizeof(uint32)) + 1];
45 uint32 pko[(PRF_MAX_KEY_LEN / sizeof(uint32)) + 1];
46 uint8 *k_ipad = (uint8 *)pki;
47 uint8 *k_opad = (uint8 *)pko;
48 int i;
50 /* if key is longer than 64 bytes reset it to key = SHA1(key) */
51 if (key_len > 64) {
52 SHA1Context tctx;
53 SHA1Reset(&tctx);
54 SHA1Input(&tctx, key, key_len);
55 SHA1Result(&tctx, key);
56 key_len = 20;
60 * the HMAC_SHA1 transform looks like:
62 * SHA1(K XOR opad, SHA1(K XOR ipad, text))
64 * where K is an n byte key
65 * ipad is the byte 0x36 repeated 64 times
66 * opad is the byte 0x5c repeated 64 times
67 * and text is the data being protected
70 /* start out by storing key in pads */
71 bcopy(key, k_ipad, key_len);
72 bzero(&k_ipad[key_len], PRF_MAX_KEY_LEN + 1 - key_len);
73 bcopy(k_ipad, k_opad, PRF_MAX_KEY_LEN + 1);
75 /* XOR key with ipad and opad values */
76 for (i = 0; i < 16; i++) {
77 pki[i] ^= 0x36363636;
78 pko[i] ^= 0x5c5c5c5c;
80 /* init contexts */
81 SHA1Reset(&icontext);
82 bcopy(&icontext, &ocontext, sizeof(icontext));
84 /* perform inner SHA1 */
85 SHA1Input(&icontext, k_ipad, 64); /* start with inner pad */
86 SHA1Input(&icontext, text, text_len); /* then text of datagram */
87 SHA1Result(&icontext, digest); /* finish up 1st pass */
89 /* perform outer SHA1 */
90 SHA1Input(&ocontext, k_opad, 64); /* start with outer pad */
91 SHA1Input(&ocontext, digest, 20); /* then results of 1st hash */
92 SHA1Result(&ocontext, digest); /* finish up 2nd pass */
95 /* PRF
96 * Length of output is in octets rather than bits
97 * since length is always a multiple of 8
98 * output array is organized so first N octets starting from 0
99 * contains PRF output
101 * supported inputs are 16, 32, 48, 64
102 * output array must be 80 octets in size to allow for sha1 overflow
105 BCMROMFN(PRF)(unsigned char *key, int key_len, unsigned char *prefix,
106 int prefix_len, unsigned char *data, int data_len,
107 unsigned char *output, int len)
109 int i;
110 unsigned char input[PRF_MAX_I_D_LEN]; /* concatenated input */
111 int currentindex = 0;
112 int total_len;
113 int data_offset = 0;
115 if ((prefix_len + data_len + 1) > PRF_MAX_I_D_LEN)
116 return (-1);
118 if (prefix_len != 0) {
119 bcopy(prefix, input, prefix_len);
120 input[prefix_len] = 0; /* single octet 0 */
121 data_offset = prefix_len + 1;
123 bcopy(data, &input[data_offset], data_len);
124 total_len = data_offset + data_len;
125 input[total_len] = 0; /* single octet count, starts at 0 */
126 total_len++;
127 for (i = 0; i < (len + 19) / 20; i++) {
128 hmac_sha1(input, total_len, key, key_len, &output[currentindex]);
129 currentindex += 20; /* next concatenation location */
130 input[total_len-1]++; /* increment octet count */
132 return (0);
136 /* faster PRF, inline hmac_sha1 functionality and eliminate redundant
137 * initilizations
140 BCMROMFN(fPRF)(unsigned char *key, int key_len, unsigned char *prefix,
141 int prefix_len, unsigned char *data, int data_len,
142 unsigned char *output, int len)
144 uint32 pki32[(PRF_MAX_KEY_LEN / sizeof(uint32)) + 1];
145 uint32 pko32[(PRF_MAX_KEY_LEN / sizeof(uint32)) + 1];
146 uint8 *pki8 = (uint8 *)pki32;
147 uint8 *pko8 = (uint8 *)pko32;
149 SHA1Context reficontext, refocontext, icontext, ocontext;
150 int i, total_len, currentindex = 0;
151 uint8 input[PRF_MAX_I_D_LEN];
152 int data_offset = 0;
154 if ((prefix_len + data_len + 1) > PRF_MAX_I_D_LEN)
155 return (-1);
157 if (prefix_len != 0) {
158 bcopy(prefix, input, prefix_len);
159 input[prefix_len] = 0;
160 data_offset = prefix_len + 1;
162 bcopy(data, &input[data_offset], data_len);
163 total_len = data_offset + data_len;
164 input[total_len] = 0;
165 total_len++;
167 /* if key is longer than 64 bytes reset it to key = SHA1(key) */
168 if (key_len > PRF_MAX_KEY_LEN) {
169 SHA1Context tctx;
170 SHA1Reset(&tctx);
171 SHA1Input(&tctx, key, key_len);
172 SHA1Result(&tctx, key);
173 key_len = SHA1HashSize;
176 /* store key in pads */
177 bcopy(key, pki8, key_len);
178 bzero(&pki8[key_len], PRF_MAX_KEY_LEN + 1 - key_len);
179 bcopy(pki8, pko8, PRF_MAX_KEY_LEN + 1);
181 /* XOR key with ipad and opad values */
182 for (i = 0; i < PRF_MAX_KEY_LEN / 4; i++) {
183 pki32[i] ^= 0x36363636;
184 pko32[i] ^= 0x5c5c5c5c;
187 /* init reference contexts */
188 SHA1Reset(&reficontext);
189 bcopy(&reficontext, &refocontext, sizeof(reficontext));
190 SHA1Input(&reficontext, pki8, PRF_MAX_KEY_LEN);
191 SHA1Input(&refocontext, pko8, PRF_MAX_KEY_LEN);
193 for (i = 0; i < (len + SHA1HashSize - 1) / SHA1HashSize; i++) {
194 /* copy reference context to working copies */
195 bcopy(&reficontext, &icontext, sizeof(reficontext));
196 bcopy(&refocontext, &ocontext, sizeof(refocontext));
198 /* perform inner SHA1 */
199 SHA1Input(&icontext, input, total_len);
200 SHA1Result(&icontext, &output[currentindex]);
202 /* perform outer SHA1 */
203 SHA1Input(&ocontext, &output[currentindex], SHA1HashSize);
204 SHA1Result(&ocontext, &output[currentindex]);
206 currentindex += SHA1HashSize;
207 input[total_len-1]++;
210 return (0);
213 #ifdef BCMPRF_TEST
214 #include <stdio.h>
215 #include "prf_vectors.h"
217 #ifdef PRF_TIMING
218 #include <sys/time.h>
219 #include <stdlib.h>
220 #endif /* PRF_TIMING */
222 void dprintf(char *label, uint8 *data, int dlen, int status)
224 int j;
225 printf("%s:\n\t", label);
226 for (j = 0; j < dlen; j++) {
227 printf("%02x ", data[j]);
228 if ((j < dlen - 1) && !((j + 1) % 16))
229 printf("\n\t");
231 printf("\n\t%s\n\n", !status?"Pass":"Fail");
234 #ifdef PRF_TIMING
235 #define NITER 10000
237 int main(int argc, char* argv[])
239 struct timeval tstart, tend;
240 unsigned char output[64 + 20];
241 int32 usec;
242 int j;
244 bzero(output, 64);
245 if (gettimeofday(&tstart, NULL)) exit(1);
246 for (j = 0; j < NITER; j++) {
247 fPRF(prf_vec[0].key, prf_vec[0].key_len, (unsigned char *)"prefix",
248 6, prf_vec[0].data, prf_vec[0].data_len, output, 64);
250 if (gettimeofday(&tend, NULL)) exit(1);
251 dprintf("fPRF", output, 64, 0);
252 usec = tend.tv_usec - tstart.tv_usec;
253 usec += 1000000 * (tend.tv_sec - tstart.tv_sec);
254 printf("usec %d\n", usec);
256 bzero(output, 64);
257 if (gettimeofday(&tstart, NULL)) exit(1);
258 for (j = 0; j < NITER; j++) {
259 PRF(prf_vec[0].key, prf_vec[0].key_len, (unsigned char *)"prefix",
260 6, prf_vec[0].data, prf_vec[0].data_len, output, 64);
262 if (gettimeofday(&tend, NULL)) exit(1);
263 dprintf("PRF", output, 64, 0);
264 usec = tend.tv_usec - tstart.tv_usec;
265 usec += 1000000 * (tend.tv_sec - tstart.tv_sec);
266 printf("usec %d\n", usec);
268 bzero(output, 64);
269 if (gettimeofday(&tstart, NULL)) exit(1);
270 for (j = 0; j < NITER; j++) {
271 fPRF(prf_vec[0].key, prf_vec[0].key_len, (unsigned char *)"prefix",
272 6, prf_vec[0].data, prf_vec[0].data_len, output, 64);
274 if (gettimeofday(&tend, NULL)) exit(1);
275 dprintf("fPRF", output, 64, 0);
276 usec = tend.tv_usec - tstart.tv_usec;
277 usec += 1000000 * (tend.tv_sec - tstart.tv_sec);
278 printf("usec %d\n", usec);
280 bzero(output, 64);
281 if (gettimeofday(&tstart, NULL)) exit(1);
282 for (j = 0; j < NITER; j++) {
283 PRF(prf_vec[0].key, prf_vec[0].key_len, (unsigned char *)"prefix",
284 6, prf_vec[0].data, prf_vec[0].data_len, output, 64);
286 if (gettimeofday(&tend, NULL)) exit(1);
287 dprintf("PRF", output, 64, 0);
288 usec = tend.tv_usec - tstart.tv_usec;
289 usec += 1000000 * (tend.tv_sec - tstart.tv_sec);
290 printf("usec %d\n", usec);
292 return (0);
295 #else
297 int main(int argc, char* argv[])
299 unsigned char digest[20];
300 unsigned char output[64 + 20];
301 int k, c, fail = 0;
303 for (k = 0; k < NUM_VECTORS; k++) {
304 printf("Test Vector %d:\n", k);
305 hmac_sha1(prf_vec[k].data, prf_vec[k].data_len, prf_vec[k].key,
306 prf_vec[k].key_len, digest);
307 c = bcmp(digest, prf_vec[k].digest1, 20);
308 dprintf("HMAC_SHA1", digest, 20, c);
309 if (c) fail++;
311 bzero(output, 64);
312 if (PRF(prf_vec[k].key, prf_vec[k].key_len,
313 prf_vec[k].prefix, prf_vec[k].prefix_len,
314 prf_vec[k].data, prf_vec[k].data_len, output, 16))
315 fail++;
316 c = bcmp(output, prf_vec[k].prf, 16);
317 dprintf("PRF", output, 16, c);
318 if (c) fail++;
320 bzero(output, 64);
321 if (fPRF(prf_vec[k].key, prf_vec[k].key_len,
322 prf_vec[k].prefix, prf_vec[k].prefix_len,
323 prf_vec[k].data, prf_vec[k].data_len, output, 16))
324 fail++;
325 c = bcmp(output, prf_vec[k].prf, 16);
326 dprintf("fPRF", output, 16, c);
327 if (c) fail++;
329 bzero(output, 64);
330 if (PRF(prf_vec[k].key, prf_vec[k].key_len,
331 prf_vec[k].prefix, prf_vec[k].prefix_len,
332 prf_vec[k].data, prf_vec[k].data_len, output, 64))
333 fail++;
334 c = bcmp(output, prf_vec[k].prf, 64);
335 dprintf("PRF", output, 64, c);
336 if (c) fail++;
338 bzero(output, 64);
339 if (fPRF(prf_vec[k].key, prf_vec[k].key_len,
340 prf_vec[k].prefix, prf_vec[k].prefix_len,
341 prf_vec[k].data, prf_vec[k].data_len, output, 64))
342 fail++;
343 c = bcmp(output, prf_vec[k].prf, 64);
344 dprintf("fPRF", output, 64, c);
345 if (c) fail++;
349 fprintf(stderr, "%s: %s\n", *argv, fail?"FAILED":"PASSED");
350 return (fail);
352 #endif /* PRF_TIMING */
353 #endif /* BCMPRF_TEST */