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