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