Disconnect hostapd from building in base
[dragonfly.git] / contrib / hostapd / 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                         }
62                 }
63         }
64
65         if (ucs2_string_size)
66                 *ucs2_string_size = j / 2;
67         return 0;
68 }
69
70
71 /**
72  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
73  * @peer_challenge: 16-octet PeerChallenge (IN)
74  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
75  * @username: 0-to-256-char UserName (IN)
76  * @username_len: Length of username
77  * @challenge: 8-octet Challenge (OUT)
78  * Returns: 0 on success, -1 on failure
79  */
80 static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
81                           const u8 *username, size_t username_len,
82                           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                 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  */
196 int 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  */
225 int 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  */
284 int 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  */
307 int 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  */
325 int 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  */
357 int 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  */
429 int 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  */
470 int 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  */
493 void 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  */
510 int 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 }