1 /*
2 * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3 * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "sha1.h"
13 #include "ms_funcs.h"
14 #include "crypto.h"
15
16 /**
17 * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
18 * @utf8_string: UTF-8 string (IN)
19 * @utf8_string_len: Length of utf8_string (IN)
20 * @ucs2_buffer: UCS-2 buffer (OUT)
21 * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
22 * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
23 * Returns: 0 on success, -1 on failure
24 */
utf8_to_ucs2(const u8 * utf8_string,size_t utf8_string_len,u8 * ucs2_buffer,size_t ucs2_buffer_size,size_t * ucs2_string_size)25 static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
26 u8 *ucs2_buffer, size_t ucs2_buffer_size,
27 size_t *ucs2_string_size)
28 {
29 size_t i, j;
30
31 for (i = 0, j = 0; i < utf8_string_len; i++) {
32 u8 c = utf8_string[i];
33 if (j >= ucs2_buffer_size) {
34 /* input too long */
35 return -1;
36 }
37 if (c <= 0x7F) {
38 WPA_PUT_LE16(ucs2_buffer + j, c);
39 j += 2;
40 } else if (i == utf8_string_len - 1 ||
41 j >= ucs2_buffer_size - 1) {
42 /* incomplete surrogate */
43 return -1;
44 } else {
45 u8 c2 = utf8_string[++i];
46 if ((c & 0xE0) == 0xC0) {
47 /* two-byte encoding */
48 WPA_PUT_LE16(ucs2_buffer + j,
49 ((c & 0x1F) << 6) | (c2 & 0x3F));
50 j += 2;
51 } else if (i == utf8_string_len ||
52 j >= ucs2_buffer_size - 1) {
53 /* incomplete surrogate */
54 return -1;
55 } else {
56 /* three-byte encoding */
57 u8 c3 = utf8_string[++i];
58 WPA_PUT_LE16(ucs2_buffer + j,
59 ((c & 0xF) << 12) |
60 ((c2 & 0x3F) << 6) | (c3 & 0x3F));
61 j += 2;
62 }
63 }
64 }
65
66 if (ucs2_string_size)
67 *ucs2_string_size = j / 2;
68 return 0;
69 }
70
71
72 /**
73 * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
74 * @peer_challenge: 16-octet PeerChallenge (IN)
75 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
76 * @username: 0-to-256-char UserName (IN)
77 * @username_len: Length of username
78 * @challenge: 8-octet Challenge (OUT)
79 * Returns: 0 on success, -1 on failure
80 */
challenge_hash(const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,u8 * challenge)81 static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
82 const u8 *username, size_t username_len,
83 u8 *challenge)
84 {
85 u8 hash[SHA1_MAC_LEN];
86 const unsigned char *addr[3];
87 size_t len[3];
88
89 addr[0] = peer_challenge;
90 len[0] = 16;
91 addr[1] = auth_challenge;
92 len[1] = 16;
93 addr[2] = username;
94 len[2] = username_len;
95
96 if (sha1_vector(3, addr, len, hash))
97 return -1;
98 os_memcpy(challenge, hash, 8);
99 return 0;
100 }
101
102
103 /**
104 * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
105 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
106 * @password_len: Length of password
107 * @password_hash: 16-octet PasswordHash (OUT)
108 * Returns: 0 on success, -1 on failure
109 */
nt_password_hash(const u8 * password,size_t password_len,u8 * password_hash)110 int nt_password_hash(const u8 *password, size_t password_len,
111 u8 *password_hash)
112 {
113 u8 buf[512], *pos;
114 size_t len, max_len;
115
116 max_len = sizeof(buf);
117 if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
118 return -1;
119
120 len *= 2;
121 pos = buf;
122 return md4_vector(1, (const u8 **) &pos, &len, password_hash);
123 }
124
125
126 /**
127 * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
128 * @password_hash: 16-octet PasswordHash (IN)
129 * @password_hash_hash: 16-octet PasswordHashHash (OUT)
130 * Returns: 0 on success, -1 on failure
131 */
hash_nt_password_hash(const u8 * password_hash,u8 * password_hash_hash)132 int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
133 {
134 size_t len = 16;
135 return md4_vector(1, &password_hash, &len, password_hash_hash);
136 }
137
138
139 /**
140 * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
141 * @challenge: 8-octet Challenge (IN)
142 * @password_hash: 16-octet PasswordHash (IN)
143 * @response: 24-octet Response (OUT)
144 */
challenge_response(const u8 * challenge,const u8 * password_hash,u8 * response)145 void challenge_response(const u8 *challenge, const u8 *password_hash,
146 u8 *response)
147 {
148 u8 zpwd[7];
149 des_encrypt(challenge, password_hash, response);
150 des_encrypt(challenge, password_hash + 7, response + 8);
151 zpwd[0] = password_hash[14];
152 zpwd[1] = password_hash[15];
153 os_memset(zpwd + 2, 0, 5);
154 des_encrypt(challenge, zpwd, response + 16);
155 }
156
157
158 /**
159 * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
160 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
161 * @peer_challenge: 16-octet PeerChallenge (IN)
162 * @username: 0-to-256-char UserName (IN)
163 * @username_len: Length of username
164 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
165 * @password_len: Length of password
166 * @response: 24-octet Response (OUT)
167 * Returns: 0 on success, -1 on failure
168 */
generate_nt_response(const u8 * auth_challenge,const u8 * peer_challenge,const u8 * username,size_t username_len,const u8 * password,size_t password_len,u8 * response)169 int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
170 const u8 *username, size_t username_len,
171 const u8 *password, size_t password_len,
172 u8 *response)
173 {
174 u8 challenge[8];
175 u8 password_hash[16];
176
177 if (challenge_hash(peer_challenge, auth_challenge, username,
178 username_len, challenge))
179 return -1;
180 if (nt_password_hash(password, password_len, password_hash))
181 return -1;
182 challenge_response(challenge, password_hash, response);
183 return 0;
184 }
185
186
187 /**
188 * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
189 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
190 * @peer_challenge: 16-octet PeerChallenge (IN)
191 * @username: 0-to-256-char UserName (IN)
192 * @username_len: Length of username
193 * @password_hash: 16-octet PasswordHash (IN)
194 * @response: 24-octet Response (OUT)
195 * Returns: 0 on success, -1 on failure
196 */
generate_nt_response_pwhash(const u8 * auth_challenge,const u8 * peer_challenge,const u8 * username,size_t username_len,const u8 * password_hash,u8 * response)197 int generate_nt_response_pwhash(const u8 *auth_challenge,
198 const u8 *peer_challenge,
199 const u8 *username, size_t username_len,
200 const u8 *password_hash,
201 u8 *response)
202 {
203 u8 challenge[8];
204
205 if (challenge_hash(peer_challenge, auth_challenge,
206 username, username_len,
207 challenge))
208 return -1;
209 challenge_response(challenge, password_hash, response);
210 return 0;
211 }
212
213
214 /**
215 * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
216 * @password_hash: 16-octet PasswordHash (IN)
217 * @nt_response: 24-octet NT-Response (IN)
218 * @peer_challenge: 16-octet PeerChallenge (IN)
219 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
220 * @username: 0-to-256-char UserName (IN)
221 * @username_len: Length of username
222 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
223 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
224 * Returns: 0 on success, -1 on failure
225 */
generate_authenticator_response_pwhash(const u8 * password_hash,const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,const u8 * nt_response,u8 * response)226 int generate_authenticator_response_pwhash(
227 const u8 *password_hash,
228 const u8 *peer_challenge, const u8 *auth_challenge,
229 const u8 *username, size_t username_len,
230 const u8 *nt_response, u8 *response)
231 {
232 static const u8 magic1[39] = {
233 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
234 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
235 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
236 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
237 };
238 static const u8 magic2[41] = {
239 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
240 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
241 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
242 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
243 0x6E
244 };
245
246 u8 password_hash_hash[16], challenge[8];
247 const unsigned char *addr1[3];
248 const size_t len1[3] = { 16, 24, sizeof(magic1) };
249 const unsigned char *addr2[3];
250 const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
251
252 addr1[0] = password_hash_hash;
253 addr1[1] = nt_response;
254 addr1[2] = magic1;
255
256 addr2[0] = response;
257 addr2[1] = challenge;
258 addr2[2] = magic2;
259
260 if (hash_nt_password_hash(password_hash, password_hash_hash))
261 return -1;
262 if (sha1_vector(3, addr1, len1, response))
263 return -1;
264
265 if (challenge_hash(peer_challenge, auth_challenge, username,
266 username_len, challenge))
267 return -1;
268 return sha1_vector(3, addr2, len2, response);
269 }
270
271
272 /**
273 * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
274 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
275 * @password_len: Length of password
276 * @nt_response: 24-octet NT-Response (IN)
277 * @peer_challenge: 16-octet PeerChallenge (IN)
278 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
279 * @username: 0-to-256-char UserName (IN)
280 * @username_len: Length of username
281 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
282 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
283 * Returns: 0 on success, -1 on failure
284 */
generate_authenticator_response(const u8 * password,size_t password_len,const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,const u8 * nt_response,u8 * response)285 int generate_authenticator_response(const u8 *password, size_t password_len,
286 const u8 *peer_challenge,
287 const u8 *auth_challenge,
288 const u8 *username, size_t username_len,
289 const u8 *nt_response, u8 *response)
290 {
291 u8 password_hash[16];
292 if (nt_password_hash(password, password_len, password_hash))
293 return -1;
294 return generate_authenticator_response_pwhash(
295 password_hash, peer_challenge, auth_challenge,
296 username, username_len, nt_response, response);
297 }
298
299
300 /**
301 * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
302 * @challenge: 8-octet Challenge (IN)
303 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
304 * @password_len: Length of password
305 * @response: 24-octet Response (OUT)
306 * Returns: 0 on success, -1 on failure
307 */
nt_challenge_response(const u8 * challenge,const u8 * password,size_t password_len,u8 * response)308 int nt_challenge_response(const u8 *challenge, const u8 *password,
309 size_t password_len, u8 *response)
310 {
311 u8 password_hash[16];
312 if (nt_password_hash(password, password_len, password_hash))
313 return -1;
314 challenge_response(challenge, password_hash, response);
315 return 0;
316 }
317
318
319 /**
320 * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
321 * @password_hash_hash: 16-octet PasswordHashHash (IN)
322 * @nt_response: 24-octet NTResponse (IN)
323 * @master_key: 16-octet MasterKey (OUT)
324 * Returns: 0 on success, -1 on failure
325 */
get_master_key(const u8 * password_hash_hash,const u8 * nt_response,u8 * master_key)326 int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
327 u8 *master_key)
328 {
329 static const u8 magic1[27] = {
330 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
331 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
332 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
333 };
334 const unsigned char *addr[3];
335 const size_t len[3] = { 16, 24, sizeof(magic1) };
336 u8 hash[SHA1_MAC_LEN];
337
338 addr[0] = password_hash_hash;
339 addr[1] = nt_response;
340 addr[2] = magic1;
341
342 if (sha1_vector(3, addr, len, hash))
343 return -1;
344 os_memcpy(master_key, hash, 16);
345 return 0;
346 }
347
348
349 /**
350 * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
351 * @master_key: 16-octet MasterKey (IN)
352 * @session_key: 8-to-16 octet SessionKey (OUT)
353 * @session_key_len: SessionKeyLength (Length of session_key) (IN)
354 * @is_send: IsSend (IN, BOOLEAN)
355 * @is_server: IsServer (IN, BOOLEAN)
356 * Returns: 0 on success, -1 on failure
357 */
get_asymetric_start_key(const u8 * master_key,u8 * session_key,size_t session_key_len,int is_send,int is_server)358 int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
359 size_t session_key_len, int is_send,
360 int is_server)
361 {
362 static const u8 magic2[84] = {
363 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
364 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
365 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
366 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
367 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
368 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
369 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
370 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
371 0x6b, 0x65, 0x79, 0x2e
372 };
373 static const u8 magic3[84] = {
374 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
375 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
376 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
377 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
378 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
379 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
380 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
381 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
382 0x6b, 0x65, 0x79, 0x2e
383 };
384 static const u8 shs_pad1[40] = {
385 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
389 };
390
391 static const u8 shs_pad2[40] = {
392 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
393 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
394 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
395 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
396 };
397 u8 digest[SHA1_MAC_LEN];
398 const unsigned char *addr[4];
399 const size_t len[4] = { 16, 40, 84, 40 };
400
401 addr[0] = master_key;
402 addr[1] = shs_pad1;
403 if (is_send) {
404 addr[2] = is_server ? magic3 : magic2;
405 } else {
406 addr[2] = is_server ? magic2 : magic3;
407 }
408 addr[3] = shs_pad2;
409
410 if (sha1_vector(4, addr, len, digest))
411 return -1;
412
413 if (session_key_len > SHA1_MAC_LEN)
414 session_key_len = SHA1_MAC_LEN;
415 os_memcpy(session_key, digest, session_key_len);
416 return 0;
417 }
418
419
420 #define PWBLOCK_LEN 516
421
422 /**
423 * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
424 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
425 * @password_len: Length of password
426 * @password_hash: 16-octet PasswordHash (IN)
427 * @pw_block: 516-byte PwBlock (OUT)
428 * Returns: 0 on success, -1 on failure
429 */
encrypt_pw_block_with_password_hash(const u8 * password,size_t password_len,const u8 * password_hash,u8 * pw_block)430 int encrypt_pw_block_with_password_hash(
431 const u8 *password, size_t password_len,
432 const u8 *password_hash, u8 *pw_block)
433 {
434 size_t ucs2_len, offset;
435 u8 *pos;
436
437 os_memset(pw_block, 0, PWBLOCK_LEN);
438
439 if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
440 return -1;
441
442 if (ucs2_len > 256)
443 return -1;
444
445 offset = (256 - ucs2_len) * 2;
446 if (offset != 0) {
447 os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
448 if (os_get_random(pw_block, offset) < 0)
449 return -1;
450 }
451 /*
452 * PasswordLength is 4 octets, but since the maximum password length is
453 * 256, only first two (in little endian byte order) can be non-zero.
454 */
455 pos = &pw_block[2 * 256];
456 WPA_PUT_LE16(pos, password_len * 2);
457 rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
458 return 0;
459 }
460
461
462 /**
463 * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
464 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
465 * @new_password_len: Length of new_password
466 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
467 * @old_password_len: Length of old_password
468 * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
469 * Returns: 0 on success, -1 on failure
470 */
new_password_encrypted_with_old_nt_password_hash(const u8 * new_password,size_t new_password_len,const u8 * old_password,size_t old_password_len,u8 * encrypted_pw_block)471 int new_password_encrypted_with_old_nt_password_hash(
472 const u8 *new_password, size_t new_password_len,
473 const u8 *old_password, size_t old_password_len,
474 u8 *encrypted_pw_block)
475 {
476 u8 password_hash[16];
477
478 if (nt_password_hash(old_password, old_password_len, password_hash))
479 return -1;
480 if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
481 password_hash,
482 encrypted_pw_block))
483 return -1;
484 return 0;
485 }
486
487
488 /**
489 * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
490 * @password_hash: 16-octer PasswordHash (IN)
491 * @block: 16-octet Block (IN)
492 * @cypher: 16-octer Cypher (OUT)
493 */
nt_password_hash_encrypted_with_block(const u8 * password_hash,const u8 * block,u8 * cypher)494 void nt_password_hash_encrypted_with_block(const u8 *password_hash,
495 const u8 *block, u8 *cypher)
496 {
497 des_encrypt(password_hash, block, cypher);
498 des_encrypt(password_hash + 8, block + 7, cypher + 8);
499 }
500
501
502 /**
503 * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
504 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
505 * @new_password_len: Length of new_password
506 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
507 * @old_password_len: Length of old_password
508 * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
509 * Returns: 0 on success, -1 on failure
510 */
old_nt_password_hash_encrypted_with_new_nt_password_hash(const u8 * new_password,size_t new_password_len,const u8 * old_password,size_t old_password_len,u8 * encrypted_password_hash)511 int old_nt_password_hash_encrypted_with_new_nt_password_hash(
512 const u8 *new_password, size_t new_password_len,
513 const u8 *old_password, size_t old_password_len,
514 u8 *encrypted_password_hash)
515 {
516 u8 old_password_hash[16], new_password_hash[16];
517
518 if (nt_password_hash(old_password, old_password_len,
519 old_password_hash) ||
520 nt_password_hash(new_password, new_password_len,
521 new_password_hash))
522 return -1;
523 nt_password_hash_encrypted_with_block(old_password_hash,
524 new_password_hash,
525 encrypted_password_hash);
526 return 0;
527 }
528