Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / crypto / ms_funcs.c
1 /*
2  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3  * Copyright (c) 2004-2012, Jouni Malinen <j@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 int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
82                    const u8 *username, size_t username_len, u8 *challenge)
83 {
84         u8 hash[SHA1_MAC_LEN];
85         const unsigned char *addr[3];
86         size_t len[3];
87
88         addr[0] = peer_challenge;
89         len[0] = 16;
90         addr[1] = auth_challenge;
91         len[1] = 16;
92         addr[2] = username;
93         len[2] = username_len;
94
95         if (sha1_vector(3, addr, len, hash))
96                 return -1;
97         os_memcpy(challenge, hash, 8);
98         return 0;
99 }
100
101
102 /**
103  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
104  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
105  * @password_len: Length of password
106  * @password_hash: 16-octet PasswordHash (OUT)
107  * Returns: 0 on success, -1 on failure
108  */
109 int nt_password_hash(const u8 *password, size_t password_len,
110                       u8 *password_hash)
111 {
112         u8 buf[512], *pos;
113         size_t len, max_len;
114
115         max_len = sizeof(buf);
116         if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
117                 return -1;
118
119         len *= 2;
120         pos = buf;
121         return md4_vector(1, (const u8 **) &pos, &len, password_hash);
122 }
123
124
125 /**
126  * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
127  * @password_hash: 16-octet PasswordHash (IN)
128  * @password_hash_hash: 16-octet PasswordHashHash (OUT)
129  * Returns: 0 on success, -1 on failure
130  */
131 int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
132 {
133         size_t len = 16;
134         return md4_vector(1, &password_hash, &len, password_hash_hash);
135 }
136
137
138 /**
139  * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
140  * @challenge: 8-octet Challenge (IN)
141  * @password_hash: 16-octet PasswordHash (IN)
142  * @response: 24-octet Response (OUT)
143  */
144 void challenge_response(const u8 *challenge, const u8 *password_hash,
145                         u8 *response)
146 {
147         u8 zpwd[7];
148         des_encrypt(challenge, password_hash, response);
149         des_encrypt(challenge, password_hash + 7, response + 8);
150         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  */
168 int 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             nt_password_hash(password, password_len, password_hash))
179                 return -1;
180         challenge_response(challenge, password_hash, response);
181         return 0;
182 }
183
184
185 /**
186  * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
187  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
188  * @peer_challenge: 16-octet PeerChallenge (IN)
189  * @username: 0-to-256-char UserName (IN)
190  * @username_len: Length of username
191  * @password_hash: 16-octet PasswordHash (IN)
192  * @response: 24-octet Response (OUT)
193  * Returns: 0 on success, -1 on failure
194  */
195 int generate_nt_response_pwhash(const u8 *auth_challenge,
196                                 const u8 *peer_challenge,
197                                 const u8 *username, size_t username_len,
198                                 const u8 *password_hash,
199                                 u8 *response)
200 {
201         u8 challenge[8];
202
203         if (challenge_hash(peer_challenge, auth_challenge,
204                            username, username_len,
205                            challenge))
206                 return -1;
207         challenge_response(challenge, password_hash, response);
208         return 0;
209 }
210
211
212 /**
213  * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
214  * @password_hash: 16-octet PasswordHash (IN)
215  * @nt_response: 24-octet NT-Response (IN)
216  * @peer_challenge: 16-octet PeerChallenge (IN)
217  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
218  * @username: 0-to-256-char UserName (IN)
219  * @username_len: Length of username
220  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
221  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
222  * Returns: 0 on success, -1 on failure
223  */
224 int generate_authenticator_response_pwhash(
225         const u8 *password_hash,
226         const u8 *peer_challenge, const u8 *auth_challenge,
227         const u8 *username, size_t username_len,
228         const u8 *nt_response, u8 *response)
229 {
230         static const u8 magic1[39] = {
231                 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
232                 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
233                 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
234                 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
235         };
236         static const u8 magic2[41] = {
237                 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
238                 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
239                 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
240                 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
241                 0x6E
242         };
243
244         u8 password_hash_hash[16], challenge[8];
245         const unsigned char *addr1[3];
246         const size_t len1[3] = { 16, 24, sizeof(magic1) };
247         const unsigned char *addr2[3];
248         const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
249
250         addr1[0] = password_hash_hash;
251         addr1[1] = nt_response;
252         addr1[2] = magic1;
253
254         addr2[0] = response;
255         addr2[1] = challenge;
256         addr2[2] = magic2;
257
258         if (hash_nt_password_hash(password_hash, password_hash_hash) ||
259             sha1_vector(3, addr1, len1, response) ||
260             challenge_hash(peer_challenge, auth_challenge, username,
261                            username_len, challenge))
262                 return -1;
263         return sha1_vector(3, addr2, len2, response);
264 }
265
266
267 /**
268  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
269  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
270  * @password_len: Length of password
271  * @nt_response: 24-octet NT-Response (IN)
272  * @peer_challenge: 16-octet PeerChallenge (IN)
273  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
274  * @username: 0-to-256-char UserName (IN)
275  * @username_len: Length of username
276  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
277  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
278  * Returns: 0 on success, -1 on failure
279  */
280 int generate_authenticator_response(const u8 *password, size_t password_len,
281                                     const u8 *peer_challenge,
282                                     const u8 *auth_challenge,
283                                     const u8 *username, size_t username_len,
284                                     const u8 *nt_response, u8 *response)
285 {
286         u8 password_hash[16];
287         if (nt_password_hash(password, password_len, password_hash))
288                 return -1;
289         return generate_authenticator_response_pwhash(
290                 password_hash, peer_challenge, auth_challenge,
291                 username, username_len, nt_response, response);
292 }
293
294
295 /**
296  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
297  * @challenge: 8-octet Challenge (IN)
298  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
299  * @password_len: Length of password
300  * @response: 24-octet Response (OUT)
301  * Returns: 0 on success, -1 on failure
302  */
303 int nt_challenge_response(const u8 *challenge, const u8 *password,
304                           size_t password_len, u8 *response)
305 {
306         u8 password_hash[16];
307         if (nt_password_hash(password, password_len, password_hash))
308                 return -1;
309         challenge_response(challenge, password_hash, response);
310         return 0;
311 }
312
313
314 /**
315  * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
316  * @password_hash_hash: 16-octet PasswordHashHash (IN)
317  * @nt_response: 24-octet NTResponse (IN)
318  * @master_key: 16-octet MasterKey (OUT)
319  * Returns: 0 on success, -1 on failure
320  */
321 int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
322                    u8 *master_key)
323 {
324         static const u8 magic1[27] = {
325                 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
326                 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
327                 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
328         };
329         const unsigned char *addr[3];
330         const size_t len[3] = { 16, 24, sizeof(magic1) };
331         u8 hash[SHA1_MAC_LEN];
332
333         addr[0] = password_hash_hash;
334         addr[1] = nt_response;
335         addr[2] = magic1;
336
337         if (sha1_vector(3, addr, len, hash))
338                 return -1;
339         os_memcpy(master_key, hash, 16);
340         return 0;
341 }
342
343
344 /**
345  * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
346  * @master_key: 16-octet MasterKey (IN)
347  * @session_key: 8-to-16 octet SessionKey (OUT)
348  * @session_key_len: SessionKeyLength (Length of session_key) (IN)
349  * @is_send: IsSend (IN, BOOLEAN)
350  * @is_server: IsServer (IN, BOOLEAN)
351  * Returns: 0 on success, -1 on failure
352  */
353 int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
354                             size_t session_key_len, int is_send,
355                             int is_server)
356 {
357         static const u8 magic2[84] = {
358                 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
359                 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
360                 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
361                 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
362                 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
363                 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
364                 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
365                 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
366                 0x6b, 0x65, 0x79, 0x2e
367         };
368         static const u8 magic3[84] = {
369                 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
370                 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
371                 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
372                 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
373                 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
374                 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
375                 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
376                 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
377                 0x6b, 0x65, 0x79, 0x2e
378         };
379         static const u8 shs_pad1[40] = {
380                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
384         };
385
386         static const u8 shs_pad2[40] = {
387                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
388                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
389                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
390                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
391         };
392         u8 digest[SHA1_MAC_LEN];
393         const unsigned char *addr[4];
394         const size_t len[4] = { 16, 40, 84, 40 };
395
396         addr[0] = master_key;
397         addr[1] = shs_pad1;
398         if (is_send) {
399                 addr[2] = is_server ? magic3 : magic2;
400         } else {
401                 addr[2] = is_server ? magic2 : magic3;
402         }
403         addr[3] = shs_pad2;
404
405         if (sha1_vector(4, addr, len, digest))
406                 return -1;
407
408         if (session_key_len > SHA1_MAC_LEN)
409                 session_key_len = SHA1_MAC_LEN;
410         os_memcpy(session_key, digest, session_key_len);
411         return 0;
412 }
413
414
415 #ifndef CONFIG_NO_RC4
416
417 #define PWBLOCK_LEN 516
418
419 /**
420  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
421  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
422  * @password_len: Length of password
423  * @password_hash: 16-octet PasswordHash (IN)
424  * @pw_block: 516-byte PwBlock (OUT)
425  * Returns: 0 on success, -1 on failure
426  */
427 int encrypt_pw_block_with_password_hash(
428         const u8 *password, size_t password_len,
429         const u8 *password_hash, u8 *pw_block)
430 {
431         size_t ucs2_len, offset;
432         u8 *pos;
433
434         os_memset(pw_block, 0, PWBLOCK_LEN);
435
436         if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
437             || ucs2_len > 256)
438                 return -1;
439
440         offset = (256 - ucs2_len) * 2;
441         if (offset != 0) {
442                 os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
443                 if (os_get_random(pw_block, offset) < 0)
444                         return -1;
445         }
446         /*
447          * PasswordLength is 4 octets, but since the maximum password length is
448          * 256, only first two (in little endian byte order) can be non-zero.
449          */
450         pos = &pw_block[2 * 256];
451         WPA_PUT_LE16(pos, password_len * 2);
452         rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
453         return 0;
454 }
455
456
457 /**
458  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
459  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
460  * @new_password_len: Length of new_password
461  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
462  * @old_password_len: Length of old_password
463  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
464  * Returns: 0 on success, -1 on failure
465  */
466 int new_password_encrypted_with_old_nt_password_hash(
467         const u8 *new_password, size_t new_password_len,
468         const u8 *old_password, size_t old_password_len,
469         u8 *encrypted_pw_block)
470 {
471         u8 password_hash[16];
472
473         if (nt_password_hash(old_password, old_password_len, password_hash))
474                 return -1;
475         if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
476                                                 password_hash,
477                                                 encrypted_pw_block))
478                 return -1;
479         return 0;
480 }
481
482 #endif /* CONFIG_NO_RC4 */
483
484
485 /**
486  * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
487  * @password_hash: 16-octer PasswordHash (IN)
488  * @block: 16-octet Block (IN)
489  * @cypher: 16-octer Cypher (OUT)
490  */
491 void nt_password_hash_encrypted_with_block(const u8 *password_hash,
492                                            const u8 *block, u8 *cypher)
493 {
494         des_encrypt(password_hash, block, cypher);
495         des_encrypt(password_hash + 8, block + 7, cypher + 8);
496 }
497
498
499 /**
500  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
501  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
502  * @new_password_len: Length of new_password
503  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
504  * @old_password_len: Length of old_password
505  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
506  * Returns: 0 on success, -1 on failure
507  */
508 int old_nt_password_hash_encrypted_with_new_nt_password_hash(
509         const u8 *new_password, size_t new_password_len,
510         const u8 *old_password, size_t old_password_len,
511         u8 *encrypted_password_hash)
512 {
513         u8 old_password_hash[16], new_password_hash[16];
514
515         if (nt_password_hash(old_password, old_password_len,
516                              old_password_hash) ||
517             nt_password_hash(new_password, new_password_len,
518                              new_password_hash))
519                 return -1;
520         nt_password_hash_encrypted_with_block(old_password_hash,
521                                               new_password_hash,
522                                               encrypted_password_hash);
523         return 0;
524 }