3 * Perform password to key hash algorithm as defined in WPA and 802.11i
6 * Copyright (C) 2012, Broadcom Corporation
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>
25 #endif /* BCMDRIVER */
27 /* F(P, S, c, i) = U1 xor U2 xor ... Uc
28 * U1 = PRF(P, S || Int(i)
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
];
39 /* U1 = PRF(P, S || int(i)) */
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
);
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
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
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
]);
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)) */
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
);
105 do_F(char *password
, int passlen
, int iterations
, unsigned char *lastdigest
, unsigned char *output
)
107 unsigned char digest
[SHA1HashSize
];
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)
138 memset(ph
, 0, sizeof(*ph
));
140 ph
->password
= password
;
141 ph
->passlen
= passlen
;
143 ph
->ssidlen
= ssidlen
;
149 do_passhash(passhash_t
*ph
, int iterations
)
151 unsigned char *output
;
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
);
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) {
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
);
185 #ifdef BCMPASSHASH_TEST
189 #define dbg(args) printf args
192 prhash(char *password
, int passlen
, unsigned char *ssid
, int ssidlen
, unsigned char *output
)
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");
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
);
228 dbg(("%s: passhash() test %d returned error\n", *argv
, k
));
231 if (memcmp(output
, passhash_vec
[k
].ref
, 2*SHA1HashSize
) != 0) {
232 dbg(("%s: passhash test %d reference mismatch\n", *argv
, k
));
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
);
253 dbg(("%s: passhash() test %d returned error\n", *argv
, k
));
256 if (memcmp(output
, passhash_vec
[k
].ref
, 2*SHA1HashSize
) != 0) {
257 dbg(("%s: passhash test %d reference mismatch\n", *argv
, k
));
262 dbg(("%s: %s\n", *argv
, fail1
?"FAILED":"PASSED"));
266 #endif /* BCMPASSHASH_TEST */