1/*
2 * Copyright (c) 2001-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <unistd.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <sys/types.h>
29#include <CommonCrypto/CommonDigest.h>
30#include <CommonCrypto/CommonCryptor.h>
31#include <libkern/OSByteOrder.h>
32#include <stdbool.h>
33#include "mschap.h"
34
35#include "DESSupport.h"
36
37static void
38ChallengeResponse(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE],
39		  const uint8_t password_hash[NT_PASSWORD_HASH_SIZE],
40		  uint8_t response[MSCHAP_NT_RESPONSE_SIZE]);
41
42static void
43password_to_unicode(const uint8_t * password, uint32_t password_len,
44		    uint8_t * unicode_password)
45{
46    int i;
47
48    if (password_len > NT_MAXPWLEN) {
49	password_len = NT_MAXPWLEN;
50    }
51    bzero(unicode_password, password_len * 2);
52    for (i = 0; i < password_len; i++) {
53	unicode_password[i * 2] = password[i];
54    }
55    return;
56}
57
58static void
59NTPasswordHash(const uint8_t * password, uint32_t password_len,
60	       uint8_t hash[NT_PASSWORD_HASH_SIZE])
61{
62    CC_MD4(password, password_len, hash);
63    return;
64}
65
66static void
67NTPasswordHashHash(const uint8_t * password, uint32_t password_len,
68		   uint8_t ret_hash[NT_PASSWORD_HASH_SIZE])
69{
70    uint8_t	hash[NT_PASSWORD_HASH_SIZE];
71
72    NTPasswordHash(password, password_len, hash);
73    NTPasswordHash(hash, NT_PASSWORD_HASH_SIZE, ret_hash);
74    return;
75}
76
77static void
78NTChallengeResponse(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE],
79		    const uint8_t * password, uint32_t password_len,
80		    uint8_t response[MSCHAP_NT_RESPONSE_SIZE])
81{
82    uint8_t 	hash[NT_PASSWORD_HASH_SIZE];
83
84    NTPasswordHash(password, password_len, hash);
85    ChallengeResponse(challenge, hash, response);
86    return;
87}
88
89static void
90NTMPPEChallengeResponse(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE],
91			const uint8_t * password,
92			uint32_t password_len,
93			uint8_t response[MSCHAP_NT_CHALLENGE_SIZE])
94{
95    uint8_t 	hash[NT_PASSWORD_HASH_SIZE];
96
97    NTPasswordHashHash(password, password_len, hash);
98    ChallengeResponse(challenge, hash, response);
99    return;
100}
101
102static void
103ChallengeResponse(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE],
104		  const uint8_t password_hash[NT_PASSWORD_HASH_SIZE],
105		  uint8_t response[MSCHAP_NT_RESPONSE_SIZE])
106{
107    uint8_t	zhash[21];
108
109    /* zero pad the password hash to 21 bytes */
110    bzero(zhash, 21);
111    bcopy(password_hash, zhash, NT_PASSWORD_HASH_SIZE);
112
113    DesEncrypt(challenge, zhash, response);
114    DesEncrypt(challenge, zhash + 7, response + 8);
115    DesEncrypt(challenge, zhash + 14, response + 16);
116    return;
117}
118
119static void
120ChallengeHash(const uint8_t peer_challenge[MSCHAP2_CHALLENGE_SIZE],
121	      const uint8_t auth_challenge[MSCHAP2_CHALLENGE_SIZE],
122	      const uint8_t * username,
123	      uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE])
124{
125    const uint8_t *	user;
126    CC_SHA1_CTX		context;
127    uint8_t		hash[CC_SHA1_DIGEST_LENGTH];
128
129    /* find the last backslash to get the user name to use for the hash */
130    user = (const uint8_t *)strrchr((const char *)username, '\\');
131    if (user == NULL) {
132	user = username;
133    }
134    else {
135	user = user + 1;
136    }
137    CC_SHA1_Init(&context);
138    CC_SHA1_Update(&context, peer_challenge, MSCHAP2_CHALLENGE_SIZE);
139    CC_SHA1_Update(&context, auth_challenge, MSCHAP2_CHALLENGE_SIZE);
140    CC_SHA1_Update(&context, user, (int)strlen((const char *)user));
141    CC_SHA1_Final(hash, &context);
142    bcopy(hash, challenge, MSCHAP_NT_CHALLENGE_SIZE);
143    return;
144}
145
146
147
148static const uint8_t	magic1[39] = {
149    0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
150    0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
151    0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
152    0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
153
154static const uint8_t	magic2[41] = {
155    0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
156    0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
157    0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
158    0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
159    0x6E};
160
161static void
162GenerateAuthResponse(uint8_t * password, uint32_t password_len,
163		     const uint8_t nt_response[MSCHAP_NT_RESPONSE_SIZE],
164		     const uint8_t peer_challenge[MSCHAP2_CHALLENGE_SIZE],
165		     const uint8_t auth_challenge[MSCHAP2_CHALLENGE_SIZE],
166		     const uint8_t * username,
167		     uint8_t auth_response[MSCHAP2_AUTH_RESPONSE_SIZE])
168{
169    uint8_t		challenge[MSCHAP_NT_CHALLENGE_SIZE];
170    CC_SHA1_CTX		context;
171    int			i;
172    uint8_t		hash[CC_SHA1_DIGEST_LENGTH];
173    uint8_t		password_hash[NT_PASSWORD_HASH_SIZE];
174    uint8_t *		scan;
175
176    NTPasswordHashHash(password, password_len, password_hash);
177
178    CC_SHA1_Init(&context);
179    CC_SHA1_Update(&context, password_hash, NT_PASSWORD_HASH_SIZE);
180    CC_SHA1_Update(&context, nt_response, MSCHAP_NT_RESPONSE_SIZE);
181    CC_SHA1_Update(&context, magic1, 39);
182    CC_SHA1_Final(hash, &context);
183
184    ChallengeHash(peer_challenge, auth_challenge, username,
185		  challenge);
186
187    CC_SHA1_Init(&context);
188    CC_SHA1_Update(&context, hash, CC_SHA1_DIGEST_LENGTH);
189    CC_SHA1_Update(&context, challenge, MSCHAP_NT_CHALLENGE_SIZE);
190    CC_SHA1_Update(&context, magic2, 41);
191    CC_SHA1_Final(hash, &context);
192
193    /*
194     * Encode the value of 'hash' as "S=" followed by
195     * 40 ASCII hexadecimal digits and return it in
196     * 'auth_response'.
197     * For example,
198     *   "S=0123456789ABCDEF0123456789ABCDEF01234567"
199     */
200    auth_response[0] = 'S';
201    auth_response[1] = '=';
202    for (i = 0, scan = auth_response + 2;
203	 i < CC_SHA1_DIGEST_LENGTH; i++, scan +=2) {
204	char	hexstr[3];
205	snprintf(hexstr, 3, "%02X", hash[i]);
206	scan[0] = hexstr[0];
207	scan[1] = hexstr[1];
208    }
209    return;
210}
211
212/*
213 * Exported Functions
214 */
215
216#define HASH_INPUT_SIZE	(NT_PASSWORD_HASH_SIZE + (MSCHAP_NT_CHALLENGE_SIZE + MSCHAP_NT_RESPONSE_SIZE) * 2)
217
218void
219NTSessionKey16(const uint8_t * password, uint32_t password_len,
220	       const uint8_t client_challenge[MSCHAP_NT_CHALLENGE_SIZE],
221	       const uint8_t server_response[MSCHAP_NT_RESPONSE_SIZE],
222	       const uint8_t server_challenge[MSCHAP_NT_CHALLENGE_SIZE],
223	       uint8_t key[NT_SESSION_KEY_SIZE])
224{
225    uint8_t 	input[HASH_INPUT_SIZE];
226    int		offset;
227    uint8_t	unicode_password[NT_MAXPWLEN * 2];
228
229    /* add hash of the hash of the unicode password */
230    offset = 0;
231    password_to_unicode(password, password_len, unicode_password);
232    NTPasswordHashHash(unicode_password, password_len * 2, input);
233    offset += NT_PASSWORD_HASH_SIZE;
234
235    /* add the client challenge */
236    bcopy(client_challenge, input + offset, MSCHAP_NT_CHALLENGE_SIZE);
237    offset += MSCHAP_NT_CHALLENGE_SIZE;
238
239    /* add the server response */
240    bcopy(server_response, input + offset, MSCHAP_NT_RESPONSE_SIZE);
241    offset += MSCHAP_NT_RESPONSE_SIZE;
242
243    /* add the server challenge */
244    bcopy(server_challenge, input + offset, MSCHAP_NT_CHALLENGE_SIZE);
245    offset += MSCHAP_NT_CHALLENGE_SIZE;
246
247    /* compute the client response */
248    NTChallengeResponse(server_challenge, unicode_password,
249			password_len * 2, input + offset);
250
251    CC_MD5(input, HASH_INPUT_SIZE, key);
252    return;
253}
254
255void
256MSChap(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE],
257       const uint8_t * password, uint32_t password_len,
258       uint8_t response[MSCHAP_NT_RESPONSE_SIZE])
259{
260    uint8_t	unicode_password[NT_MAXPWLEN * 2];
261
262    password_to_unicode(password, password_len, unicode_password);
263    NTChallengeResponse(challenge, unicode_password, password_len * 2,
264			response);
265    return;
266}
267
268void
269MSChap_MPPE(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE],
270	    const uint8_t * password, uint32_t password_len,
271	    uint8_t response[MSCHAP_NT_RESPONSE_SIZE])
272{
273    uint8_t	unicode_password[NT_MAXPWLEN * 2];
274
275    password_to_unicode(password, password_len, unicode_password);
276    NTMPPEChallengeResponse(challenge, unicode_password,
277			    password_len * 2, response);
278    return;
279}
280
281void
282MSChap2(const uint8_t auth_challenge[MSCHAP2_CHALLENGE_SIZE],
283	const uint8_t peer_challenge[MSCHAP2_CHALLENGE_SIZE],
284	const uint8_t * username,
285	const uint8_t * password, uint32_t password_len,
286	uint8_t response[MSCHAP_NT_RESPONSE_SIZE])
287{
288    uint8_t	unicode_password[NT_MAXPWLEN * 2];
289    uint8_t	challenge[MSCHAP_NT_CHALLENGE_SIZE];
290
291    ChallengeHash(peer_challenge, auth_challenge, username,
292		  challenge);
293    password_to_unicode(password, password_len, unicode_password);
294    NTChallengeResponse(challenge, unicode_password, password_len * 2,
295			response);
296    return;
297}
298
299bool
300MSChap2AuthResponseValid(const uint8_t * password, uint32_t password_len,
301			 const uint8_t nt_response[MSCHAP_NT_RESPONSE_SIZE],
302			 const uint8_t peer_challenge[MSCHAP2_CHALLENGE_SIZE],
303			 const uint8_t auth_challenge[MSCHAP2_CHALLENGE_SIZE],
304			 const uint8_t * username,
305			 const uint8_t response[MSCHAP2_AUTH_RESPONSE_SIZE])
306{
307    uint8_t	my_response[MSCHAP2_AUTH_RESPONSE_SIZE];
308    uint8_t	unicode_password[NT_MAXPWLEN * 2];
309
310    password_to_unicode(password, password_len, unicode_password);
311
312    GenerateAuthResponse(unicode_password, password_len * 2,
313			 nt_response,
314			 peer_challenge,
315			 auth_challenge,
316			 username,
317			 my_response);
318    if (bcmp(my_response, response, MSCHAP2_AUTH_RESPONSE_SIZE)) {
319	return (false);
320    }
321    return (true);
322}
323
324static void
325rc4_encrypt(const void * clear, uint32_t clear_length,
326	    const void * key, uint32_t key_length,
327	    void * cypher)
328{
329    size_t 		bytes_processed;
330    CCCryptorStatus	status;
331
332    /* sizeof(cypher) == clear_length */
333    status = CCCrypt(kCCEncrypt, kCCAlgorithmRC4, 0,
334		     key, key_length, NULL,
335		     clear, clear_length,
336		     cypher, clear_length,
337		     &bytes_processed);
338    if (status != kCCSuccess) {
339	fprintf(stderr, "rc4_encrypt: CCCrypt failed with %d\n",
340		status);
341	return;
342    }
343    return;
344}
345
346static void
347EncryptPwBlockWithPasswordHash(const uint8_t * password,
348			       uint32_t password_len,
349			       const uint8_t pw_hash[NT_PASSWORD_HASH_SIZE],
350			       NTPasswordBlockRef pwblock)
351{
352    NTPasswordBlock	clear_pwblock;
353    int			offset;
354    uint32_t		password_len_little_endian;
355
356    MSChapFillWithRandom(&clear_pwblock, sizeof(clear_pwblock));
357    offset = sizeof(clear_pwblock.password) - password_len;
358    bcopy(password, ((void *)&clear_pwblock) + offset, password_len);
359    /* convert password length to little endian */
360    password_len_little_endian = OSSwapHostToLittleInt32(password_len);
361    bcopy(&password_len_little_endian, clear_pwblock.password_length,
362	  sizeof(uint32_t));
363    rc4_encrypt(&clear_pwblock, sizeof(clear_pwblock),
364		pw_hash, NT_PASSWORD_HASH_SIZE, pwblock);
365    return;
366}
367
368/*
369 * RFC 2759, Section 8.9
370 *   NewPasswordEncryptedWithOldNtPasswordHash
371 */
372void
373NTPasswordBlockEncryptNewPasswordWithOldHash(const uint8_t * new_password,
374					     uint32_t new_password_len,
375					     const uint8_t * old_password,
376					     uint32_t old_password_len,
377					     NTPasswordBlockRef pwblock)
378{
379    uint8_t	hash[NT_PASSWORD_HASH_SIZE];
380    uint8_t	new_password_unicode[NT_MAXPWLEN * 2];
381    uint8_t	old_password_unicode[NT_MAXPWLEN * 2];
382
383    password_to_unicode(new_password, new_password_len, new_password_unicode);
384    password_to_unicode(old_password, old_password_len, old_password_unicode);
385
386    NTPasswordHash(old_password_unicode, old_password_len * 2, hash);
387    EncryptPwBlockWithPasswordHash(new_password_unicode,
388				   new_password_len * 2,
389				   hash, pwblock);
390    return;
391}
392
393/*
394 * NtPasswordHashEncryptedWithBlock()
395 */
396static void
397NTPasswordHashEncryptedWithBlock(const uint8_t pw_hash[NT_PASSWORD_HASH_SIZE],
398				 const uint8_t block[NT_PASSWORD_HASH_SIZE],
399				 uint8_t cypher[NT_PASSWORD_HASH_SIZE])
400{
401    DesEncrypt(pw_hash, block, cypher);
402    DesEncrypt(pw_hash + 8, block + 7, cypher + 8);
403    return;
404}
405
406
407/*
408 * RFC 2759, Section 8.12
409 * OldNtPasswordHashEncryptedWithNewNtPasswordHash()
410 */
411void
412NTPasswordHashEncryptOldWithNew(const uint8_t * new_password,
413				uint32_t new_password_len,
414				const uint8_t * old_password,
415				uint32_t old_password_len,
416				uint8_t encrypted_hash[NT_PASSWORD_HASH_SIZE])
417{
418    uint8_t	new_password_unicode[NT_MAXPWLEN * 2];
419    uint8_t	new_pw_hash[NT_PASSWORD_HASH_SIZE];
420    uint8_t	old_password_unicode[NT_MAXPWLEN * 2];
421    uint8_t	old_pw_hash[NT_PASSWORD_HASH_SIZE];
422
423    password_to_unicode(new_password, new_password_len, new_password_unicode);
424    NTPasswordHash(new_password_unicode, new_password_len * 2, new_pw_hash);
425
426    password_to_unicode(old_password, old_password_len, old_password_unicode);
427    NTPasswordHash(old_password_unicode, old_password_len * 2, old_pw_hash);
428
429    NTPasswordHashEncryptedWithBlock(old_pw_hash, new_pw_hash,
430				     encrypted_hash);
431    return;
432}
433
434void
435MSChapFillWithRandom(void * buf, uint32_t len)
436{
437    int			i;
438    int			n;
439    u_int32_t * 	p = (u_int32_t *)buf;
440
441    n = len / sizeof(*p);
442    for (i = 0; i < n; i++, p++) {
443	*p = arc4random();
444    }
445    return;
446}
447
448/**
449 ** RFC 3079
450 ** MPPE functions
451 **/
452
453/*
454 * Pads used in key derivation
455 */
456
457const static uint8_t 	SHSpad1[40] =
458    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
460      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
461      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
462
463const static uint8_t 	SHSpad2[40] =
464    { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
465      0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
466      0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
467      0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
468
469/*
470 * "Magic" constants used in key derivations
471 */
472
473const static uint8_t 	Magic1[27] =
474    { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
475      0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
476      0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
477
478#define MAGIC2_3_SIZE	84
479#define MAGIC2_SIZE	MAGIC2_3_SIZE
480#define MAGIC3_SIZE	MAGIC2_3_SIZE
481
482const static uint8_t	Magic2[MAGIC2_SIZE] =
483    { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
484      0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
485      0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
486      0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
487      0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
488      0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
489      0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
490      0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
491      0x6b, 0x65, 0x79, 0x2e };
492
493const static uint8_t	Magic3[MAGIC3_SIZE] =
494    { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
495      0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
496      0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
497      0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
498      0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
499      0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
500      0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
501      0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
502      0x6b, 0x65, 0x79, 0x2e };
503
504static void
505GetMasterKey(const uint8_t PasswordHashHash[NT_PASSWORD_HASH_SIZE],
506	     const uint8_t NTResponse[MSCHAP_NT_RESPONSE_SIZE],
507	     uint8_t MasterKey[NT_MASTER_KEY_SIZE])
508{
509    CC_SHA1_CTX		context;
510    uint8_t		Digest[CC_SHA1_DIGEST_LENGTH];
511
512    memset(Digest, 0, sizeof(Digest));
513
514    CC_SHA1_Init(&context);
515    CC_SHA1_Update(&context, PasswordHashHash, NT_PASSWORD_HASH_SIZE);
516    CC_SHA1_Update(&context, NTResponse, MSCHAP_NT_RESPONSE_SIZE);
517    CC_SHA1_Update(&context, Magic1, sizeof(Magic1));
518    CC_SHA1_Final(Digest, &context);
519    memcpy(MasterKey, Digest, NT_MASTER_KEY_SIZE);
520    return;
521}
522
523void
524MSChap2_MPPEGetMasterKey(const uint8_t * password, uint32_t password_len,
525			 const uint8_t NTResponse[MSCHAP_NT_RESPONSE_SIZE],
526			 uint8_t MasterKey[NT_MASTER_KEY_SIZE])
527{
528    uint8_t 	password_hash[NT_PASSWORD_HASH_SIZE];
529    uint8_t	unicode_password[NT_MAXPWLEN * 2];
530
531    password_to_unicode(password, password_len, unicode_password);
532
533    NTPasswordHashHash(unicode_password, password_len * 2, password_hash);
534    GetMasterKey(password_hash, NTResponse, MasterKey);
535}
536
537void
538MSChap2_MPPEGetAsymetricStartKey(const uint8_t MasterKey[NT_MASTER_KEY_SIZE],
539				 uint8_t SessionKey[NT_SESSION_KEY_SIZE],
540				 int SessionKeyLength,
541				 bool IsSend,
542				 bool IsServer)
543{
544    CC_SHA1_CTX		context;
545    uint8_t		Digest[CC_SHA1_DIGEST_LENGTH];
546    const uint8_t *	s;
547
548    /*
549     * The logic in the spec says:
550     *  if (IsSend) {
551     *	    if (IsServer) {
552     *         	s = Magic3;
553     *	    }
554     *	    else {
555     *	    	s = Magic2;
556     *	    }
557     * 	}
558     *  else {
559     *	    if (IsServer) {
560     *      	s = Magic2;
561     *	    }
562     *	    else {
563     *      	s = Magic3;
564     *	    }
565     *	}
566     *
567     * The corresponding truth table is:
568     * IsSend	IsServer	s
569     *   0	  0		Magic3
570     *   0	  1		Magic2
571     *   1	  0		Magic2
572     *   1	  1		Magic3
573     * which is simply:
574     *	s = (IsSend == IsServer) ? Magic3 : Magic2;
575     */
576    s = (IsSend == IsServer) ? Magic3 : Magic2;
577    memset(Digest, 0, sizeof(Digest));
578    CC_SHA1_Init(&context);
579    CC_SHA1_Update(&context, MasterKey, NT_MASTER_KEY_SIZE);
580    CC_SHA1_Update(&context, SHSpad1, sizeof(SHSpad1));
581    CC_SHA1_Update(&context, s, MAGIC2_3_SIZE);
582    CC_SHA1_Update(&context, SHSpad2, sizeof(SHSpad2));
583    CC_SHA1_Final(Digest, &context);
584
585    if (SessionKeyLength > NT_SESSION_KEY_SIZE) {
586	SessionKeyLength = NT_SESSION_KEY_SIZE;
587    }
588    memcpy(SessionKey, Digest, SessionKeyLength);
589    return;
590}
591
592#ifdef TEST_MSCHAP
593
594const char * password = "clientPass";
595const uint8_t nt_response[MSCHAP_NT_RESPONSE_SIZE] = {
596    0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
597    0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
598    0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
599};
600
601const uint8_t PasswordHashHash[NT_PASSWORD_HASH_SIZE] = {
602    0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
603    0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
604};
605
606const uint8_t MasterKey[NT_MASTER_KEY_SIZE] = {
607    0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
608    0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
609};
610
611const uint8_t SendStartKey128[NT_SESSION_KEY_SIZE] ={
612    0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
613    0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
614};
615
616
617int
618main()
619{
620    uint8_t master[NT_MASTER_KEY_SIZE];
621    uint8_t send_start[NT_SESSION_KEY_SIZE];
622
623    MSChap2_MPPEGetMasterKey((const uint8_t *)password, strlen(password),
624			     nt_response, master);
625    if (bcmp(master, MasterKey, NT_MASTER_KEY_SIZE) != 0) {
626	printf("Master Key generation failed\n");
627	exit(1);
628    }
629    printf("Master Key generation successful\n");
630
631    MSChap2_MPPEGetAsymetricStartKey(master,
632				     send_start, sizeof(send_start),
633				     1, 1);
634    if (bcmp(send_start, SendStartKey128, sizeof(send_start)) != 0) {
635	printf("SendStartKey128 generation failed\n");
636	exit(1);
637    }
638    printf("SendStartKey128 generation successful\n");
639    exit(0);
640    return (0);
641}
642#endif /* TEST_MSCHAP */
643