3 * Perform password to key hash algorithm as defined in WPA and 802.11i
6 * Copyright (C) 2010, 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,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>
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
);
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))
34 #endif /* BCMDRIVER */
36 #ifdef BCMPASSHASH_TEST
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)
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
];
54 /* U1 = PRF(P, S || int(i)) */
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
);
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
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
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
]);
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)) */
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
);
120 do_F(char *password
, int passlen
, int iterations
, unsigned char *lastdigest
, unsigned char *output
)
122 unsigned char digest
[SHA1HashSize
];
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)
153 bzero(ph
, sizeof(*ph
));
155 ph
->password
= password
;
156 ph
->passlen
= passlen
;
158 ph
->ssidlen
= ssidlen
;
164 do_passhash(passhash_t
*ph
, int iterations
)
166 unsigned char *output
;
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
);
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) {
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
);
200 #ifdef BCMPASSHASH_TEST
202 prhash(char *password
, int passlen
, unsigned char *ssid
, int ssidlen
, unsigned char *output
)
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");
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
);
237 dbg(("%s: passhash() test %d returned error\n", *argv
, k
));
240 if (bcmp(output
, passhash_vec
[k
].ref
, 2*SHA1HashSize
) != 0) {
241 dbg(("%s: passhash test %d reference mismatch\n", *argv
, k
));
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
);
262 dbg(("%s: passhash() test %d returned error\n", *argv
, k
));
265 if (bcmp(output
, passhash_vec
[k
].ref
, 2*SHA1HashSize
) != 0) {
266 dbg(("%s: passhash test %d reference mismatch\n", *argv
, k
));
271 dbg(("%s: %s\n", *argv
, fail1
?"FAILED":"PASSED"));
274 #endif /* BCMPASSHASH_TEST */