]> git.ozlabs.org Git - ppp.git/blob - pppd/chap_ms.c
Update copyrights. The new CMU copyright notice is from CMU and now
[ppp.git] / pppd / chap_ms.c
1 /*
2  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
3  *
4  * Copyright (c) 1995 Eric Rosenquist.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * 3. The name(s) of the authors of this software must not be used to
19  *    endorse or promote products derived from this software without
20  *    prior written permission.
21  *
22  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29  */
30
31 /*
32  * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
33  *
34  *   Implemented LANManager type password response to MS-CHAP challenges.
35  *   Now pppd provides both NT style and LANMan style blocks, and the
36  *   prefered is set by option "ms-lanman". Default is to use NT.
37  *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
38  *
39  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
40  */
41
42 /*
43  * Modifications by Frank Cusack, frank@google.com, March 2002.
44  *
45  *   Implemented MS-CHAPv2 functionality, heavily based on sample
46  *   implementation in RFC 2759.  Implemented MPPE functionality,
47  *   heavily based on sample implementation in RFC 3079.
48  *   Copyright (c) 2002 Google, Inc.
49  */
50
51 #define RCSID   "$Id: chap_ms.c,v 1.25 2002/12/04 23:03:32 paulus Exp $"
52
53 #ifdef CHAPMS
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <ctype.h>
59 #include <sys/types.h>
60 #include <sys/time.h>
61 #include <unistd.h>
62
63 #include "pppd.h"
64 #include "chap.h"
65 #include "chap_ms.h"
66 #include "md4.h"
67 #include "sha1.h"
68 #include "pppcrypt.h"
69
70 static const char rcsid[] = RCSID;
71
72
73 static void     ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
74 static void     ascii2unicode __P((char[], int, u_char[]));
75 static void     NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
76 static void     ChallengeResponse __P((u_char *, u_char *, u_char[24]));
77 static void     ChapMS_NT __P((u_char *, char *, int, u_char[24]));
78 static void     ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
79                                 u_char[24]));
80 static void     GenerateAuthenticatorResponse __P((char*, int, u_char[24],
81                                                    u_char[16], u_char *,
82                                                    char *, u_char[41]));
83 #ifdef MSLANMAN
84 static void     ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
85 #endif
86
87 #ifdef MPPE
88 static void     Set_Start_Key __P((u_char *, char *, int));
89 static void     SetMasterKeys __P((char *, int, u_char[24], int));
90 #endif
91
92 extern double drand48 __P((void));
93
94 #ifdef MSLANMAN
95 bool    ms_lanman = 0;          /* Use LanMan password instead of NT */
96                                 /* Has meaning only with MS-CHAP challenges */
97 #endif
98
99 #ifdef MPPE
100 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
101 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
102 #endif
103
104 static void
105 ChallengeResponse(u_char *challenge,
106                   u_char PasswordHash[MD4_SIGNATURE_SIZE],
107                   u_char response[24])
108 {
109     u_char    ZPasswordHash[21];
110
111     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
112     BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
113
114 #if 0
115     dbglog("ChallengeResponse - ZPasswordHash %.*B",
116            sizeof(ZPasswordHash), ZPasswordHash);
117 #endif
118
119     (void) DesSetkey(ZPasswordHash + 0);
120     DesEncrypt(challenge, response + 0);
121     (void) DesSetkey(ZPasswordHash + 7);
122     DesEncrypt(challenge, response + 8);
123     (void) DesSetkey(ZPasswordHash + 14);
124     DesEncrypt(challenge, response + 16);
125
126 #if 0
127     dbglog("ChallengeResponse - response %.24B", response);
128 #endif
129 }
130
131 static void
132 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
133               char *username, u_char Challenge[8])
134     
135 {
136     SHA1_CTX    sha1Context;
137     u_char      sha1Hash[SHA1_SIGNATURE_SIZE];
138     char        *user;
139
140     /* remove domain from "domain\username" */
141     if ((user = strrchr(username, '\\')) != NULL)
142         ++user;
143     else
144         user = username;
145
146     SHA1_Init(&sha1Context);
147     SHA1_Update(&sha1Context, PeerChallenge, 16);
148     SHA1_Update(&sha1Context, rchallenge, 16);
149     SHA1_Update(&sha1Context, user, strlen(user));
150     SHA1_Final(sha1Hash, &sha1Context);
151
152     BCOPY(sha1Hash, Challenge, 8);
153 }
154
155 /*
156  * Convert the ASCII version of the password to Unicode.
157  * This implicitly supports 8-bit ISO8859/1 characters.
158  * This gives us the little-endian representation, which
159  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
160  * is machine-dependent.)
161  */
162 static void
163 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
164 {
165     int i;
166
167     BZERO(unicode, ascii_len * 2);
168     for (i = 0; i < ascii_len; i++)
169         unicode[i * 2] = (u_char) ascii[i];
170 }
171
172 static void
173 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
174 {
175 #ifdef __NetBSD__
176     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
177     int                 mdlen = secret_len;
178 #else
179     int                 mdlen = secret_len * 8;
180 #endif
181     MD4_CTX             md4Context;
182
183     MD4Init(&md4Context);
184     MD4Update(&md4Context, secret, mdlen);
185     MD4Final(hash, &md4Context);
186
187 }
188
189 static void
190 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
191           u_char NTResponse[24])
192 {
193     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
194     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
195
196     /* Hash the Unicode version of the secret (== password). */
197     ascii2unicode(secret, secret_len, unicodePassword);
198     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
199
200     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
201 }
202
203 static void
204 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
205            char *secret, int secret_len, u_char NTResponse[24])
206 {
207     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
208     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
209     u_char      Challenge[8];
210
211     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
212
213     /* Hash the Unicode version of the secret (== password). */
214     ascii2unicode(secret, secret_len, unicodePassword);
215     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
216
217     ChallengeResponse(Challenge, PasswordHash, NTResponse);
218 }
219
220 #ifdef MSLANMAN
221 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
222
223 static void
224 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
225               MS_ChapResponse *response)
226 {
227     int                 i;
228     u_char              UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
229     u_char              PasswordHash[MD4_SIGNATURE_SIZE];
230
231     /* LANMan password is case insensitive */
232     BZERO(UcasePassword, sizeof(UcasePassword));
233     for (i = 0; i < secret_len; i++)
234        UcasePassword[i] = (u_char)toupper(secret[i]);
235     (void) DesSetkey(UcasePassword + 0);
236     DesEncrypt( StdText, PasswordHash + 0 );
237     (void) DesSetkey(UcasePassword + 7);
238     DesEncrypt( StdText, PasswordHash + 8 );
239     ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
240 }
241 #endif
242
243
244 static void
245 GenerateAuthenticatorResponse(char *secret, int secret_len,
246                               u_char NTResponse[24], u_char PeerChallenge[16],
247                               u_char *rchallenge, char *username,
248                               u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
249 {
250     /*
251      * "Magic" constants used in response generation, from RFC 2759.
252      */
253     u_char Magic1[39] = /* "Magic server to client signing constant" */
254         { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
255           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
256           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
257           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
258     u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
259         { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
260           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
261           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
262           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
263           0x6E };
264
265     int         i;
266     SHA1_CTX    sha1Context;
267     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
268     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
269     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
270     u_char      Digest[SHA1_SIGNATURE_SIZE];
271     u_char      Challenge[8];
272
273     /* Hash (x2) the Unicode version of the secret (== password). */
274     ascii2unicode(secret, secret_len, unicodePassword);
275     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
276     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
277
278     SHA1_Init(&sha1Context);
279     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
280     SHA1_Update(&sha1Context, NTResponse, 24);
281     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
282     SHA1_Final(Digest, &sha1Context);
283
284     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
285
286     SHA1_Init(&sha1Context);
287     SHA1_Update(&sha1Context, Digest, sizeof(Digest));
288     SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
289     SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
290     SHA1_Final(Digest, &sha1Context);
291
292     /* Convert to ASCII hex string. */
293     for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
294         sprintf(&authResponse[i * 2], "%02X", Digest[i]);
295 }
296
297
298 #ifdef MPPE
299 /*
300  * Set mppe_xxxx_key from the NTPasswordHashHash.
301  * RFC 2548 (RADIUS support) requires us to export this function (ugh).
302  */
303 void
304 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
305 {
306     SHA1_CTX    sha1Context;
307     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
308
309     SHA1_Init(&sha1Context);
310     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
311     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
312     SHA1_Update(&sha1Context, rchallenge, 8);
313     SHA1_Final(Digest, &sha1Context);
314
315     /* Same key in both directions. */
316     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
317     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
318 }
319
320 /*
321  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
322  */
323 static void
324 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
325 {
326     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
327     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
328     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
329
330     /* Hash (x2) the Unicode version of the secret (== password). */
331     ascii2unicode(secret, secret_len, unicodePassword);
332     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
333     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
334
335     mppe_set_keys(rchallenge, PasswordHashHash);
336 }
337
338 /*
339  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
340  */
341 static void
342 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
343 {
344     SHA1_CTX    sha1Context;
345     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
346     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
347     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
348     u_char      MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
349     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
350
351     u_char SHApad1[40] =
352         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
356     u_char SHApad2[40] =
357         { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
358           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
359           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
360           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
361
362     /* "This is the MPPE Master Key" */
363     u_char Magic1[27] =
364         { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
365           0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
366           0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
367     /* "On the client side, this is the send key; "
368        "on the server side, it is the receive key." */
369     u_char Magic2[84] =
370         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
371           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
372           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
373           0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
374           0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
375           0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
376           0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
377           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
378           0x6b, 0x65, 0x79, 0x2e };
379     /* "On the client side, this is the receive key; "
380        "on the server side, it is the send key." */
381     u_char Magic3[84] =
382         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
383           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
384           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
385           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
386           0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
387           0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
388           0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
389           0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
390           0x6b, 0x65, 0x79, 0x2e };
391     u_char *s;
392
393     /* Hash (x2) the Unicode version of the secret (== password). */
394     ascii2unicode(secret, secret_len, unicodePassword);
395     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
396     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
397
398     SHA1_Init(&sha1Context);
399     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
400     SHA1_Update(&sha1Context, NTResponse, 24);
401     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
402     SHA1_Final(MasterKey, &sha1Context);
403
404     /*
405      * generate send key
406      */
407     if (IsServer)
408         s = Magic3;
409     else
410         s = Magic2;
411     SHA1_Init(&sha1Context);
412     SHA1_Update(&sha1Context, MasterKey, 16);
413     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
414     SHA1_Update(&sha1Context, s, 84);
415     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
416     SHA1_Final(Digest, &sha1Context);
417
418     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
419
420     /*
421      * generate recv key
422      */
423     if (IsServer)
424         s = Magic2;
425     else
426         s = Magic3;
427     SHA1_Init(&sha1Context);
428     SHA1_Update(&sha1Context, MasterKey, 16);
429     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
430     SHA1_Update(&sha1Context, s, 84);
431     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
432     SHA1_Final(Digest, &sha1Context);
433
434     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
435 }
436
437 #endif /* MPPE */
438
439
440 void
441 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
442        MS_ChapResponse *response)
443 {
444 #if 0
445     CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
446 #endif
447     BZERO(response, sizeof(*response));
448
449     ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
450
451 #ifdef MSLANMAN
452     ChapMS_LANMan(rchallenge, secret, secret_len, response);
453
454     /* preferred method is set by option  */
455     response->UseNT[0] = !ms_lanman;
456 #else
457     response->UseNT[0] = 1;
458 #endif
459
460     cstate->resp_length = MS_CHAP_RESPONSE_LEN;
461
462 #ifdef MPPE
463     Set_Start_Key(rchallenge, secret, secret_len);
464 #endif
465 }
466
467
468 /*
469  * If PeerChallenge is NULL, one is generated and response->PeerChallenge
470  * is filled in.  Call this way when generating a response.
471  * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
472  * Call this way when verifying a response (or debugging).
473  * Do not call with PeerChallenge = response->PeerChallenge.
474  *
475  * response->PeerChallenge is then used for calculation of the
476  * Authenticator Response.
477  */
478 void
479 ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge,
480         char *user, char *secret, int secret_len, MS_Chap2Response *response,
481         u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1], int authenticator)
482 {
483     /* ARGSUSED */
484     u_char *p = response->PeerChallenge;
485     int i;
486
487     BZERO(response, sizeof(*response));
488
489     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
490     if (!PeerChallenge)
491         for (i = 0; i < sizeof(response->PeerChallenge); i++)
492             *p++ = (u_char) (drand48() * 0xff);
493     else
494         BCOPY(PeerChallenge, response->PeerChallenge,
495               sizeof(response->PeerChallenge));
496
497     /* Generate the NT-Response */
498     ChapMS2_NT(rchallenge, response->PeerChallenge, user,
499                secret, secret_len, response->NTResp);
500
501     /* Generate the Authenticator Response. */
502     GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
503                                   response->PeerChallenge, rchallenge,
504                                   user, authResponse);
505
506     cstate->resp_length = MS_CHAP2_RESPONSE_LEN;
507
508 #ifdef MPPE
509     SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
510 #endif
511 }
512
513
514 #endif /* CHAPMS */