RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / bcmcrypto / passhash.c
blob99479c8983cd6ebe6c34c4cf6addb2009bd79dba
1 /*
2 * passhash.c
3 * Perform password to key hash algorithm as defined in WPA and 802.11i
4 * specifications
6 * Copyright (C) 2012, 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 241182 2011-02-17 21:50:03Z $
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 #include <string.h>
25 #endif /* BCMDRIVER */
27 /* F(P, S, c, i) = U1 xor U2 xor ... Uc
28 * U1 = PRF(P, S || Int(i)
29 * U2 = PRF(P, U1)
30 * Uc = PRF(P, Uc-1)
32 static void
33 F(char *password, int passlen, unsigned char *ssid, int ssidlength, int iterations, int count,
34 unsigned char *output)
36 unsigned char digest[36], digest1[SHA1HashSize];
37 int i, j;
39 /* U1 = PRF(P, S || int(i)) */
40 if (ssidlength > 32)
41 ssidlength = 32;
42 memcpy(digest, ssid, ssidlength);
43 digest[ssidlength] = (unsigned char)((count>>24) & 0xff);
44 digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff);
45 digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff);
46 digest[ssidlength+3] = (unsigned char)(count & 0xff);
47 hmac_sha1(digest, ssidlength+4, (unsigned char *)password, passlen, digest1);
49 /* output = U1 */
50 memcpy(output, digest1, SHA1HashSize);
52 for (i = 1; i < iterations; i++) {
53 /* Un = PRF(P, Un-1) */
54 hmac_sha1(digest1, SHA1HashSize, (unsigned char *)password, passlen, digest);
55 memcpy(digest1, digest, SHA1HashSize);
57 /* output = output xor Un */
58 for (j = 0; j < SHA1HashSize; j++) {
59 output[j] ^= digest[j];
64 /* passhash: perform passwork->key hash algorithm as defined in WPA and 802.11i
65 * specifications.
66 * password is an ascii string of 8 to 63 characters in length
67 * ssid is up to 32 bytes
68 * ssidlen is the length of ssid in bytes
69 * output must be at lest 40 bytes long, and returns a 256 bit key
70 * returns 0 on success, non-zero on failure
72 int
73 BCMROMFN(passhash)(char *password, int passlen, unsigned char *ssid, int ssidlen,
74 unsigned char *output)
76 if ((strlen(password) < 8) || (strlen(password) > 63) || (ssidlen > 32)) return 1;
78 F(password, passlen, ssid, ssidlen, 4096, 1, output);
79 F(password, passlen, ssid, ssidlen, 4096, 2, &output[SHA1HashSize]);
80 return 0;
83 static void
84 init_F(char *password, int passlen, unsigned char *ssid, int ssidlength,
85 int count, unsigned char *lastdigest, unsigned char *output)
87 unsigned char digest[36];
89 /* U0 = PRF(P, S || int(i)) */
90 /* output = U0 */
91 if (ssidlength > 32)
92 ssidlength = 32;
93 memcpy(digest, ssid, ssidlength);
94 digest[ssidlength] = (unsigned char)((count>>24) & 0xff);
95 digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff);
96 digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff);
97 digest[ssidlength+3] = (unsigned char)(count & 0xff);
98 hmac_sha1(digest, ssidlength+4, (unsigned char *)password, passlen, output);
100 /* Save U0 for next PRF() */
101 memcpy(lastdigest, output, SHA1HashSize);
104 static void
105 do_F(char *password, int passlen, int iterations, unsigned char *lastdigest, unsigned char *output)
107 unsigned char digest[SHA1HashSize];
108 int i, j;
110 for (i = 0; i < iterations; i++) {
111 /* Un = PRF(P, Un-1) */
112 hmac_sha1(lastdigest, SHA1HashSize, (unsigned char *)password, passlen, digest);
113 /* output = output xor Un */
114 for (j = 0; j < SHA1HashSize; j++)
115 output[j] ^= digest[j];
117 /* Save Un for next PRF() */
118 memcpy(lastdigest, digest, SHA1HashSize);
122 /* passhash: Perform passwork to key hash algorithm as defined in WPA and 802.11i
123 * specifications. We are breaking this lengthy process into smaller pieces. Users
124 * are responsible for making sure password length is between 8 and 63 inclusive.
126 * init_passhash: initialize passhash_t structure.
127 * do_passhash: advance states in passhash_t structure and return 0 to indicate
128 * it is done and 1 to indicate more to be done.
129 * get_passhash: copy passhash result to output buffer.
132 init_passhash(passhash_t *ph,
133 char *password, int passlen, unsigned char *ssid, int ssidlen)
135 if (strlen(password) < 8 || strlen(password) > 63)
136 return -1;
138 memset(ph, 0, sizeof(*ph));
139 ph->count = 1;
140 ph->password = password;
141 ph->passlen = passlen;
142 ph->ssid = ssid;
143 ph->ssidlen = ssidlen;
145 return 0;
149 do_passhash(passhash_t *ph, int iterations)
151 unsigned char *output;
153 if (ph->count > 2)
154 return -1;
155 output = ph->output + SHA1HashSize * (ph->count - 1);
156 if (ph->iters == 0) {
157 init_F(ph->password, ph->passlen, ph->ssid, ph->ssidlen,
158 ph->count, ph->digest, output);
159 ph->iters = 1;
160 iterations --;
162 if (ph->iters + iterations > 4096)
163 iterations = 4096 - ph->iters;
164 do_F(ph->password, ph->passlen, iterations, ph->digest, output);
165 ph->iters += iterations;
166 if (ph->iters == 4096) {
167 ph->count ++;
168 ph->iters = 0;
169 if (ph->count > 2)
170 return 0;
172 return 1;
176 get_passhash(passhash_t *ph, unsigned char *output, int outlen)
178 if (ph->count > 2 && outlen <= (int)sizeof(ph->output)) {
179 memcpy(output, ph->output, outlen);
180 return 0;
182 return -1;
185 #ifdef BCMPASSHASH_TEST
187 #include <stdio.h>
189 #define dbg(args) printf args
191 void
192 prhash(char *password, int passlen, unsigned char *ssid, int ssidlen, unsigned char *output)
194 int k;
195 printf("pass\n\t%s\nssid(hex)\n\t", password);
196 for (k = 0; k < ssidlen; k++) {
197 printf("%02x ", ssid[k]);
198 if (!((k+1)%16)) printf("\n\t");
200 printf("\nhash\n\t");
201 for (k = 0; k < 2 * SHA1HashSize; k++) {
202 printf("%02x ", output[k]);
203 if (!((k + 1) % SHA1HashSize)) printf("\n\t");
205 printf("\n");
208 #include "passhash_vectors.h"
211 main(int argc, char **argv)
213 unsigned char output[2*SHA1HashSize];
214 int retv, k, fail = 0, fail1 = 0;
215 passhash_t passhash_states;
217 dbg(("%s: testing passhash()\n", *argv));
219 for (k = 0; k < NUM_PASSHASH_VECTORS; k++) {
220 printf("Passhash test %d:\n", k);
221 memset(output, 0, sizeof(output));
222 retv = passhash(passhash_vec[k].pass, passhash_vec[k].pl,
223 passhash_vec[k].salt, passhash_vec[k].sl, output);
224 prhash(passhash_vec[k].pass, passhash_vec[k].pl,
225 passhash_vec[k].salt, passhash_vec[k].sl, output);
227 if (retv) {
228 dbg(("%s: passhash() test %d returned error\n", *argv, k));
229 fail++;
231 if (memcmp(output, passhash_vec[k].ref, 2*SHA1HashSize) != 0) {
232 dbg(("%s: passhash test %d reference mismatch\n", *argv, k));
233 fail++;
237 dbg(("%s: %s\n", *argv, fail?"FAILED":"PASSED"));
239 dbg(("%s: testing init_passhash()/do_passhash()/get_passhash()\n", *argv));
241 for (k = 0; k < NUM_PASSHASH_VECTORS; k++) {
242 printf("Passhash test %d:\n", k);
243 init_passhash(&passhash_states,
244 passhash_vec[k].pass, passhash_vec[k].pl,
245 passhash_vec[k].salt, passhash_vec[k].sl);
246 while ((retv = do_passhash(&passhash_states, 100)) > 0)
248 get_passhash(&passhash_states, output, sizeof(output));
249 prhash(passhash_vec[k].pass, passhash_vec[k].pl,
250 passhash_vec[k].salt, passhash_vec[k].sl, output);
252 if (retv < 0) {
253 dbg(("%s: passhash() test %d returned error\n", *argv, k));
254 fail1++;
256 if (memcmp(output, passhash_vec[k].ref, 2*SHA1HashSize) != 0) {
257 dbg(("%s: passhash test %d reference mismatch\n", *argv, k));
258 fail1++;
262 dbg(("%s: %s\n", *argv, fail1?"FAILED":"PASSED"));
263 return (fail+fail1);
266 #endif /* BCMPASSHASH_TEST */