ms_funcs.c revision 61d9df3e62aaa0e87ad05452fcb95142159a17b6
13d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman/*
23d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
33d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
43d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman *
53d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * This software may be distributed under the terms of the BSD license.
63d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * See README for more details.
73d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman */
83d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman
93d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman#include "includes.h"
10565cc44bea707ff3865fbeb731e4790dd9874786Dan Gohman
11565cc44bea707ff3865fbeb731e4790dd9874786Dan Gohman#include "common.h"
123d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman#include "sha1.h"
133d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman#include "ms_funcs.h"
143d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman#include "crypto.h"
153d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman
163d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman/**
173d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
18686775deca8b8685eb90801495880e3abdd844c2Chris Lattner * @utf8_string: UTF-8 string (IN)
193d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * @utf8_string_len: Length of utf8_string (IN)
203b844ba7d5be205a9b4f5f0b0d1b7978977f4b8cChandler Carruth * @ucs2_buffer: UCS-2 buffer (OUT)
213d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
223d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
233d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * Returns: 0 on success, -1 on failure
243d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman */
253d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohmanstatic int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
263d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman                        u8 *ucs2_buffer, size_t ucs2_buffer_size,
273d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman                        size_t *ucs2_string_size)
283d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman{
29c9fe6056e4ce8ffad1ef439fca3318a5faf1c075Kostya Serebryany	size_t i, j;
303d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman
3114110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne	for (i = 0, j = 0; i < utf8_string_len; i++) {
323d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman		u8 c = utf8_string[i];
333d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman		if (j >= ucs2_buffer_size) {
343d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman			/* input too long */
353d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman			return -1;
363d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman		}
373d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman		if (c <= 0x7F) {
38b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren			WPA_PUT_LE16(ucs2_buffer + j, c);
39b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren			j += 2;
40b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren		} else if (i == utf8_string_len - 1 ||
41b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren			   j >= ucs2_buffer_size - 1) {
42b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren			/* incomplete surrogate */
43b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren			return -1;
44b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren		} else {
45b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren			u8 c2 = utf8_string[++i];
463d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman			if ((c & 0xE0) == 0xC0) {
473d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman				/* two-byte encoding */
483d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman				WPA_PUT_LE16(ucs2_buffer + j,
493d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman					     ((c & 0x1F) << 6) | (c2 & 0x3F));
50c9fe6056e4ce8ffad1ef439fca3318a5faf1c075Kostya Serebryany				j += 2;
513d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman			} else if (i == utf8_string_len ||
520b5c4fc2ae3b503c2b1f354bf52b718aa50a6aeeDan Gohman				   j >= ucs2_buffer_size - 1) {
533d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman				/* incomplete surrogate */
542d7cb069fe101da3971a07900ff583380bcac184Duncan Sands				return -1;
552d7cb069fe101da3971a07900ff583380bcac184Duncan Sands			} else {
562d7cb069fe101da3971a07900ff583380bcac184Duncan Sands				/* three-byte encoding */
57b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren				u8 c3 = utf8_string[++i];
58b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren				WPA_PUT_LE16(ucs2_buffer + j,
593d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman					     ((c & 0xF) << 12) |
60b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
61b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren			}
62b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren		}
63b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren	}
643d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman
65b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman	if (ucs2_string_size)
66b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman		*ucs2_string_size = j / 2;
67b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman	return 0;
68b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman}
693d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman
70224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman
713d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman/**
72224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
73224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * @peer_challenge: 16-octet PeerChallenge (IN)
74224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
75224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * @username: 0-to-256-char UserName (IN)
76224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * @username_len: Length of username
773d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * @challenge: 8-octet Challenge (OUT)
78224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * Returns: 0 on success, -1 on failure
793d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman */
80b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohmanstatic int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
81b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman			  const u8 *username, size_t username_len,
82b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman			  u8 *challenge)
83b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman{
84b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman	u8 hash[SHA1_MAC_LEN];
85b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman	const unsigned char *addr[3];
86b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman	size_t len[3];
873d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman
883d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman	addr[0] = peer_challenge;
89c9fe6056e4ce8ffad1ef439fca3318a5faf1c075Kostya Serebryany	len[0] = 16;
900b5c4fc2ae3b503c2b1f354bf52b718aa50a6aeeDan Gohman	addr[1] = auth_challenge;
910b5c4fc2ae3b503c2b1f354bf52b718aa50a6aeeDan Gohman	len[1] = 16;
923d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman	addr[2] = username;
933d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman	len[2] = username_len;
94565cc44bea707ff3865fbeb731e4790dd9874786Dan Gohman
95565cc44bea707ff3865fbeb731e4790dd9874786Dan Gohman	if (sha1_vector(3, addr, len, hash))
963d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman		return -1;
978cb4a070d491ddd671b049110cc8d0accb08b905Kostya Serebryany	os_memcpy(challenge, hash, 8);
988cb4a070d491ddd671b049110cc8d0accb08b905Kostya Serebryany	return 0;
998cb4a070d491ddd671b049110cc8d0accb08b905Kostya Serebryany}
1008cb4a070d491ddd671b049110cc8d0accb08b905Kostya Serebryany
101b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman
102b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman/**
103b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
104b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman * @password: 0-to-256-unicode-char Password (IN; UTF-8)
105b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @password_len: Length of password
106b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @password_hash: 16-octet PasswordHash (OUT)
107b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * Returns: 0 on success, -1 on failure
108b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren */
109b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Renint nt_password_hash(const u8 *password, size_t password_len,
110b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren		      u8 *password_hash)
111b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren{
1123d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman	u8 buf[512], *pos;
1133d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman	size_t len, max_len;
1143d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman
1153d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman	max_len = sizeof(buf);
1163d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
117b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren		return -1;
118b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren
119b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren	len *= 2;
120b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren	pos = buf;
121b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
122b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren}
123b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren
124b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren
125b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren/**
126b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
127b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @password_hash: 16-octet PasswordHash (IN)
128b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @password_hash_hash: 16-octet PasswordHashHash (OUT)
129b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * Returns: 0 on success, -1 on failure
130b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren */
131b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Renint hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
132b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren{
133b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren	size_t len = 16;
134b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren	return md4_vector(1, &password_hash, &len, password_hash_hash);
135b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren}
136b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren
137b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren
138b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren/**
139b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
140b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @challenge: 8-octet Challenge (IN)
141b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @password_hash: 16-octet PasswordHash (IN)
142b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @response: 24-octet Response (OUT)
143b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren */
144b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Renvoid challenge_response(const u8 *challenge, const u8 *password_hash,
145b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren			u8 *response)
146b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren{
147b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren	u8 zpwd[7];
148b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren	des_encrypt(challenge, password_hash, response);
149b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren	des_encrypt(challenge, password_hash + 7, response + 8);
1503d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman	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
163 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
164 * @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
176	if (challenge_hash(peer_challenge, auth_challenge, username,
177			   username_len, challenge))
178		return -1;
179	if (nt_password_hash(password, password_len, password_hash))
180		return -1;
181	challenge_response(challenge, password_hash, response);
182	return 0;
183}
184
185
186/**
187 * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
188 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
189 * @peer_challenge: 16-octet PeerChallenge (IN)
190 * @username: 0-to-256-char UserName (IN)
191 * @username_len: Length of username
192 * @password_hash: 16-octet PasswordHash (IN)
193 * @response: 24-octet Response (OUT)
194 * Returns: 0 on success, -1 on failure
195 */
196int generate_nt_response_pwhash(const u8 *auth_challenge,
197				const u8 *peer_challenge,
198				const u8 *username, size_t username_len,
199				const u8 *password_hash,
200				u8 *response)
201{
202	u8 challenge[8];
203
204	if (challenge_hash(peer_challenge, auth_challenge,
205			   username, username_len,
206			   challenge))
207		return -1;
208	challenge_response(challenge, password_hash, response);
209	return 0;
210}
211
212
213/**
214 * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
215 * @password_hash: 16-octet PasswordHash (IN)
216 * @nt_response: 24-octet NT-Response (IN)
217 * @peer_challenge: 16-octet PeerChallenge (IN)
218 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
219 * @username: 0-to-256-char UserName (IN)
220 * @username_len: Length of username
221 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
222 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
223 * Returns: 0 on success, -1 on failure
224 */
225int generate_authenticator_response_pwhash(
226	const u8 *password_hash,
227	const u8 *peer_challenge, const u8 *auth_challenge,
228	const u8 *username, size_t username_len,
229	const u8 *nt_response, u8 *response)
230{
231	static const u8 magic1[39] = {
232		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
233		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
234		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
235		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
236	};
237	static const u8 magic2[41] = {
238		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
239		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
240		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
241		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
242		0x6E
243	};
244
245	u8 password_hash_hash[16], challenge[8];
246	const unsigned char *addr1[3];
247	const size_t len1[3] = { 16, 24, sizeof(magic1) };
248	const unsigned char *addr2[3];
249	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
250
251	addr1[0] = password_hash_hash;
252	addr1[1] = nt_response;
253	addr1[2] = magic1;
254
255	addr2[0] = response;
256	addr2[1] = challenge;
257	addr2[2] = magic2;
258
259	if (hash_nt_password_hash(password_hash, password_hash_hash))
260		return -1;
261	if (sha1_vector(3, addr1, len1, response))
262		return -1;
263
264	if (challenge_hash(peer_challenge, auth_challenge, username,
265			   username_len, challenge))
266		return -1;
267	return sha1_vector(3, addr2, len2, response);
268}
269
270
271/**
272 * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
273 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
274 * @password_len: Length of password
275 * @nt_response: 24-octet NT-Response (IN)
276 * @peer_challenge: 16-octet PeerChallenge (IN)
277 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
278 * @username: 0-to-256-char UserName (IN)
279 * @username_len: Length of username
280 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
281 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
282 * Returns: 0 on success, -1 on failure
283 */
284int generate_authenticator_response(const u8 *password, size_t password_len,
285				    const u8 *peer_challenge,
286				    const u8 *auth_challenge,
287				    const u8 *username, size_t username_len,
288				    const u8 *nt_response, u8 *response)
289{
290	u8 password_hash[16];
291	if (nt_password_hash(password, password_len, password_hash))
292		return -1;
293	return generate_authenticator_response_pwhash(
294		password_hash, peer_challenge, auth_challenge,
295		username, username_len, nt_response, response);
296}
297
298
299/**
300 * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
301 * @challenge: 8-octet Challenge (IN)
302 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
303 * @password_len: Length of password
304 * @response: 24-octet Response (OUT)
305 * Returns: 0 on success, -1 on failure
306 */
307int nt_challenge_response(const u8 *challenge, const u8 *password,
308			  size_t password_len, u8 *response)
309{
310	u8 password_hash[16];
311	if (nt_password_hash(password, password_len, password_hash))
312		return -1;
313	challenge_response(challenge, password_hash, response);
314	return 0;
315}
316
317
318/**
319 * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
320 * @password_hash_hash: 16-octet PasswordHashHash (IN)
321 * @nt_response: 24-octet NTResponse (IN)
322 * @master_key: 16-octet MasterKey (OUT)
323 * Returns: 0 on success, -1 on failure
324 */
325int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
326		   u8 *master_key)
327{
328	static const u8 magic1[27] = {
329		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
330		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
331		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
332	};
333	const unsigned char *addr[3];
334	const size_t len[3] = { 16, 24, sizeof(magic1) };
335	u8 hash[SHA1_MAC_LEN];
336
337	addr[0] = password_hash_hash;
338	addr[1] = nt_response;
339	addr[2] = magic1;
340
341	if (sha1_vector(3, addr, len, hash))
342		return -1;
343	os_memcpy(master_key, hash, 16);
344	return 0;
345}
346
347
348/**
349 * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
350 * @master_key: 16-octet MasterKey (IN)
351 * @session_key: 8-to-16 octet SessionKey (OUT)
352 * @session_key_len: SessionKeyLength (Length of session_key) (IN)
353 * @is_send: IsSend (IN, BOOLEAN)
354 * @is_server: IsServer (IN, BOOLEAN)
355 * Returns: 0 on success, -1 on failure
356 */
357int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
358			    size_t session_key_len, int is_send,
359			    int is_server)
360{
361	static const u8 magic2[84] = {
362		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
363		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
364		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
365		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
366		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
367		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
368		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
369		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
370		0x6b, 0x65, 0x79, 0x2e
371	};
372	static const u8 magic3[84] = {
373		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
374		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
375		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
376		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
377		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
378		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
379		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
380		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
381		0x6b, 0x65, 0x79, 0x2e
382	};
383	static const u8 shs_pad1[40] = {
384		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
388	};
389
390	static const u8 shs_pad2[40] = {
391		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
392		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
393		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
394		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
395	};
396	u8 digest[SHA1_MAC_LEN];
397	const unsigned char *addr[4];
398	const size_t len[4] = { 16, 40, 84, 40 };
399
400	addr[0] = master_key;
401	addr[1] = shs_pad1;
402	if (is_send) {
403		addr[2] = is_server ? magic3 : magic2;
404	} else {
405		addr[2] = is_server ? magic2 : magic3;
406	}
407	addr[3] = shs_pad2;
408
409	if (sha1_vector(4, addr, len, digest))
410		return -1;
411
412	if (session_key_len > SHA1_MAC_LEN)
413		session_key_len = SHA1_MAC_LEN;
414	os_memcpy(session_key, digest, session_key_len);
415	return 0;
416}
417
418
419#define PWBLOCK_LEN 516
420
421/**
422 * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
423 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
424 * @password_len: Length of password
425 * @password_hash: 16-octet PasswordHash (IN)
426 * @pw_block: 516-byte PwBlock (OUT)
427 * Returns: 0 on success, -1 on failure
428 */
429int encrypt_pw_block_with_password_hash(
430	const u8 *password, size_t password_len,
431	const u8 *password_hash, u8 *pw_block)
432{
433	size_t ucs2_len, offset;
434	u8 *pos;
435
436	os_memset(pw_block, 0, PWBLOCK_LEN);
437
438	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
439		return -1;
440
441	if (ucs2_len > 256)
442		return -1;
443
444	offset = (256 - ucs2_len) * 2;
445	if (offset != 0) {
446		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
447		if (os_get_random(pw_block, offset) < 0)
448			return -1;
449	}
450	/*
451	 * PasswordLength is 4 octets, but since the maximum password length is
452	 * 256, only first two (in little endian byte order) can be non-zero.
453	 */
454	pos = &pw_block[2 * 256];
455	WPA_PUT_LE16(pos, password_len * 2);
456	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
457	return 0;
458}
459
460
461/**
462 * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
463 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
464 * @new_password_len: Length of new_password
465 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
466 * @old_password_len: Length of old_password
467 * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
468 * Returns: 0 on success, -1 on failure
469 */
470int new_password_encrypted_with_old_nt_password_hash(
471	const u8 *new_password, size_t new_password_len,
472	const u8 *old_password, size_t old_password_len,
473	u8 *encrypted_pw_block)
474{
475	u8 password_hash[16];
476
477	if (nt_password_hash(old_password, old_password_len, password_hash))
478		return -1;
479	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
480						password_hash,
481						encrypted_pw_block))
482		return -1;
483	return 0;
484}
485
486
487/**
488 * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
489 * @password_hash: 16-octer PasswordHash (IN)
490 * @block: 16-octet Block (IN)
491 * @cypher: 16-octer Cypher (OUT)
492 */
493void nt_password_hash_encrypted_with_block(const u8 *password_hash,
494					   const u8 *block, u8 *cypher)
495{
496	des_encrypt(password_hash, block, cypher);
497	des_encrypt(password_hash + 8, block + 7, cypher + 8);
498}
499
500
501/**
502 * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
503 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
504 * @new_password_len: Length of new_password
505 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
506 * @old_password_len: Length of old_password
507 * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
508 * Returns: 0 on success, -1 on failure
509 */
510int old_nt_password_hash_encrypted_with_new_nt_password_hash(
511	const u8 *new_password, size_t new_password_len,
512	const u8 *old_password, size_t old_password_len,
513	u8 *encrypted_password_hash)
514{
515	u8 old_password_hash[16], new_password_hash[16];
516
517	if (nt_password_hash(old_password, old_password_len,
518			     old_password_hash) ||
519	    nt_password_hash(new_password, new_password_len,
520			     new_password_hash))
521		return -1;
522	nt_password_hash_encrypted_with_block(old_password_hash,
523					      new_password_hash,
524					      encrypted_password_hash);
525	return 0;
526}
527