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