blob: b2bbab2b5c320ef656373f358c91383e5e885072 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003 * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "sha1.h"
13#include "ms_funcs.h"
14#include "crypto.h"
15
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080016/**
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 */
25static 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 }
62 }
63 }
64
65 if (ucs2_string_size)
66 *ucs2_string_size = j / 2;
67 return 0;
68}
69
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070070
71/**
72 * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
73 * @peer_challenge: 16-octet PeerChallenge (IN)
74 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
75 * @username: 0-to-256-char UserName (IN)
76 * @username_len: Length of username
77 * @challenge: 8-octet Challenge (OUT)
78 * Returns: 0 on success, -1 on failure
79 */
80static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
81 const u8 *username, size_t username_len,
82 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
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800104 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700105 * @password_len: Length of password
106 * @password_hash: 16-octet PasswordHash (OUT)
107 * Returns: 0 on success, -1 on failure
108 */
109int nt_password_hash(const u8 *password, size_t password_len,
110 u8 *password_hash)
111{
112 u8 buf[512], *pos;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800113 size_t len, max_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700114
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800115 max_len = sizeof(buf);
116 if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
117 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700118
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800119 len *= 2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700120 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 */
131int 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 */
144void challenge_response(const u8 *challenge, const u8 *password_hash,
145 u8 *response)
146{
147 u8 zpwd[7];
148 des_encrypt(challenge, password_hash, response);
149 des_encrypt(challenge, password_hash + 7, response + 8);
150 zpwd[0] = password_hash[14];
151 zpwd[1] = password_hash[15];
152 os_memset(zpwd + 2, 0, 5);
153 des_encrypt(challenge, zpwd, response + 16);
154}
155
156
157/**
158 * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
159 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
160 * @peer_challenge: 16-octet PeerChallenge (IN)
161 * @username: 0-to-256-char UserName (IN)
162 * @username_len: Length of username
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800163 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700164 * @password_len: Length of password
165 * @response: 24-octet Response (OUT)
166 * Returns: 0 on success, -1 on failure
167 */
168int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
169 const u8 *username, size_t username_len,
170 const u8 *password, size_t password_len,
171 u8 *response)
172{
173 u8 challenge[8];
174 u8 password_hash[16];
175
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700176 if (challenge_hash(peer_challenge, auth_challenge, username,
177 username_len, challenge))
178 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700179 if (nt_password_hash(password, password_len, password_hash))
180 return -1;
181 challenge_response(challenge, password_hash, response);
182 return 0;
183}
184
185
186/**
187 * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
188 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
189 * @peer_challenge: 16-octet PeerChallenge (IN)
190 * @username: 0-to-256-char UserName (IN)
191 * @username_len: Length of username
192 * @password_hash: 16-octet PasswordHash (IN)
193 * @response: 24-octet Response (OUT)
194 * Returns: 0 on success, -1 on failure
195 */
196int generate_nt_response_pwhash(const u8 *auth_challenge,
197 const u8 *peer_challenge,
198 const u8 *username, size_t username_len,
199 const u8 *password_hash,
200 u8 *response)
201{
202 u8 challenge[8];
203
204 if (challenge_hash(peer_challenge, auth_challenge,
205 username, username_len,
206 challenge))
207 return -1;
208 challenge_response(challenge, password_hash, response);
209 return 0;
210}
211
212
213/**
214 * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
215 * @password_hash: 16-octet PasswordHash (IN)
216 * @nt_response: 24-octet NT-Response (IN)
217 * @peer_challenge: 16-octet PeerChallenge (IN)
218 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
219 * @username: 0-to-256-char UserName (IN)
220 * @username_len: Length of username
221 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
222 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
223 * Returns: 0 on success, -1 on failure
224 */
225int generate_authenticator_response_pwhash(
226 const u8 *password_hash,
227 const u8 *peer_challenge, const u8 *auth_challenge,
228 const u8 *username, size_t username_len,
229 const u8 *nt_response, u8 *response)
230{
231 static const u8 magic1[39] = {
232 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
233 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
234 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
235 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
236 };
237 static const u8 magic2[41] = {
238 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
239 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
240 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
241 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
242 0x6E
243 };
244
245 u8 password_hash_hash[16], challenge[8];
246 const unsigned char *addr1[3];
247 const size_t len1[3] = { 16, 24, sizeof(magic1) };
248 const unsigned char *addr2[3];
249 const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
250
251 addr1[0] = password_hash_hash;
252 addr1[1] = nt_response;
253 addr1[2] = magic1;
254
255 addr2[0] = response;
256 addr2[1] = challenge;
257 addr2[2] = magic2;
258
259 if (hash_nt_password_hash(password_hash, password_hash_hash))
260 return -1;
261 if (sha1_vector(3, addr1, len1, response))
262 return -1;
263
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700264 if (challenge_hash(peer_challenge, auth_challenge, username,
265 username_len, challenge))
266 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700267 return sha1_vector(3, addr2, len2, response);
268}
269
270
271/**
272 * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800273 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700274 * @password_len: Length of password
275 * @nt_response: 24-octet NT-Response (IN)
276 * @peer_challenge: 16-octet PeerChallenge (IN)
277 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
278 * @username: 0-to-256-char UserName (IN)
279 * @username_len: Length of username
280 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
281 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
282 * Returns: 0 on success, -1 on failure
283 */
284int generate_authenticator_response(const u8 *password, size_t password_len,
285 const u8 *peer_challenge,
286 const u8 *auth_challenge,
287 const u8 *username, size_t username_len,
288 const u8 *nt_response, u8 *response)
289{
290 u8 password_hash[16];
291 if (nt_password_hash(password, password_len, password_hash))
292 return -1;
293 return generate_authenticator_response_pwhash(
294 password_hash, peer_challenge, auth_challenge,
295 username, username_len, nt_response, response);
296}
297
298
299/**
300 * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
301 * @challenge: 8-octet Challenge (IN)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800302 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700303 * @password_len: Length of password
304 * @response: 24-octet Response (OUT)
305 * Returns: 0 on success, -1 on failure
306 */
307int nt_challenge_response(const u8 *challenge, const u8 *password,
308 size_t password_len, u8 *response)
309{
310 u8 password_hash[16];
311 if (nt_password_hash(password, password_len, password_hash))
312 return -1;
313 challenge_response(challenge, password_hash, response);
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 */
325int 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 */
357int 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#define PWBLOCK_LEN 516
420
421/**
422 * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800423 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700424 * @password_len: Length of password
425 * @password_hash: 16-octet PasswordHash (IN)
426 * @pw_block: 516-byte PwBlock (OUT)
427 * Returns: 0 on success, -1 on failure
428 */
429int encrypt_pw_block_with_password_hash(
430 const u8 *password, size_t password_len,
431 const u8 *password_hash, u8 *pw_block)
432{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800433 size_t ucs2_len, offset;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700434 u8 *pos;
435
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800436 os_memset(pw_block, 0, PWBLOCK_LEN);
437
438 if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700439 return -1;
440
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800441 if (ucs2_len > 256)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700442 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800443
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 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700450 /*
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
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800463 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700464 * @new_password_len: Length of new_password
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800465 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700466 * @old_password_len: Length of old_password
467 * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
468 * Returns: 0 on success, -1 on failure
469 */
470int 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
487/**
488 * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
489 * @password_hash: 16-octer PasswordHash (IN)
490 * @block: 16-octet Block (IN)
491 * @cypher: 16-octer Cypher (OUT)
492 */
493void nt_password_hash_encrypted_with_block(const u8 *password_hash,
494 const u8 *block, u8 *cypher)
495{
496 des_encrypt(password_hash, block, cypher);
497 des_encrypt(password_hash + 8, block + 7, cypher + 8);
498}
499
500
501/**
502 * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800503 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700504 * @new_password_len: Length of new_password
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800505 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700506 * @old_password_len: Length of old_password
507 * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
508 * Returns: 0 on success, -1 on failure
509 */
510int old_nt_password_hash_encrypted_with_new_nt_password_hash(
511 const u8 *new_password, size_t new_password_len,
512 const u8 *old_password, size_t old_password_len,
513 u8 *encrypted_password_hash)
514{
515 u8 old_password_hash[16], new_password_hash[16];
516
517 if (nt_password_hash(old_password, old_password_len,
518 old_password_hash) ||
519 nt_password_hash(new_password, new_password_len,
520 new_password_hash))
521 return -1;
522 nt_password_hash_encrypted_with_block(old_password_hash,
523 new_password_hash,
524 encrypted_password_hash);
525 return 0;
526}