181464Sbrian/*-
281464Sbrian * Copyright (c) 1997        Gabor Kincses <gabor@acm.org>
381464Sbrian *               1997 - 2001 Brian Somers <brian@Awfulhak.org>
481464Sbrian *          based on work by Eric Rosenquist
581464Sbrian *                           Strata Software Limited.
629841Sbrian * All rights reserved.
729841Sbrian *
881464Sbrian * Redistribution and use in source and binary forms, with or without
981464Sbrian * modification, are permitted provided that the following conditions
1081464Sbrian * are met:
1181464Sbrian * 1. Redistributions of source code must retain the above copyright
1281464Sbrian *    notice, this list of conditions and the following disclaimer.
1381464Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1481464Sbrian *    notice, this list of conditions and the following disclaimer in the
1581464Sbrian *    documentation and/or other materials provided with the distribution.
1629841Sbrian *
1781464Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1881464Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1981464Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2081464Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2181464Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2281464Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2381464Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2481464Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2581464Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2681464Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2781464Sbrian * SUCH DAMAGE.
2830715Sbrian *
2950479Speter * $FreeBSD$
3029841Sbrian */
3129841Sbrian
3244106Sbrian#include <ctype.h>
3358040Sbrian#ifdef __FreeBSD__
3457451Smarkm#include <openssl/des.h>
3568344Sbrian#include <sha.h>
3658040Sbrian#else
3775212Sbrian#include <sys/types.h>
3868344Sbrian#include <stdlib.h>
3996387Sbrian#ifdef __NetBSD__
4096387Sbrian#include <openssl/des.h>
4196387Sbrian#else
4258040Sbrian#include <des.h>
4396387Sbrian#endif
4468344Sbrian#include <openssl/sha.h>
4558040Sbrian#endif
4667910Sbrian#include <md4.h>
4730715Sbrian#include <string.h>
4829841Sbrian
4929841Sbrian#include "chap_ms.h"
5029841Sbrian
5167910Sbrian/*
5267910Sbrian * Documentation & specifications:
5367910Sbrian *
5467910Sbrian * MS-CHAP (CHAP80)	rfc2433
5567910Sbrian * MS-CHAP-V2 (CHAP81)	rfc2759
5667910Sbrian * MPPE key management	draft-ietf-pppext-mppe-keys-02.txt
5767910Sbrian */
5867910Sbrian
5967910Sbrianstatic char SHA1_Pad1[40] =
6067910Sbrian  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6167910Sbrian   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6267910Sbrian   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6367910Sbrian   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
6467910Sbrian
6567910Sbrianstatic char SHA1_Pad2[40] =
6667910Sbrian  {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
6767910Sbrian   0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
6867910Sbrian   0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
6967910Sbrian   0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2};
7067910Sbrian
7129841Sbrian/* unused, for documentation only */
7229841Sbrian/* only NTResp is filled in for FreeBSD */
7336285Sbrianstruct MS_ChapResponse {
7429841Sbrian    u_char LANManResp[24];
7529841Sbrian    u_char NTResp[24];
7629841Sbrian    u_char UseNT;	/* If 1, ignore the LANMan response field */
7736285Sbrian};
7829841Sbrian
7967912Sbrianstatic u_char
8067912SbrianGet7Bits(u_char *input, int startBit)
8129841Sbrian{
8229841Sbrian    register unsigned int	word;
8329841Sbrian
8429841Sbrian    word  = (unsigned)input[startBit / 8] << 8;
8529841Sbrian    word |= (unsigned)input[startBit / 8 + 1];
8629841Sbrian
8729841Sbrian    word >>= 15 - (startBit % 8 + 7);
8829841Sbrian
8929841Sbrian    return word & 0xFE;
9029841Sbrian}
9129841Sbrian
9229841Sbrian/* IN  56 bit DES key missing parity bits
9329841Sbrian   OUT 64 bit DES key with parity bits added */
9467912Sbrianstatic void
9567912SbrianMakeKey(u_char *key, u_char *des_key)
9629841Sbrian{
9729841Sbrian    des_key[0] = Get7Bits(key,  0);
9829841Sbrian    des_key[1] = Get7Bits(key,  7);
9929841Sbrian    des_key[2] = Get7Bits(key, 14);
10029841Sbrian    des_key[3] = Get7Bits(key, 21);
10129841Sbrian    des_key[4] = Get7Bits(key, 28);
10229841Sbrian    des_key[5] = Get7Bits(key, 35);
10329841Sbrian    des_key[6] = Get7Bits(key, 42);
10429841Sbrian    des_key[7] = Get7Bits(key, 49);
10529841Sbrian
10629841Sbrian    des_set_odd_parity((des_cblock *)des_key);
10729841Sbrian}
10829841Sbrian
10944106Sbrianstatic void /* IN 8 octets IN 7 octest OUT 8 octets */
11044106SbrianDesEncrypt(u_char *clear, u_char *key, u_char *cipher)
11144106Sbrian{
11244106Sbrian    des_cblock		des_key;
11344106Sbrian    des_key_schedule	key_schedule;
11444106Sbrian
11544106Sbrian    MakeKey(key, des_key);
11644106Sbrian    des_set_key(&des_key, key_schedule);
11744106Sbrian    des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
11844106Sbrian}
11944106Sbrian
12044106Sbrianstatic void      /* IN 8 octets      IN 16 octets     OUT 24 octets */
12144106SbrianChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
12244106Sbrian{
12344106Sbrian    char    ZPasswordHash[21];
12444106Sbrian
12544106Sbrian    memset(ZPasswordHash, '\0', sizeof ZPasswordHash);
12644106Sbrian    memcpy(ZPasswordHash, pwHash, 16);
12744106Sbrian
12844106Sbrian    DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
12944106Sbrian    DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
13044106Sbrian    DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
13144106Sbrian}
13244106Sbrian
13367910Sbrianvoid
13467912SbrianNtPasswordHash(char *key, int keylen, char *hash)
13598243Sbrian{
13667910Sbrian  MD4_CTX MD4context;
13767910Sbrian
13867910Sbrian  MD4Init(&MD4context);
13967910Sbrian  MD4Update(&MD4context, key, keylen);
14067910Sbrian  MD4Final(hash, &MD4context);
14167910Sbrian}
14267910Sbrian
14367910Sbrianvoid
14467912SbrianHashNtPasswordHash(char *hash, char *hashhash)
14598243Sbrian{
14667910Sbrian  MD4_CTX MD4context;
14767910Sbrian
14867910Sbrian  MD4Init(&MD4context);
14967910Sbrian  MD4Update(&MD4context, hash, 16);
15067910Sbrian  MD4Final(hashhash, &MD4context);
15167910Sbrian}
15267910Sbrian
153134789Sbrianstatic void
15467912SbrianChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge,
155134789Sbrian              char *UserName, char *Challenge)
15667912Sbrian{
15767910Sbrian  SHA_CTX Context;
15867910Sbrian  char Digest[SHA_DIGEST_LENGTH];
15967910Sbrian  char *Name;
16067910Sbrian
16167910Sbrian  Name = strrchr(UserName, '\\');
16298243Sbrian  if(NULL == Name)
16367910Sbrian    Name = UserName;
16467910Sbrian  else
16567910Sbrian    Name++;
16667910Sbrian
16767910Sbrian  SHA1_Init(&Context);
16867910Sbrian
16998243Sbrian  SHA1_Update(&Context, PeerChallenge, 16);
17067910Sbrian  SHA1_Update(&Context, AuthenticatorChallenge, 16);
17169330Sbrian  SHA1_Update(&Context, Name, strlen(Name));
17267910Sbrian
17367910Sbrian  SHA1_Final(Digest, &Context);
17467910Sbrian  memcpy(Challenge, Digest, 8);
17567910Sbrian}
17667910Sbrian
17767910Sbrianvoid
17867912SbrianGenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge,
179134789Sbrian                   char *UserName, char *Password,
18067912Sbrian                   int PasswordLen, char *Response)
18167912Sbrian{
18267910Sbrian  char Challenge[8];
18367910Sbrian  char PasswordHash[16];
18467910Sbrian
185134789Sbrian  ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge);
18667910Sbrian  NtPasswordHash(Password, PasswordLen, PasswordHash);
18767910Sbrian  ChallengeResponse(Challenge, PasswordHash, Response);
18867910Sbrian}
18967910Sbrian
19068344Sbrian#ifndef __FreeBSD__
19168344Sbrian#define LENGTH 20
19279437Sbrianstatic char *
19368344SbrianSHA1_End(SHA_CTX *ctx, char *buf)
19468344Sbrian{
19568344Sbrian    int i;
19668344Sbrian    unsigned char digest[LENGTH];
19768344Sbrian    static const char hex[]="0123456789abcdef";
19868344Sbrian
19968344Sbrian    if (!buf)
20068344Sbrian        buf = malloc(2*LENGTH + 1);
20168344Sbrian    if (!buf)
20268344Sbrian        return 0;
20368344Sbrian    SHA1_Final(digest, ctx);
20468344Sbrian    for (i = 0; i < LENGTH; i++) {
20568344Sbrian        buf[i+i] = hex[digest[i] >> 4];
20668344Sbrian        buf[i+i+1] = hex[digest[i] & 0x0f];
20768344Sbrian    }
20868344Sbrian    buf[i+i] = '\0';
20968344Sbrian    return buf;
21068344Sbrian}
21168344Sbrian#endif
21268344Sbrian
21367910Sbrianvoid
21467912SbrianGenerateAuthenticatorResponse(char *Password, int PasswordLen,
21567912Sbrian                              char *NTResponse, char *PeerChallenge,
21667912Sbrian                              char *AuthenticatorChallenge, char *UserName,
217134789Sbrian                              char *AuthenticatorResponse)
21867912Sbrian{
21967910Sbrian  SHA_CTX Context;
22067910Sbrian  char PasswordHash[16];
22167910Sbrian  char PasswordHashHash[16];
22267910Sbrian  char Challenge[8];
22367910Sbrian  u_char Digest[SHA_DIGEST_LENGTH];
22467910Sbrian  int i;
22567910Sbrian
22667910Sbrian      /*
22767910Sbrian       * "Magic" constants used in response generation
22867910Sbrian       */
22967910Sbrian  char Magic1[39] =
23067910Sbrian         {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
23167910Sbrian          0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
23267910Sbrian          0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
23367910Sbrian          0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
23467910Sbrian
23567910Sbrian
23667910Sbrian  char Magic2[41] =
23767910Sbrian         {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
23867910Sbrian          0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
23967910Sbrian          0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
24067910Sbrian          0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
24167910Sbrian          0x6E};
24267910Sbrian      /*
24367910Sbrian       * Hash the password with MD4
24467910Sbrian       */
24567910Sbrian  NtPasswordHash(Password, PasswordLen, PasswordHash);
24667910Sbrian      /*
24767910Sbrian       * Now hash the hash
24867910Sbrian       */
24967910Sbrian  HashNtPasswordHash(PasswordHash, PasswordHashHash);
25067910Sbrian
25167910Sbrian  SHA1_Init(&Context);
25267910Sbrian  SHA1_Update(&Context, PasswordHashHash, 16);
25367910Sbrian  SHA1_Update(&Context, NTResponse, 24);
25467910Sbrian  SHA1_Update(&Context, Magic1, 39);
25567910Sbrian  SHA1_Final(Digest, &Context);
256134789Sbrian  ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge);
25767910Sbrian  SHA1_Init(&Context);
25867910Sbrian  SHA1_Update(&Context, Digest, 20);
25967910Sbrian  SHA1_Update(&Context, Challenge, 8);
26067910Sbrian  SHA1_Update(&Context, Magic2, 41);
26167910Sbrian
26267910Sbrian      /*
26367910Sbrian       * Encode the value of 'Digest' as "S=" followed by
26467910Sbrian       * 40 ASCII hexadecimal digits and return it in
26567910Sbrian       * AuthenticatorResponse.
26667910Sbrian       * For example,
26767910Sbrian       *   "S=0123456789ABCDEF0123456789ABCDEF01234567"
26867910Sbrian       */
26967910Sbrian  AuthenticatorResponse[0] = 'S';
27067910Sbrian  AuthenticatorResponse[1] = '=';
27167910Sbrian  SHA1_End(&Context, AuthenticatorResponse + 2);
27267910Sbrian  for (i=2; i<42; i++)
27367910Sbrian    AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]);
27467910Sbrian
27567910Sbrian}
27698243Sbrian
27767910Sbrianvoid
27867912SbrianGetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey)
27967912Sbrian{
28067910Sbrian  char Digest[SHA_DIGEST_LENGTH];
28167910Sbrian  SHA_CTX Context;
28267910Sbrian  static char Magic1[27] =
28367910Sbrian      {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
28467910Sbrian       0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
28567910Sbrian       0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79};
28667910Sbrian
28767910Sbrian  SHA1_Init(&Context);
28867910Sbrian  SHA1_Update(&Context, PasswordHashHash, 16);
28967910Sbrian  SHA1_Update(&Context, NTResponse, 24);
29067910Sbrian  SHA1_Update(&Context, Magic1, 27);
29167910Sbrian  SHA1_Final(Digest, &Context);
29267910Sbrian  memcpy(MasterKey, Digest, 16);
29367910Sbrian}
29467910Sbrian
29567910Sbrianvoid
29667912SbrianGetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength,
29767912Sbrian                     int IsSend, int IsServer)
29867912Sbrian{
29967910Sbrian  char Digest[SHA_DIGEST_LENGTH];
30067910Sbrian  SHA_CTX Context;
30167910Sbrian  char *s;
30267910Sbrian
30367910Sbrian  static char Magic2[84] =
30467910Sbrian      {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
30567910Sbrian       0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
30667910Sbrian       0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
30767910Sbrian       0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
30867910Sbrian       0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
30967910Sbrian       0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
31067910Sbrian       0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
31167910Sbrian       0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
31267910Sbrian       0x6b, 0x65, 0x79, 0x2e};
31367910Sbrian
31467910Sbrian  static char Magic3[84] =
31567910Sbrian      {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
31667910Sbrian       0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
31767910Sbrian       0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
31867910Sbrian       0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
31967910Sbrian       0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
32067910Sbrian       0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
32167910Sbrian       0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
32267910Sbrian       0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
32367910Sbrian       0x6b, 0x65, 0x79, 0x2e};
32467910Sbrian
32567910Sbrian  if (IsSend) {
32667910Sbrian     if (IsServer) {
32767910Sbrian        s = Magic3;
32867910Sbrian     } else {
32967910Sbrian        s = Magic2;
33067910Sbrian     }
33167910Sbrian  } else {
33267910Sbrian     if (IsServer) {
33367910Sbrian        s = Magic2;
33467910Sbrian     } else {
33567910Sbrian        s = Magic3;
33667910Sbrian     }
33767910Sbrian  }
33867910Sbrian
33967910Sbrian  SHA1_Init(&Context);
34067910Sbrian  SHA1_Update(&Context, MasterKey, 16);
34167910Sbrian  SHA1_Update(&Context, SHA1_Pad1, 40);
34267910Sbrian  SHA1_Update(&Context, s, 84);
34367910Sbrian  SHA1_Update(&Context, SHA1_Pad2, 40);
34467910Sbrian  SHA1_Final(Digest, &Context);
34567910Sbrian
34667910Sbrian  memcpy(SessionKey, Digest, SessionKeyLength);
34767910Sbrian}
34867910Sbrian
34967910Sbrianvoid
35067912SbrianGetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength,
35167912Sbrian                 char *InterimKey)
35267912Sbrian{
35367910Sbrian  SHA_CTX Context;
35467910Sbrian  char Digest[SHA_DIGEST_LENGTH];
35567910Sbrian
35667910Sbrian  SHA1_Init(&Context);
35767910Sbrian  SHA1_Update(&Context, StartKey, SessionKeyLength);
35867910Sbrian  SHA1_Update(&Context, SHA1_Pad1, 40);
35967910Sbrian  SHA1_Update(&Context, SessionKey, SessionKeyLength);
36067910Sbrian  SHA1_Update(&Context, SHA1_Pad2, 40);
36167910Sbrian  SHA1_Final(Digest, &Context);
36267910Sbrian
36367910Sbrian  memcpy(InterimKey, Digest, SessionKeyLength);
36467910Sbrian}
36567910Sbrian
36667912Sbrian#if 0
36767912Sbrianstatic void
36867912SbrianGet_Key(char *InitialSessionKey, char *CurrentSessionKey,
36967912Sbrian        int LengthOfDesiredKey)
37067912Sbrian{
37167910Sbrian  SHA_CTX Context;
37267910Sbrian  char Digest[SHA_DIGEST_LENGTH];
37367910Sbrian
37467910Sbrian  SHA1_Init(&Context);
37567910Sbrian  SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey);
37667910Sbrian  SHA1_Update(&Context, SHA1_Pad1, 40);
37767910Sbrian  SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey);
37867910Sbrian  SHA1_Update(&Context, SHA1_Pad2, 40);
37967910Sbrian  SHA1_Final(Digest, &Context);
38067910Sbrian
38167910Sbrian  memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey);
38267910Sbrian}
38367912Sbrian#endif
38467910Sbrian
38529841Sbrian/* passwordHash 16-bytes MD4 hashed password
38629841Sbrian   challenge    8-bytes peer CHAP challenge
38729841Sbrian   since passwordHash is in a 24-byte buffer, response is written in there */
38829841Sbrianvoid
38944106Sbrianmschap_NT(char *passwordHash, char *challenge)
39029841Sbrian{
39129841Sbrian    u_char response[24];
39229841Sbrian
39329841Sbrian    ChallengeResponse(challenge, passwordHash, response);
39430715Sbrian    memcpy(passwordHash, response, 24);
39544106Sbrian    passwordHash[24] = 1;		/* NT-style response */
39629841Sbrian}
39744106Sbrian
39844106Sbrianvoid
39944106Sbrianmschap_LANMan(char *digest, char *challenge, char *secret)
40044106Sbrian{
40144106Sbrian  static u_char salt[] = "KGS!@#$%";	/* RASAPI32.dll */
40244106Sbrian  char SECRET[14], *ptr, *end;
40344106Sbrian  u_char hash[16];
40444106Sbrian
40544106Sbrian  end = SECRET + sizeof SECRET;
40644106Sbrian  for (ptr = SECRET; *secret && ptr < end; ptr++, secret++)
40744106Sbrian    *ptr = toupper(*secret);
40844106Sbrian  if (ptr < end)
40944106Sbrian    memset(ptr, '\0', end - ptr);
41044106Sbrian
41144106Sbrian  DesEncrypt(salt, SECRET, hash);
41244106Sbrian  DesEncrypt(salt, SECRET + 7, hash + 8);
41344106Sbrian
41444106Sbrian  ChallengeResponse(challenge, hash, digest);
41544106Sbrian}
416