add /etc/ppp/peers
[ppp.git] / pppd / chap_ms.c
1 /*
2  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
3  *
4  * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
5  * http://www.strataware.com/
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms are permitted
10  * provided that the above copyright notice and this paragraph are
11  * duplicated in all such forms and that any documentation,
12  * advertising materials, and other materials related to such
13  * distribution and use acknowledge that the software was developed
14  * by Eric Rosenquist.  The name of the author may not be used to
15  * endorse or promote products derived from this software without
16  * specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21  */
22
23 #ifndef lint
24 static char rcsid[] = "$Id: chap_ms.c,v 1.1 1996/05/28 00:42:30 paulus Exp $";
25 #endif
26
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/time.h>
30 #include <syslog.h>
31
32 #include "pppd.h"
33 #include "chap.h"
34 #include "chap_ms.h"
35 #include "md4.h"
36
37
38 #ifdef CHAPMS
39 #include <des.h>
40
41 typedef struct {
42     u_char LANManResp[24];
43     u_char NTResp[24];
44     u_char UseNT;               /* If 1, ignore the LANMan response field */
45 } MS_ChapResponse;
46 /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
47    in case this struct gets padded. */
48
49
50 static void     DesEncrypt __P((u_char *, u_char *, u_char *));
51 static void     MakeKey __P((u_char *, u_char *));
52
53
54 static void
55 ChallengeResponse(challenge, pwHash, response)
56     u_char *challenge;  /* IN   8 octets */
57     u_char *pwHash;     /* IN  16 octets */
58     u_char *response;   /* OUT 24 octets */
59 {
60     char    ZPasswordHash[21];
61
62     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
63     BCOPY(pwHash, ZPasswordHash, 16);
64
65 #if 0
66     log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash");
67 #endif
68
69     DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
70     DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
71     DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
72
73 #if 0
74     log_packet(response, 24, "ChallengeResponse - response");
75 #endif
76 }
77
78
79 static void
80 DesEncrypt(clear, key, cipher)
81     u_char *clear;      /* IN  8 octets */
82     u_char *key;        /* IN  7 octets */
83     u_char *cipher;     /* OUT 8 octets */
84 {
85     des_cblock          des_key;
86     des_key_schedule    key_schedule;
87
88     MakeKey(key, des_key);
89
90     des_set_key(&des_key, key_schedule);
91
92 #if 0
93     CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X",
94                clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
95 #endif
96
97     des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
98
99 #if 0
100     CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X",
101                cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
102 #endif
103 }
104
105
106 static u_char Get7Bits(input, startBit)
107     u_char *input;
108     int startBit;
109 {
110     register unsigned int       word;
111
112     word  = (unsigned)input[startBit / 8] << 8;
113     word |= (unsigned)input[startBit / 8 + 1];
114
115     word >>= 15 - (startBit % 8 + 7);
116
117     return word & 0xFE;
118 }
119
120
121 static void MakeKey(key, des_key)
122     u_char *key;        /* IN  56 bit DES key missing parity bits */
123     u_char *des_key;    /* OUT 64 bit DES key with parity bits added */
124 {
125     des_key[0] = Get7Bits(key,  0);
126     des_key[1] = Get7Bits(key,  7);
127     des_key[2] = Get7Bits(key, 14);
128     des_key[3] = Get7Bits(key, 21);
129     des_key[4] = Get7Bits(key, 28);
130     des_key[5] = Get7Bits(key, 35);
131     des_key[6] = Get7Bits(key, 42);
132     des_key[7] = Get7Bits(key, 49);
133
134     des_set_odd_parity((des_cblock *)des_key);
135
136 #if 0
137     CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X",
138                key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
139     CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X",
140                des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
141 #endif
142 }
143
144 #endif /* CHAPMS */
145
146
147 void
148 ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
149     chap_state *cstate;
150     char *rchallenge;
151     int rchallenge_len;
152     char *secret;
153     int secret_len;
154 {
155 #ifdef CHAPMS
156     int                 i;
157     MDstruct            md4Context;
158     MS_ChapResponse     response;
159     u_char              unicodePassword[MAX_NT_PASSWORD * 2];
160
161 #if 0
162     CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
163 #endif
164
165     BZERO(&response, sizeof(response));
166
167     /* Initialize the Unicode version of the secret (== password). */
168     /* This implicitly supports 8-bit ISO8859/1 characters. */
169     BZERO(unicodePassword, sizeof(unicodePassword));
170     for (i = 0; i < secret_len; i++)
171         unicodePassword[i * 2] = (u_char)secret[i];
172
173     MDbegin(&md4Context);
174     MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */
175     MDupdate(&md4Context, NULL, 0);     /* Tell MD4 we're done */
176
177     ChallengeResponse(rchallenge, (char *)md4Context.buffer, response.NTResp);
178
179     response.UseNT = 1;
180
181     BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
182     cstate->resp_length = MS_CHAP_RESPONSE_LEN;
183 #endif /* CHAPMS */
184 }