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
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 $
20 #include <bcmcrypto/sha1.h>
21 #include <bcmcrypto/prf.h>
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
);
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))
37 #endif /* BCMDRIVER */
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
;
50 /* if key is longer than 64 bytes reset it to key = SHA1(key) */
54 SHA1Input(&tctx
, key
, key_len
);
55 SHA1Result(&tctx
, key
);
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
++) {
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 */
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
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
)
110 unsigned char input
[PRF_MAX_I_D_LEN
]; /* concatenated input */
111 int currentindex
= 0;
115 if ((prefix_len
+ data_len
+ 1) > PRF_MAX_I_D_LEN
)
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 */
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 */
136 /* faster PRF, inline hmac_sha1 functionality and eliminate redundant
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
];
154 if ((prefix_len
+ data_len
+ 1) > PRF_MAX_I_D_LEN
)
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;
167 /* if key is longer than 64 bytes reset it to key = SHA1(key) */
168 if (key_len
> PRF_MAX_KEY_LEN
) {
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]++;
215 #include "prf_vectors.h"
218 #include <sys/time.h>
220 #endif /* PRF_TIMING */
222 void dprintf(char *label
, uint8
*data
, int dlen
, int status
)
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))
231 printf("\n\t%s\n\n", !status
?"Pass":"Fail");
237 int main(int argc
, char* argv
[])
239 struct timeval tstart
, tend
;
240 unsigned char output
[64 + 20];
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
);
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
);
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
);
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
);
297 int main(int argc
, char* argv
[])
299 unsigned char digest
[20];
300 unsigned char output
[64 + 20];
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
);
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))
316 c
= bcmp(output
, prf_vec
[k
].prf
, 16);
317 dprintf("PRF", output
, 16, c
);
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))
325 c
= bcmp(output
, prf_vec
[k
].prf
, 16);
326 dprintf("fPRF", output
, 16, c
);
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))
334 c
= bcmp(output
, prf_vec
[k
].prf
, 64);
335 dprintf("PRF", output
, 64, c
);
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))
343 c
= bcmp(output
, prf_vec
[k
].prf
, 64);
344 dprintf("fPRF", output
, 64, c
);
349 fprintf(stderr
, "%s: %s\n", *argv
, fail
?"FAILED":"PASSED");
352 #endif /* PRF_TIMING */
353 #endif /* BCMPRF_TEST */