Home | History | Annotate | Download | only in crypto
      1 /*
      2  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
      3  * Copyright (c) 2004-2012, Jouni Malinen <j (at) 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  */
     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  */
     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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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