Resync with broadcom drivers 5.100.138.20 and utilities.
[tomato.git] / release / src-rt / bcmcrypto / passhash.c
blobd8ac4079e7e29d14b2f4dd2f2047319d330c7dc9
1 /*
2 * passhash.c
3 * Perform password to key hash algorithm as defined in WPA and 802.11i
4 * specifications
6 * Copyright (C) 2010, Broadcom Corporation
7 * All Rights Reserved.
8 *
9 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
10 * the contents of this file may not be disclosed to third parties, copied
11 * or duplicated in any form, in whole or in part, without the prior
12 * written permission of Broadcom Corporation.
14 * $Id: passhash.c,v 1.18.230.2 2010-12-01 23:33:28 Exp $
17 #include <bcmcrypto/passhash.h>
18 #include <bcmcrypto/sha1.h>
19 #include <bcmcrypto/prf.h>
21 #ifdef BCMDRIVER
22 #include <osl.h>
23 #else
24 #if defined(__GNUC__)
25 extern void bcopy(const void *src, void *dst, size_t len);
26 extern int bcmp(const void *b1, const void *b2, size_t len);
27 extern void bzero(void *b, size_t len);
28 extern size_t strlen(const char *s);
29 #else
30 #define bcopy(src, dst, len) memcpy((dst), (src), (len))
31 #define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
32 #define bzero(b, len) memset((b), 0, (len))
33 #endif
34 #endif /* BCMDRIVER */
36 #ifdef BCMPASSHASH_TEST
37 #include <stdio.h>
38 void prhash(char *password, int passlen, unsigned char *ssid, int ssidlen, unsigned char *output);
39 #define dbg(args) printf args
40 #endif /* BCMPASSHASH_TEST */
42 /* F(P, S, c, i) = U1 xor U2 xor ... Uc
43 * U1 = PRF(P, S || Int(i)
44 * U2 = PRF(P, U1)
45 * Uc = PRF(P, Uc-1)
47 static void
48 F(char *password, int passlen, unsigned char *ssid, int ssidlength, int iterations, int count,
49 unsigned char *output)
51 unsigned char digest[36], digest1[SHA1HashSize];
52 int i, j;
54 /* U1 = PRF(P, S || int(i)) */
55 if (ssidlength > 32)
56 ssidlength = 32;
57 bcopy(ssid, digest, ssidlength);
58 digest[ssidlength] = (unsigned char)((count>>24) & 0xff);
59 digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff);
60 digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff);
61 digest[ssidlength+3] = (unsigned char)(count & 0xff);
62 hmac_sha1(digest, ssidlength+4, (unsigned char *)password, passlen, digest1);
64 /* output = U1 */
65 bcopy(digest1, output, SHA1HashSize);
67 for (i = 1; i < iterations; i++) {
68 /* Un = PRF(P, Un-1) */
69 hmac_sha1(digest1, SHA1HashSize, (unsigned char *)password, passlen, digest);
70 bcopy(digest, digest1, SHA1HashSize);
72 /* output = output xor Un */
73 for (j = 0; j < SHA1HashSize; j++) {
74 output[j] ^= digest[j];
79 /* passhash: perform passwork->key hash algorithm as defined in WPA and 802.11i
80 * specifications.
81 * password is an ascii string of 8 to 63 characters in length
82 * ssid is up to 32 bytes
83 * ssidlen is the length of ssid in bytes
84 * output must be at lest 40 bytes long, and returns a 256 bit key
85 * returns 0 on success, non-zero on failure
87 int
88 BCMROMFN(passhash)(char *password, int passlen, unsigned char *ssid, int ssidlen,
89 unsigned char *output)
91 if ((strlen(password) < 8) || (strlen(password) > 63) || (ssidlen > 32)) return 1;
93 F(password, passlen, ssid, ssidlen, 4096, 1, output);
94 F(password, passlen, ssid, ssidlen, 4096, 2, &output[SHA1HashSize]);
95 return 0;
98 static void
99 init_F(char *password, int passlen, unsigned char *ssid, int ssidlength,
100 int count, unsigned char *lastdigest, unsigned char *output)
102 unsigned char digest[36];
104 /* U0 = PRF(P, S || int(i)) */
105 /* output = U0 */
106 if (ssidlength > 32)
107 ssidlength = 32;
108 bcopy(ssid, digest, ssidlength);
109 digest[ssidlength] = (unsigned char)((count>>24) & 0xff);
110 digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff);
111 digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff);
112 digest[ssidlength+3] = (unsigned char)(count & 0xff);
113 hmac_sha1(digest, ssidlength+4, (unsigned char *)password, passlen, output);
115 /* Save U0 for next PRF() */
116 bcopy(output, lastdigest, SHA1HashSize);
119 static void
120 do_F(char *password, int passlen, int iterations, unsigned char *lastdigest, unsigned char *output)
122 unsigned char digest[SHA1HashSize];
123 int i, j;
125 for (i = 0; i < iterations; i++) {
126 /* Un = PRF(P, Un-1) */
127 hmac_sha1(lastdigest, SHA1HashSize, (unsigned char *)password, passlen, digest);
128 /* output = output xor Un */
129 for (j = 0; j < SHA1HashSize; j++)
130 output[j] ^= digest[j];
132 /* Save Un for next PRF() */
133 bcopy(digest, lastdigest, SHA1HashSize);
137 /* passhash: Perform passwork to key hash algorithm as defined in WPA and 802.11i
138 * specifications. We are breaking this lengthy process into smaller pieces. Users
139 * are responsible for making sure password length is between 8 and 63 inclusive.
141 * init_passhash: initialize passhash_t structure.
142 * do_passhash: advance states in passhash_t structure and return 0 to indicate
143 * it is done and 1 to indicate more to be done.
144 * get_passhash: copy passhash result to output buffer.
147 init_passhash(passhash_t *ph,
148 char *password, int passlen, unsigned char *ssid, int ssidlen)
150 if (strlen(password) < 8 || strlen(password) > 63)
151 return -1;
153 bzero(ph, sizeof(*ph));
154 ph->count = 1;
155 ph->password = password;
156 ph->passlen = passlen;
157 ph->ssid = ssid;
158 ph->ssidlen = ssidlen;
160 return 0;
164 do_passhash(passhash_t *ph, int iterations)
166 unsigned char *output;
168 if (ph->count > 2)
169 return -1;
170 output = ph->output + SHA1HashSize * (ph->count - 1);
171 if (ph->iters == 0) {
172 init_F(ph->password, ph->passlen, ph->ssid, ph->ssidlen,
173 ph->count, ph->digest, output);
174 ph->iters = 1;
175 iterations --;
177 if (ph->iters + iterations > 4096)
178 iterations = 4096 - ph->iters;
179 do_F(ph->password, ph->passlen, iterations, ph->digest, output);
180 ph->iters += iterations;
181 if (ph->iters == 4096) {
182 ph->count ++;
183 ph->iters = 0;
184 if (ph->count > 2)
185 return 0;
187 return 1;
191 get_passhash(passhash_t *ph, unsigned char *output, int outlen)
193 if (ph->count > 2 && outlen <= (int)sizeof(ph->output)) {
194 bcopy(ph->output, output, outlen);
195 return 0;
197 return -1;
200 #ifdef BCMPASSHASH_TEST
201 void
202 prhash(char *password, int passlen, unsigned char *ssid, int ssidlen, unsigned char *output)
204 int k;
205 printf("pass\n\t%s\nssid(hex)\n\t", password);
206 for (k = 0; k < ssidlen; k++) {
207 printf("%02x ", ssid[k]);
208 if (!((k+1)%16)) printf("\n\t");
210 printf("\nhash\n\t");
211 for (k = 0; k < 2 * SHA1HashSize; k++) {
212 printf("%02x ", output[k]);
213 if (!((k + 1) % SHA1HashSize)) printf("\n\t");
215 printf("\n");
218 #include "passhash_vectors.h"
220 int main(int argc, char **argv)
222 unsigned char output[2*SHA1HashSize];
223 int retv, k, fail = 0, fail1 = 0;
224 passhash_t passhash_states;
226 dbg(("%s: testing passhash()\n", *argv));
228 for (k = 0; k < NUM_PASSHASH_VECTORS; k++) {
229 printf("Passhash test %d:\n", k);
230 bzero(output, sizeof(output));
231 retv = passhash(passhash_vec[k].pass, passhash_vec[k].pl,
232 passhash_vec[k].salt, passhash_vec[k].sl, output);
233 prhash(passhash_vec[k].pass, passhash_vec[k].pl,
234 passhash_vec[k].salt, passhash_vec[k].sl, output);
236 if (retv) {
237 dbg(("%s: passhash() test %d returned error\n", *argv, k));
238 fail++;
240 if (bcmp(output, passhash_vec[k].ref, 2*SHA1HashSize) != 0) {
241 dbg(("%s: passhash test %d reference mismatch\n", *argv, k));
242 fail++;
246 dbg(("%s: %s\n", *argv, fail?"FAILED":"PASSED"));
248 dbg(("%s: testing init_passhash()/do_passhash()/get_passhash()\n", *argv));
250 for (k = 0; k < NUM_PASSHASH_VECTORS; k++) {
251 printf("Passhash test %d:\n", k);
252 init_passhash(&passhash_states,
253 passhash_vec[k].pass, passhash_vec[k].pl,
254 passhash_vec[k].salt, passhash_vec[k].sl);
255 while ((retv = do_passhash(&passhash_states, 100)) > 0)
257 get_passhash(&passhash_states, output, sizeof(output));
258 prhash(passhash_vec[k].pass, passhash_vec[k].pl,
259 passhash_vec[k].salt, passhash_vec[k].sl, output);
261 if (retv < 0) {
262 dbg(("%s: passhash() test %d returned error\n", *argv, k));
263 fail1++;
265 if (bcmp(output, passhash_vec[k].ref, 2*SHA1HashSize) != 0) {
266 dbg(("%s: passhash test %d reference mismatch\n", *argv, k));
267 fail1++;
271 dbg(("%s: %s\n", *argv, fail1?"FAILED":"PASSED"));
272 return (fail+fail1);
274 #endif /* BCMPASSHASH_TEST */