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) };
161 u8 hash[SHA1_MAC_LEN];
163 addr[0] = password_hash_hash;
164 addr[1] = nt_response;
167 sha1_vector(3, addr, len, hash);
168 memcpy(master_key, hash, 16);
172 void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
173 size_t session_key_len, int is_send,
176 static const u8 magic2[84] = {
177 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
178 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
179 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
180 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
181 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
182 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
183 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
184 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
185 0x6b, 0x65, 0x79, 0x2e
187 static const u8 magic3[84] = {
188 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
189 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
190 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
191 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
192 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
193 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
194 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
195 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
196 0x6b, 0x65, 0x79, 0x2e
198 static const u8 shs_pad1[40] = {
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
205 static const u8 shs_pad2[40] = {
206 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
207 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
208 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
209 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
211 u8 digest[SHA1_MAC_LEN];
212 const unsigned char *addr[4];
213 const size_t len[4] = { 16, 40, 84, 40 };
215 addr[0] = master_key;
218 addr[2] = is_server ? magic3 : magic2;
220 addr[2] = is_server ? magic2 : magic3;
224 sha1_vector(4, addr, len, digest);
226 if (session_key_len > SHA1_MAC_LEN)
227 session_key_len = SHA1_MAC_LEN;
228 memcpy(session_key, digest, session_key_len);
232 #ifdef TEST_MAIN_MS_FUNCS
233 int main(int argc, char *argv[])
235 /* Test vector from RFC2759 example */
236 u8 *username = "User";
237 u8 *password = "clientPass";
238 u8 auth_challenge[] = {
239 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
240 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
242 u8 peer_challenge[] = {
243 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
244 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
246 u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 };
247 u8 password_hash[] = {
248 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
249 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
252 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
253 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
254 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
256 u8 password_hash_hash[] = {
257 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
258 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
260 u8 authenticator_response[] = {
261 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
262 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
263 0x93, 0x2C, 0xDA, 0x56
266 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
267 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
269 u8 send_start_key[] = {
270 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
271 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
277 printf("Testing ms_funcs.c\n");
279 challenge_hash(peer_challenge, auth_challenge,
280 username, strlen(username),
282 if (memcmp(challenge, buf, sizeof(challenge)) != 0) {
283 printf("challenge_hash failed\n");
287 nt_password_hash(password, strlen(password), buf);
288 if (memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
289 printf("nt_password_hash failed\n");
293 generate_nt_response(auth_challenge, peer_challenge,
294 username, strlen(username),
295 password, strlen(password),
297 if (memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
298 printf("generate_nt_response failed\n");
302 hash_nt_password_hash(password_hash, buf);
303 if (memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) {
304 printf("hash_nt_password_hash failed\n");
308 generate_authenticator_response(password, strlen(password),
309 peer_challenge, auth_challenge,
310 username, strlen(username),
312 if (memcmp(authenticator_response, buf, sizeof(authenticator_response))
314 printf("generate_authenticator_response failed\n");
318 get_master_key(password_hash_hash, nt_response, buf);
319 if (memcmp(master_key, buf, sizeof(master_key)) != 0) {
320 printf("get_master_key failed\n");
324 get_asymetric_start_key(master_key, buf, sizeof(send_start_key), 1, 1);
325 if (memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
326 printf("get_asymetric_start_key failed\n");
331 printf("FAILED! %d errors\n", errors);
335 #endif /* TEST_MAIN_MS_FUNCS */