18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "sha1.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ms_funcs.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/**
171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @utf8_string: UTF-8 string (IN)
191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @utf8_string_len: Length of utf8_string (IN)
201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @ucs2_buffer: UCS-2 buffer (OUT)
211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Returns: 0 on success, -1 on failure
241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */
251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt                        u8 *ucs2_buffer, size_t ucs2_buffer_size,
271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt                        size_t *ucs2_string_size)
281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t i, j;
301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (i = 0, j = 0; i < utf8_string_len; i++) {
321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		u8 c = utf8_string[i];
331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (j >= ucs2_buffer_size) {
341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			/* input too long */
351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return -1;
361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (c <= 0x7F) {
381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			WPA_PUT_LE16(ucs2_buffer + j, c);
391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			j += 2;
401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else if (i == utf8_string_len - 1 ||
411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   j >= ucs2_buffer_size - 1) {
421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			/* incomplete surrogate */
431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return -1;
441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else {
451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			u8 c2 = utf8_string[++i];
461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if ((c & 0xE0) == 0xC0) {
471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				/* two-byte encoding */
481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				WPA_PUT_LE16(ucs2_buffer + j,
491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     ((c & 0x1F) << 6) | (c2 & 0x3F));
501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				j += 2;
511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			} else if (i == utf8_string_len ||
521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   j >= ucs2_buffer_size - 1) {
531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				/* incomplete surrogate */
541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			} else {
561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				/* three-byte encoding */
571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				u8 c3 = utf8_string[++i];
581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				WPA_PUT_LE16(ucs2_buffer + j,
591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     ((c & 0xF) << 12) |
601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ucs2_string_size)
661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		*ucs2_string_size = j / 2;
671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @peer_challenge: 16-octet PeerChallenge (IN)
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @username: 0-to-256-char UserName (IN)
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @username_len: Length of username
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @challenge: 8-octet Challenge (OUT)
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  const u8 *username, size_t username_len,
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  u8 *challenge)
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA1_MAC_LEN];
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const unsigned char *addr[3];
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[3];
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = peer_challenge;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = 16;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = auth_challenge;
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = 16;
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = username;
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = username_len;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sha1_vector(3, addr, len, hash))
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(challenge, hash, 8);
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
1041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @password: 0-to-256-unicode-char Password (IN; UTF-8)
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_len: Length of password
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_hash: 16-octet PasswordHash (OUT)
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint nt_password_hash(const u8 *password, size_t password_len,
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      u8 *password_hash)
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 buf[512], *pos;
1131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t len, max_len;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	max_len = sizeof(buf);
1161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
1171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	len *= 2;
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_hash: 16-octet PasswordHash (IN)
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_hash_hash: 16-octet PasswordHashHash (OUT)
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len = 16;
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return md4_vector(1, &password_hash, &len, password_hash_hash);
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @challenge: 8-octet Challenge (IN)
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_hash: 16-octet PasswordHash (IN)
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @response: 24-octet Response (OUT)
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid challenge_response(const u8 *challenge, const u8 *password_hash,
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			u8 *response)
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 zpwd[7];
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	des_encrypt(challenge, password_hash, response);
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	des_encrypt(challenge, password_hash + 7, response + 8);
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	zpwd[0] = password_hash[14];
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	zpwd[1] = password_hash[15];
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(zpwd + 2, 0, 5);
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	des_encrypt(challenge, zpwd, response + 16);
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @peer_challenge: 16-octet PeerChallenge (IN)
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @username: 0-to-256-char UserName (IN)
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @username_len: Length of username
1631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @password: 0-to-256-unicode-char Password (IN; UTF-8)
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_len: Length of password
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @response: 24-octet Response (OUT)
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const u8 *username, size_t username_len,
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const u8 *password, size_t password_len,
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 u8 *response)
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 challenge[8];
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 password_hash[16];
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	challenge_hash(peer_challenge, auth_challenge, username, username_len,
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       challenge);
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nt_password_hash(password, password_len, password_hash))
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	challenge_response(challenge, password_hash, response);
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @peer_challenge: 16-octet PeerChallenge (IN)
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @username: 0-to-256-char UserName (IN)
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @username_len: Length of username
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_hash: 16-octet PasswordHash (IN)
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @response: 24-octet Response (OUT)
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint generate_nt_response_pwhash(const u8 *auth_challenge,
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const u8 *peer_challenge,
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const u8 *username, size_t username_len,
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const u8 *password_hash,
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				u8 *response)
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 challenge[8];
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (challenge_hash(peer_challenge, auth_challenge,
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   username, username_len,
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   challenge))
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	challenge_response(challenge, password_hash, response);
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_hash: 16-octet PasswordHash (IN)
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @nt_response: 24-octet NT-Response (IN)
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @peer_challenge: 16-octet PeerChallenge (IN)
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @username: 0-to-256-char UserName (IN)
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @username_len: Length of username
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * encoded as a 42-octet ASCII string (S=hexdump_of_response)
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint generate_authenticator_response_pwhash(
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *password_hash,
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *peer_challenge, const u8 *auth_challenge,
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *username, size_t username_len,
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *nt_response, u8 *response)
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static const u8 magic1[39] = {
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static const u8 magic2[41] = {
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x6E
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 password_hash_hash[16], challenge[8];
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const unsigned char *addr1[3];
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t len1[3] = { 16, 24, sizeof(magic1) };
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const unsigned char *addr2[3];
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr1[0] = password_hash_hash;
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr1[1] = nt_response;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr1[2] = magic1;
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr2[0] = response;
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr2[1] = challenge;
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr2[2] = magic2;
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hash_nt_password_hash(password_hash, password_hash_hash))
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sha1_vector(3, addr1, len1, response))
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	challenge_hash(peer_challenge, auth_challenge, username, username_len,
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       challenge);
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return sha1_vector(3, addr2, len2, response);
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
2711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @password: 0-to-256-unicode-char Password (IN; UTF-8)
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_len: Length of password
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @nt_response: 24-octet NT-Response (IN)
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @peer_challenge: 16-octet PeerChallenge (IN)
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @username: 0-to-256-char UserName (IN)
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @username_len: Length of username
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * encoded as a 42-octet ASCII string (S=hexdump_of_response)
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint generate_authenticator_response(const u8 *password, size_t password_len,
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    const u8 *peer_challenge,
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    const u8 *auth_challenge,
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    const u8 *username, size_t username_len,
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    const u8 *nt_response, u8 *response)
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 password_hash[16];
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nt_password_hash(password, password_len, password_hash))
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return generate_authenticator_response_pwhash(
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		password_hash, peer_challenge, auth_challenge,
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		username, username_len, nt_response, response);
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @challenge: 8-octet Challenge (IN)
3001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @password: 0-to-256-unicode-char Password (IN; UTF-8)
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_len: Length of password
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @response: 24-octet Response (OUT)
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint nt_challenge_response(const u8 *challenge, const u8 *password,
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  size_t password_len, u8 *response)
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 password_hash[16];
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nt_password_hash(password, password_len, password_hash))
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	challenge_response(challenge, password_hash, response);
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_hash_hash: 16-octet PasswordHashHash (IN)
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @nt_response: 24-octet NTResponse (IN)
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @master_key: 16-octet MasterKey (OUT)
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   u8 *master_key)
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static const u8 magic1[27] = {
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const unsigned char *addr[3];
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t len[3] = { 16, 24, sizeof(magic1) };
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA1_MAC_LEN];
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = password_hash_hash;
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = nt_response;
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = magic1;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sha1_vector(3, addr, len, hash))
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(master_key, hash, 16);
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @master_key: 16-octet MasterKey (IN)
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @session_key: 8-to-16 octet SessionKey (OUT)
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @session_key_len: SessionKeyLength (Length of session_key) (IN)
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @is_send: IsSend (IN, BOOLEAN)
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @is_server: IsServer (IN, BOOLEAN)
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint get_asymetric_start_key(const u8 *master_key, u8 *session_key,
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    size_t session_key_len, int is_send,
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    int is_server)
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static const u8 magic2[84] = {
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x6b, 0x65, 0x79, 0x2e
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static const u8 magic3[84] = {
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x6b, 0x65, 0x79, 0x2e
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static const u8 shs_pad1[40] = {
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static const u8 shs_pad2[40] = {
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 digest[SHA1_MAC_LEN];
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const unsigned char *addr[4];
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t len[4] = { 16, 40, 84, 40 };
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = master_key;
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = shs_pad1;
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (is_send) {
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		addr[2] = is_server ? magic3 : magic2;
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		addr[2] = is_server ? magic2 : magic3;
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = shs_pad2;
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sha1_vector(4, addr, len, digest))
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (session_key_len > SHA1_MAC_LEN)
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		session_key_len = SHA1_MAC_LEN;
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(session_key, digest, session_key_len);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define PWBLOCK_LEN 516
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
4211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @password: 0-to-256-unicode-char Password (IN; UTF-8)
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_len: Length of password
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_hash: 16-octet PasswordHash (IN)
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pw_block: 516-byte PwBlock (OUT)
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint encrypt_pw_block_with_password_hash(
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *password, size_t password_len,
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *password_hash, u8 *pw_block)
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t ucs2_len, offset;
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos;
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(pw_block, 0, PWBLOCK_LEN);
4351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ucs2_len > 256)
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	offset = (256 - ucs2_len) * 2;
4431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (offset != 0) {
4441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
4451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (os_get_random(pw_block, offset) < 0)
4461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return -1;
4471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PasswordLength is 4 octets, but since the maximum password length is
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * 256, only first two (in little endian byte order) can be non-zero.
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = &pw_block[2 * 256];
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_LE16(pos, password_len * 2);
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
4611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @new_password_len: Length of new_password
4631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @old_password_len: Length of old_password
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint new_password_encrypted_with_old_nt_password_hash(
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *new_password, size_t new_password_len,
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *old_password, size_t old_password_len,
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *encrypted_pw_block)
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 password_hash[16];
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nt_password_hash(old_password, old_password_len, password_hash))
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						password_hash,
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						encrypted_pw_block))
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @password_hash: 16-octer PasswordHash (IN)
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @block: 16-octet Block (IN)
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cypher: 16-octer Cypher (OUT)
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid nt_password_hash_encrypted_with_block(const u8 *password_hash,
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   const u8 *block, u8 *cypher)
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	des_encrypt(password_hash, block, cypher);
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	des_encrypt(password_hash + 8, block + 7, cypher + 8);
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
5011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @new_password_len: Length of new_password
5031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @old_password_len: Length of old_password
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint old_nt_password_hash_encrypted_with_new_nt_password_hash(
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *new_password, size_t new_password_len,
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *old_password, size_t old_password_len,
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *encrypted_password_hash)
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 old_password_hash[16], new_password_hash[16];
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nt_password_hash(old_password, old_password_len,
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     old_password_hash) ||
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    nt_password_hash(new_password, new_password_len,
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     new_password_hash))
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nt_password_hash_encrypted_with_block(old_password_hash,
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      new_password_hash,
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      encrypted_password_hash);
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
525