blob: d0d6a96af2bc2c6a6134194fbe8f2fb8b423ab29 [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;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080051 } else if (i == utf8_string_len - 1 ||
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080052 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));
Dmitry Shmidtbd14a572014-02-18 10:33:49 -080061 j += 2;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080062 }
63 }
64 }
65
66 if (ucs2_string_size)
67 *ucs2_string_size = j / 2;
68 return 0;
69}
70
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070071
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 */
Dmitry Shmidtaf9da312015-04-03 10:03:11 -070081int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
82 const u8 *username, size_t username_len, u8 *challenge)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070083{
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,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800177 username_len, challenge) ||
178 nt_password_hash(password, password_len, password_hash))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700179 return -1;
180 challenge_response(challenge, password_hash, response);
181 return 0;
182}
183
184
185/**
186 * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
187 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
188 * @peer_challenge: 16-octet PeerChallenge (IN)
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)
193 * Returns: 0 on success, -1 on failure
194 */
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)
200{
201 u8 challenge[8];
202
203 if (challenge_hash(peer_challenge, auth_challenge,
204 username, username_len,
205 challenge))
206 return -1;
207 challenge_response(challenge, password_hash, response);
208 return 0;
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
221 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
222 * Returns: 0 on success, -1 on failure
223 */
224int generate_authenticator_response_pwhash(
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
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800258 if (hash_nt_password_hash(password_hash, password_hash_hash) ||
259 sha1_vector(3, addr1, len1, response) ||
260 challenge_hash(peer_challenge, auth_challenge, username,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700261 username_len, challenge))
262 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700263 return sha1_vector(3, addr2, len2, response);
264}
265
266
267/**
268 * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800269 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700270 * @password_len: Length of password
271 * @nt_response: 24-octet NT-Response (IN)
272 * @peer_challenge: 16-octet PeerChallenge (IN)
273 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
274 * @username: 0-to-256-char UserName (IN)
275 * @username_len: Length of username
276 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
277 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
278 * Returns: 0 on success, -1 on failure
279 */
280int generate_authenticator_response(const u8 *password, size_t password_len,
281 const u8 *peer_challenge,
282 const u8 *auth_challenge,
283 const u8 *username, size_t username_len,
284 const u8 *nt_response, u8 *response)
285{
286 u8 password_hash[16];
287 if (nt_password_hash(password, password_len, password_hash))
288 return -1;
289 return generate_authenticator_response_pwhash(
290 password_hash, peer_challenge, auth_challenge,
291 username, username_len, nt_response, response);
292}
293
294
295/**
296 * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
297 * @challenge: 8-octet Challenge (IN)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800298 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700299 * @password_len: Length of password
300 * @response: 24-octet Response (OUT)
301 * Returns: 0 on success, -1 on failure
302 */
303int nt_challenge_response(const u8 *challenge, const u8 *password,
304 size_t password_len, u8 *response)
305{
306 u8 password_hash[16];
307 if (nt_password_hash(password, password_len, password_hash))
308 return -1;
309 challenge_response(challenge, password_hash, response);
310 return 0;
311}
312
313
314/**
315 * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
316 * @password_hash_hash: 16-octet PasswordHashHash (IN)
317 * @nt_response: 24-octet NTResponse (IN)
318 * @master_key: 16-octet MasterKey (OUT)
319 * Returns: 0 on success, -1 on failure
320 */
321int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
322 u8 *master_key)
323{
324 static const u8 magic1[27] = {
325 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
326 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
327 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
328 };
329 const unsigned char *addr[3];
330 const size_t len[3] = { 16, 24, sizeof(magic1) };
331 u8 hash[SHA1_MAC_LEN];
332
333 addr[0] = password_hash_hash;
334 addr[1] = nt_response;
335 addr[2] = magic1;
336
337 if (sha1_vector(3, addr, len, hash))
338 return -1;
339 os_memcpy(master_key, hash, 16);
340 return 0;
341}
342
343
344/**
345 * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
346 * @master_key: 16-octet MasterKey (IN)
347 * @session_key: 8-to-16 octet SessionKey (OUT)
348 * @session_key_len: SessionKeyLength (Length of session_key) (IN)
349 * @is_send: IsSend (IN, BOOLEAN)
350 * @is_server: IsServer (IN, BOOLEAN)
351 * Returns: 0 on success, -1 on failure
352 */
353int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
354 size_t session_key_len, int is_send,
355 int is_server)
356{
357 static const u8 magic2[84] = {
358 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
359 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
360 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
361 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
362 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
363 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
364 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
365 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
366 0x6b, 0x65, 0x79, 0x2e
367 };
368 static const u8 magic3[84] = {
369 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
370 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
371 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
372 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
373 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
374 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
375 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
376 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
377 0x6b, 0x65, 0x79, 0x2e
378 };
379 static const u8 shs_pad1[40] = {
380 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
384 };
385
386 static const u8 shs_pad2[40] = {
387 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
388 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
389 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
390 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
391 };
392 u8 digest[SHA1_MAC_LEN];
393 const unsigned char *addr[4];
394 const size_t len[4] = { 16, 40, 84, 40 };
395
396 addr[0] = master_key;
397 addr[1] = shs_pad1;
398 if (is_send) {
399 addr[2] = is_server ? magic3 : magic2;
400 } else {
401 addr[2] = is_server ? magic2 : magic3;
402 }
403 addr[3] = shs_pad2;
404
405 if (sha1_vector(4, addr, len, digest))
406 return -1;
407
408 if (session_key_len > SHA1_MAC_LEN)
409 session_key_len = SHA1_MAC_LEN;
410 os_memcpy(session_key, digest, session_key_len);
411 return 0;
412}
413
414
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800415#ifndef CONFIG_NO_RC4
416
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700417#define PWBLOCK_LEN 516
418
419/**
420 * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800421 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700422 * @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{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800431 size_t ucs2_len, offset;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700432 u8 *pos;
433
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800434 os_memset(pw_block, 0, PWBLOCK_LEN);
435
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800436 if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
437 || ucs2_len > 256)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700438 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800439
440 offset = (256 - ucs2_len) * 2;
441 if (offset != 0) {
442 os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
443 if (os_get_random(pw_block, offset) < 0)
444 return -1;
445 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700446 /*
447 * PasswordLength is 4 octets, but since the maximum password length is
448 * 256, only first two (in little endian byte order) can be non-zero.
449 */
450 pos = &pw_block[2 * 256];
451 WPA_PUT_LE16(pos, password_len * 2);
452 rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
453 return 0;
454}
455
456
457/**
458 * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800459 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700460 * @new_password_len: Length of new_password
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800461 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700462 * @old_password_len: Length of old_password
463 * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
464 * Returns: 0 on success, -1 on failure
465 */
466int new_password_encrypted_with_old_nt_password_hash(
467 const u8 *new_password, size_t new_password_len,
468 const u8 *old_password, size_t old_password_len,
469 u8 *encrypted_pw_block)
470{
471 u8 password_hash[16];
472
473 if (nt_password_hash(old_password, old_password_len, password_hash))
474 return -1;
475 if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
476 password_hash,
477 encrypted_pw_block))
478 return -1;
479 return 0;
480}
481
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800482#endif /* CONFIG_NO_RC4 */
483
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700484
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
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800501 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700502 * @new_password_len: Length of new_password
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800503 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700504 * @old_password_len: Length of old_password
505 * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
506 * Returns: 0 on success, -1 on failure
507 */
508int old_nt_password_hash_encrypted_with_new_nt_password_hash(
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
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;
520 nt_password_hash_encrypted_with_block(old_password_hash,
521 new_password_hash,
522 encrypted_password_hash);
523 return 0;
524}