2 * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
25 static void challenge_hash(u8 *peer_challenge, u8 *auth_challenge,
26 u8 *username, size_t username_len,
29 u8 hash[SHA1_MAC_LEN];
30 const unsigned char *addr[3];
33 addr[0] = peer_challenge;
35 addr[1] = auth_challenge;
38 len[2] = username_len;
40 sha1_vector(3, addr, len, hash);
41 memcpy(challenge, hash, 8);
45 void nt_password_hash(u8 *password, size_t password_len, u8 *password_hash)
50 /* Convert password into unicode */
51 buf = malloc(password_len * 2);
54 memset(buf, 0, password_len * 2);
55 for (i = 0; i < password_len; i++)
56 buf[2 * i] = password[i];
58 md4(buf, password_len * 2, password_hash);
63 void hash_nt_password_hash(u8 *password_hash, u8 *password_hash_hash)
65 md4(password_hash, 16, password_hash_hash);
69 void challenge_response(u8 *challenge, u8 *password_hash, u8 *response)
72 des_encrypt(challenge, password_hash, response);
73 des_encrypt(challenge, password_hash + 7, response + 8);
74 zpwd[0] = password_hash[14];
75 zpwd[1] = password_hash[15];
76 memset(zpwd + 2, 0, 5);
77 des_encrypt(challenge, zpwd, response + 16);
81 void generate_nt_response(u8 *auth_challenge, u8 *peer_challenge,
82 u8 *username, size_t username_len,
83 u8 *password, size_t password_len,
89 challenge_hash(peer_challenge, auth_challenge, username, username_len,
91 nt_password_hash(password, password_len, password_hash);
92 challenge_response(challenge, password_hash, response);
96 void generate_authenticator_response(u8 *password, size_t password_len,
99 u8 *username, size_t username_len,
100 u8 *nt_response, u8 *response)
102 static const u8 magic1[39] = {
103 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
104 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
105 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
106 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
108 static const u8 magic2[41] = {
109 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
110 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
111 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
112 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
116 u8 password_hash[16], password_hash_hash[16], challenge[8];
117 const unsigned char *addr1[3];
118 const size_t len1[3] = { 16, 24, sizeof(magic1) };
119 const unsigned char *addr2[3];
120 const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
122 addr1[0] = password_hash_hash;
123 addr1[1] = nt_response;
127 addr2[1] = challenge;
130 nt_password_hash(password, password_len, password_hash);
131 hash_nt_password_hash(password_hash, password_hash_hash);
132 sha1_vector(3, addr1, len1, response);
134 challenge_hash(peer_challenge, auth_challenge, username, username_len,
136 sha1_vector(3, addr2, len2, response);
140 void nt_challenge_response(u8 *challenge, u8 *password, size_t password_len,
143 u8 password_hash[16];
144 nt_password_hash(password, password_len, password_hash);
145 challenge_response(challenge, password_hash, response);
149 /* IN: 16-octet password_hash_hash and 24-octet nt_response
150 * OUT: 16-octet master_key */
151 void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
154 static const u8 magic1[27] = {
155 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
156 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
157 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
159 const unsigned char *addr[3];
160 const size_t len[3] = { 16, 24, sizeof(magic1) };
162 addr[0] = password_hash_hash;
163 addr[1] = nt_response;
166 sha1_vector(3, addr, len, master_key);
170 void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
171 size_t session_key_len, int is_send,
174 static const u8 magic2[84] = {
175 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
176 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
177 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
178 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
179 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
180 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
181 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
182 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
183 0x6b, 0x65, 0x79, 0x2e
185 static const u8 magic3[84] = {
186 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
187 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
188 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
189 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
190 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
191 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
192 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
193 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
194 0x6b, 0x65, 0x79, 0x2e
196 static const u8 shs_pad1[40] = {
197 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
203 static const u8 shs_pad2[40] = {
204 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
205 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
206 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
207 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
209 u8 digest[SHA1_MAC_LEN];
210 const unsigned char *addr[4];
211 const size_t len[4] = { 16, 40, 84, 40 };
213 addr[0] = master_key;
216 addr[2] = is_server ? magic3 : magic2;
218 addr[2] = is_server ? magic2 : magic3;
222 sha1_vector(4, addr, len, digest);
224 if (session_key_len > SHA1_MAC_LEN)
225 session_key_len = SHA1_MAC_LEN;
226 memcpy(session_key, digest, session_key_len);
230 #ifdef TEST_MAIN_MS_FUNCS
231 int main(int argc, char *argv[])
233 /* Test vector from RFC2759 example */
234 u8 *username = "User";
235 u8 *password = "clientPass";
236 u8 auth_challenge[] = {
237 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
238 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
240 u8 peer_challenge[] = {
241 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
242 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
244 u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 };
245 u8 password_hash[] = {
246 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
247 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
250 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
251 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
252 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
254 u8 password_hash_hash[] = {
255 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
256 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
258 u8 authenticator_response[] = {
259 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
260 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
261 0x93, 0x2C, 0xDA, 0x56
264 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
265 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
267 u8 send_start_key[] = {
268 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
269 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
275 printf("Testing ms_funcs.c\n");
277 challenge_hash(peer_challenge, auth_challenge,
278 username, strlen(username),
280 if (memcmp(challenge, buf, sizeof(challenge)) != 0) {
281 printf("challenge_hash failed\n");
285 nt_password_hash(password, strlen(password), buf);
286 if (memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
287 printf("nt_password_hash failed\n");
291 generate_nt_response(auth_challenge, peer_challenge,
292 username, strlen(username),
293 password, strlen(password),
295 if (memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
296 printf("generate_nt_response failed\n");
300 hash_nt_password_hash(password_hash, buf);
301 if (memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) {
302 printf("hash_nt_password_hash failed\n");
306 generate_authenticator_response(password, strlen(password),
307 peer_challenge, auth_challenge,
308 username, strlen(username),
310 if (memcmp(authenticator_response, buf, sizeof(authenticator_response))
312 printf("generate_authenticator_response failed\n");
316 get_master_key(password_hash_hash, nt_response, buf);
317 if (memcmp(master_key, buf, sizeof(master_key)) != 0) {
318 printf("get_master_key failed\n");
322 get_asymetric_start_key(master_key, buf, sizeof(send_start_key), 1, 1);
323 if (memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
324 printf("get_asymetric_start_key failed\n");
329 printf("FAILED! %d errors\n", errors);
333 #endif /* TEST_MAIN_MS_FUNCS */