Better MS-CHAP implementation
Backport of the MS-CHAP implementation from pppd-2.4.1 to ipppd. This means ipppd now also supports MS-CHAP without the need for libdes. Patch by Emmanuel Charpentier. Taken from Debian sid Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
This commit is contained in:
parent
d4c28816dd
commit
f9c7fe0ed0
|
@ -73,7 +73,7 @@ endif
|
||||||
|
|
||||||
DEBUG_FLAGS = @CONFIG_IPPPD_DEBUGFLAGS@
|
DEBUG_FLAGS = @CONFIG_IPPPD_DEBUGFLAGS@
|
||||||
COMPILE_FLAGS = @CFLAGS@
|
COMPILE_FLAGS = @CFLAGS@
|
||||||
CFLAGS = -O2 -fomit-frame-pointer -Wall
|
CFLAGS = -O2 -fomit-frame-pointer -Wall -DREQ_SYSOPTIONS=0
|
||||||
VER = 2.2.0
|
VER = 2.2.0
|
||||||
|
|
||||||
# it's a hack
|
# it's a hack
|
||||||
|
|
|
@ -3,6 +3,8 @@ PPP Client Support for Microsoft's CHAP-80
|
||||||
|
|
||||||
Eric Rosenquist rosenqui@strataware.com
|
Eric Rosenquist rosenqui@strataware.com
|
||||||
|
|
||||||
|
(NOTE: ipppd now supports MS-CHAP out of the box -- Paul Slootman 2002-06-25)
|
||||||
|
|
||||||
|
|
||||||
INTRODUCTION
|
INTRODUCTION
|
||||||
|
|
||||||
|
|
229
ipppd/chap_ms.c
229
ipppd/chap_ms.c
|
@ -20,36 +20,79 @@
|
||||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef USE_MSCHAP
|
/*
|
||||||
|
* Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
|
||||||
|
*
|
||||||
|
* Implemented LANManager type password response to MS-CHAP challenges.
|
||||||
|
* Now pppd provides both NT style and LANMan style blocks, and the
|
||||||
|
* prefered is set by option "ms-lanman". Default is to use NT.
|
||||||
|
* The hash text (StdText) was taken from Win95 RASAPI32.DLL.
|
||||||
|
*
|
||||||
|
* You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
|
||||||
|
*/
|
||||||
|
|
||||||
char chap_ms_rcsid[] = "$Id: chap_ms.c,v 1.4 2004/08/30 14:56:36 keil Exp $";
|
char chap_ms_rcsid[] = "$Id: chap_ms.c,v 1.4 2004/08/30 14:56:36 keil Exp $";
|
||||||
|
|
||||||
|
#ifdef USE_MSCHAP
|
||||||
|
#define CHAPMS 1
|
||||||
|
#define MSLANMAN 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CHAPMS
|
||||||
|
|
||||||
|
#define _GNU_SOURCE 1
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <syslog.h>
|
#include <unistd.h>
|
||||||
|
#ifdef HAVE_CRYPT_H
|
||||||
|
#include <crypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "ipppd.h"
|
#include "ipppd.h"
|
||||||
#include "chap.h"
|
#include "chap.h"
|
||||||
#include "chap_ms.h"
|
#include "chap_ms.h"
|
||||||
#include "md4.h"
|
#include "md4.h"
|
||||||
|
|
||||||
#ifdef USE_SSLDES
|
#ifdef USE_SSLDES
|
||||||
#include <ssl/des.h>
|
#include <openssl/des.h>
|
||||||
#else
|
#else
|
||||||
|
#ifndef HAVE_LIBCRYPT
|
||||||
#include <des.h>
|
#include <des.h>
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u_char LANManResp[24];
|
u_char LANManResp[24];
|
||||||
u_char NTResp[24];
|
u_char NTResp[24];
|
||||||
u_char UseNT; /* If 1, ignore the LANMan response field */
|
u_char UseNT; /* If 1, ignore the LANMan response field */
|
||||||
} MS_ChapResponse;
|
} MS_ChapResponse;
|
||||||
#define MS_CHAP_RESPONSE_LEN 49 /* Don't rely on sizeof(MS_ChapResponse) in case of struct padding */
|
/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
|
||||||
|
in case this struct gets padded. */
|
||||||
|
|
||||||
|
|
||||||
|
static void ChallengeResponse __P((u_char *, u_char *, u_char *));
|
||||||
static void DesEncrypt __P((u_char *, u_char *, u_char *));
|
static void DesEncrypt __P((u_char *, u_char *, u_char *));
|
||||||
static void MakeKey __P((u_char *, u_char *));
|
static void MakeKey __P((u_char *, u_char *));
|
||||||
|
static u_char Get7Bits __P((u_char *, int));
|
||||||
|
static void ChapMS_NT __P((char *, int, char *, int, MS_ChapResponse *));
|
||||||
|
#ifdef MSLANMAN
|
||||||
|
static void ChapMS_LANMan __P((char *, int, char *, int, MS_ChapResponse *));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCRYPT
|
||||||
|
static void Expand __P((u_char *, u_char *));
|
||||||
|
static void Collapse __P((u_char *, u_char *));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MSLANMAN
|
||||||
|
/* bool */ int ms_lanman = 0; /* Use LanMan password instead of NT */
|
||||||
|
/* Has meaning only with MS-CHAP challenges */
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ChallengeResponse(challenge, pwHash, response)
|
ChallengeResponse(challenge, pwHash, response)
|
||||||
|
@ -60,10 +103,11 @@ ChallengeResponse(challenge, pwHash, response)
|
||||||
char ZPasswordHash[21];
|
char ZPasswordHash[21];
|
||||||
|
|
||||||
BZERO(ZPasswordHash, sizeof(ZPasswordHash));
|
BZERO(ZPasswordHash, sizeof(ZPasswordHash));
|
||||||
BCOPY(pwHash, ZPasswordHash, 16);
|
BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash");
|
dbglog("ChallengeResponse - ZPasswordHash %.*B",
|
||||||
|
sizeof(ZPasswordHash), ZPasswordHash);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
|
DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
|
||||||
|
@ -71,11 +115,42 @@ ChallengeResponse(challenge, pwHash, response)
|
||||||
DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
|
DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
log_packet(response, 24, "ChallengeResponse - response");
|
dbglog("ChallengeResponse - response %.24B", response);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCRYPT
|
||||||
|
static void
|
||||||
|
DesEncrypt(clear, key, cipher)
|
||||||
|
u_char *clear; /* IN 8 octets */
|
||||||
|
u_char *key; /* IN 7 octets */
|
||||||
|
u_char *cipher; /* OUT 8 octets */
|
||||||
|
{
|
||||||
|
u_char des_key[8];
|
||||||
|
u_char crypt_key[66];
|
||||||
|
u_char des_input[66];
|
||||||
|
|
||||||
|
MakeKey(key, des_key);
|
||||||
|
|
||||||
|
Expand(des_key, crypt_key);
|
||||||
|
setkey(crypt_key);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Expand(clear, des_input);
|
||||||
|
encrypt(des_input, 0);
|
||||||
|
Collapse(des_input, cipher);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* HAVE_LIBCRYPT */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DesEncrypt(clear, key, cipher)
|
DesEncrypt(clear, key, cipher)
|
||||||
u_char *clear; /* IN 8 octets */
|
u_char *clear; /* IN 8 octets */
|
||||||
|
@ -90,18 +165,18 @@ DesEncrypt(clear, key, cipher)
|
||||||
des_set_key(&des_key, key_schedule);
|
des_set_key(&des_key, key_schedule);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X",
|
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
|
||||||
clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
|
des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X",
|
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
|
||||||
cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_LIBCRYPT */
|
||||||
|
|
||||||
|
|
||||||
static u_char Get7Bits(input, startBit)
|
static u_char Get7Bits(input, startBit)
|
||||||
u_char *input;
|
u_char *input;
|
||||||
|
@ -117,6 +192,45 @@ static u_char Get7Bits(input, startBit)
|
||||||
return word & 0xFE;
|
return word & 0xFE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCRYPT
|
||||||
|
|
||||||
|
/* in == 8-byte string (expanded version of the 56-bit key)
|
||||||
|
* out == 64-byte string where each byte is either 1 or 0
|
||||||
|
* Note that the low-order "bit" is always ignored by by setkey()
|
||||||
|
*/
|
||||||
|
static void Expand(in, out)
|
||||||
|
u_char *in;
|
||||||
|
u_char *out;
|
||||||
|
{
|
||||||
|
int j, c;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < 64; in++){
|
||||||
|
c = *in;
|
||||||
|
for(j = 7; j >= 0; j--)
|
||||||
|
*out++ = (c >> j) & 01;
|
||||||
|
i += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The inverse of Expand
|
||||||
|
*/
|
||||||
|
static void Collapse(in, out)
|
||||||
|
u_char *in;
|
||||||
|
u_char *out;
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
int i;
|
||||||
|
unsigned int c;
|
||||||
|
|
||||||
|
for (i = 0; i < 64; i += 8, out++) {
|
||||||
|
c = 0;
|
||||||
|
for (j = 7; j >= 0; j--, in++)
|
||||||
|
c |= *in << j;
|
||||||
|
*out = c & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void MakeKey(key, des_key)
|
static void MakeKey(key, des_key)
|
||||||
u_char *key; /* IN 56 bit DES key missing parity bits */
|
u_char *key; /* IN 56 bit DES key missing parity bits */
|
||||||
|
@ -131,16 +245,73 @@ static void MakeKey(key, des_key)
|
||||||
des_key[6] = Get7Bits(key, 42);
|
des_key[6] = Get7Bits(key, 42);
|
||||||
des_key[7] = Get7Bits(key, 49);
|
des_key[7] = Get7Bits(key, 49);
|
||||||
|
|
||||||
|
#ifndef HAVE_LIBCRYPT
|
||||||
des_set_odd_parity((des_cblock *)des_key);
|
des_set_odd_parity((des_cblock *)des_key);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X",
|
CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key));
|
||||||
key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
|
CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", des_key));
|
||||||
CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X",
|
|
||||||
des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* USE_MSCHAP */
|
|
||||||
|
static void
|
||||||
|
ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response)
|
||||||
|
char *rchallenge;
|
||||||
|
int rchallenge_len;
|
||||||
|
char *secret;
|
||||||
|
int secret_len;
|
||||||
|
MS_ChapResponse *response;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
#ifdef __NetBSD__
|
||||||
|
/* NetBSD uses the libc md4 routines which take bytes instead of bits */
|
||||||
|
int mdlen = secret_len * 2;
|
||||||
|
#else
|
||||||
|
int mdlen = secret_len * 2 * 8;
|
||||||
|
#endif
|
||||||
|
MD4_CTX md4Context;
|
||||||
|
u_char hash[MD4_SIGNATURE_SIZE];
|
||||||
|
u_char unicodePassword[MAX_NT_PASSWORD * 2];
|
||||||
|
|
||||||
|
/* Initialize the Unicode version of the secret (== password). */
|
||||||
|
/* This implicitly supports 8-bit ISO8859/1 characters. */
|
||||||
|
BZERO(unicodePassword, sizeof(unicodePassword));
|
||||||
|
for (i = 0; i < secret_len; i++)
|
||||||
|
unicodePassword[i * 2] = (u_char)secret[i];
|
||||||
|
|
||||||
|
MD4Init(&md4Context);
|
||||||
|
MD4Update(&md4Context, unicodePassword, mdlen);
|
||||||
|
|
||||||
|
MD4Final(hash, &md4Context); /* Tell MD4 we're done */
|
||||||
|
|
||||||
|
ChallengeResponse(rchallenge, hash, response->NTResp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MSLANMAN
|
||||||
|
static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
|
||||||
|
|
||||||
|
static void
|
||||||
|
ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response)
|
||||||
|
char *rchallenge;
|
||||||
|
int rchallenge_len;
|
||||||
|
char *secret;
|
||||||
|
int secret_len;
|
||||||
|
MS_ChapResponse *response;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
|
||||||
|
u_char PasswordHash[MD4_SIGNATURE_SIZE];
|
||||||
|
|
||||||
|
/* LANMan password is case insensitive */
|
||||||
|
BZERO(UcasePassword, sizeof(UcasePassword));
|
||||||
|
for (i = 0; i < secret_len; i++)
|
||||||
|
UcasePassword[i] = (u_char)toupper(secret[i]);
|
||||||
|
DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
|
||||||
|
DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
|
||||||
|
ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
|
ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
|
||||||
|
@ -150,33 +321,27 @@ ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
|
||||||
char *secret;
|
char *secret;
|
||||||
int secret_len;
|
int secret_len;
|
||||||
{
|
{
|
||||||
#ifdef USE_MSCHAP
|
|
||||||
int i;
|
|
||||||
MDstruct md4Context;
|
|
||||||
MS_ChapResponse response;
|
MS_ChapResponse response;
|
||||||
u_char unicodePassword[MAX_NT_PASSWORD * 2];
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
|
CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BZERO(&response, sizeof(response));
|
BZERO(&response, sizeof(response));
|
||||||
|
|
||||||
/* Initialize the Unicode version of the secret (== password). */
|
/* Calculate both always */
|
||||||
/* This implicitly supports 8-bit ISO8859/1 characters. */
|
ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
|
||||||
BZERO(unicodePassword, sizeof(unicodePassword));
|
|
||||||
for (i = 0; i < secret_len; i++)
|
|
||||||
unicodePassword[i * 2] = (u_char)secret[i];
|
|
||||||
|
|
||||||
MDbegin(&md4Context);
|
#ifdef MSLANMAN
|
||||||
MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */
|
ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
|
||||||
MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */
|
|
||||||
|
|
||||||
ChallengeResponse(rchallenge, (char *)md4Context.buffer, response.NTResp);
|
|
||||||
|
|
||||||
|
/* prefered method is set by option */
|
||||||
|
response.UseNT = !ms_lanman;
|
||||||
|
#else
|
||||||
response.UseNT = 1;
|
response.UseNT = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
|
BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
|
||||||
cstate->resp_length = MS_CHAP_RESPONSE_LEN;
|
cstate->resp_length = MS_CHAP_RESPONSE_LEN;
|
||||||
#endif /* USE_MSCHAP */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CHAPMS */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* chap.h - Cryptographic Handshake Authentication Protocol definitions.
|
* chap.h - Challenge Handshake Authentication Protocol definitions.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
|
* Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
|
||||||
* http://www.strataware.com/
|
* http://www.strataware.com/
|
||||||
|
@ -19,12 +19,14 @@
|
||||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
*
|
*
|
||||||
* $Id: chap_ms.h,v 1.1 1997/03/07 16:01:15 hipp Exp $
|
* $Id: chap_ms.h,v 1.2 1997/11/27 06:08:10 paulus Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CHAPMS_INCLUDE__
|
#ifndef __CHAPMS_INCLUDE__
|
||||||
|
|
||||||
|
#define MD4_SIGNATURE_SIZE 16 /* 16 bytes in a MD4 message digest */
|
||||||
#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */
|
#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */
|
||||||
|
#define MS_CHAP_RESPONSE_LEN 49
|
||||||
|
|
||||||
void ChapMS __P((chap_state *, char *, int, char *, int));
|
void ChapMS __P((chap_state *, char *, int, char *, int));
|
||||||
|
|
||||||
|
|
127
ipppd/md4.c
127
ipppd/md4.c
|
@ -13,10 +13,10 @@
|
||||||
** computation.
|
** computation.
|
||||||
** -- Initialize MD using MDbegin(&MD)
|
** -- Initialize MD using MDbegin(&MD)
|
||||||
** -- For each full block (64 bytes) X you wish to process, call
|
** -- For each full block (64 bytes) X you wish to process, call
|
||||||
** MDupdate(&MD,X,512)
|
** MD4Update(&MD,X,512)
|
||||||
** (512 is the number of bits in a full block.)
|
** (512 is the number of bits in a full block.)
|
||||||
** -- For the last block (less than 64 bytes) you wish to process,
|
** -- For the last block (less than 64 bytes) you wish to process,
|
||||||
** MDupdate(&MD,X,n)
|
** MD4Update(&MD,X,n)
|
||||||
** where n is the number of bits in the partial block. A partial
|
** where n is the number of bits in the partial block. A partial
|
||||||
** block terminates the computation, so every MD computation
|
** block terminates the computation, so every MD computation
|
||||||
** should terminate by processing a partial block, even if it
|
** should terminate by processing a partial block, even if it
|
||||||
|
@ -29,17 +29,6 @@
|
||||||
|
|
||||||
/* Implementation notes:
|
/* Implementation notes:
|
||||||
** This implementation assumes that ints are 32-bit quantities.
|
** This implementation assumes that ints are 32-bit quantities.
|
||||||
** If the machine stores the least-significant byte of an int in the
|
|
||||||
** least-addressed byte (e.g., VAX and 8086), then LOWBYTEFIRST
|
|
||||||
** should be set to TRUE. Otherwise (e.g., SUNS), LOWBYTEFIRST
|
|
||||||
** should be set to FALSE. Note that on machines with LOWBYTEFIRST
|
|
||||||
** FALSE the routine MDupdate modifies has a side-effect on its input
|
|
||||||
** array (the order of bytes in each word are reversed). If this is
|
|
||||||
** undesired a call to MDreverse(X) can reverse the bytes of X back
|
|
||||||
** into order after each call to MDupdate.
|
|
||||||
**
|
|
||||||
** NOTE: LOWBYTEFIRST removed by Eric Rosenquist in favour of run-time
|
|
||||||
** detection to simplify build process.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
|
@ -48,7 +37,6 @@
|
||||||
/* Compile-time includes
|
/* Compile-time includes
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <netinet/in.h>
|
|
||||||
#include "md4.h"
|
#include "md4.h"
|
||||||
#include "ipppd.h"
|
#include "ipppd.h"
|
||||||
|
|
||||||
|
@ -91,7 +79,7 @@
|
||||||
#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
|
#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
|
||||||
#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
|
#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
|
||||||
|
|
||||||
/* MDprint(MDp)
|
/* MD4print(MDp)
|
||||||
** Print message digest buffer MDp as 32 hexadecimal digits.
|
** Print message digest buffer MDp as 32 hexadecimal digits.
|
||||||
** Order is from low-order byte of buffer[0] to high-order byte of
|
** Order is from low-order byte of buffer[0] to high-order byte of
|
||||||
** buffer[3].
|
** buffer[3].
|
||||||
|
@ -99,22 +87,24 @@
|
||||||
** This is a user-callable routine.
|
** This is a user-callable routine.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
MDprint(MDp)
|
MD4Print(MDp)
|
||||||
MDptr MDp;
|
MD4_CTX *MDp;
|
||||||
{ int i,j;
|
{
|
||||||
|
int i,j;
|
||||||
for (i=0;i<4;i++)
|
for (i=0;i<4;i++)
|
||||||
for (j=0;j<32;j=j+8)
|
for (j=0;j<32;j=j+8)
|
||||||
printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
|
printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MDbegin(MDp)
|
/* MD4Init(MDp)
|
||||||
** Initialize message digest buffer MDp.
|
** Initialize message digest buffer MDp.
|
||||||
** This is a user-callable routine.
|
** This is a user-callable routine.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
MDbegin(MDp)
|
MD4Init(MDp)
|
||||||
MDptr MDp;
|
MD4_CTX *MDp;
|
||||||
{ int i;
|
{
|
||||||
|
int i;
|
||||||
MDp->buffer[0] = I0;
|
MDp->buffer[0] = I0;
|
||||||
MDp->buffer[1] = I1;
|
MDp->buffer[1] = I1;
|
||||||
MDp->buffer[2] = I2;
|
MDp->buffer[2] = I2;
|
||||||
|
@ -123,21 +113,6 @@ for (i=0;i<8;i++) MDp->count[i] = 0;
|
||||||
MDp->done = 0;
|
MDp->done = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MDreverse(X)
|
|
||||||
** Reverse the byte-ordering of every int in X.
|
|
||||||
** Assumes X is an array of 16 ints.
|
|
||||||
** The macro revx reverses the byte-ordering of the next word of X.
|
|
||||||
*/
|
|
||||||
#define revx { t = (*X << 16) | (*X >> 16); \
|
|
||||||
*X++ = ((t & 0xFF00FF00) >> 8) | ((t & 0x00FF00FF) << 8); }
|
|
||||||
void
|
|
||||||
MDreverse(X)
|
|
||||||
unsigned int *X;
|
|
||||||
{ register unsigned int t;
|
|
||||||
revx; revx; revx; revx; revx; revx; revx; revx;
|
|
||||||
revx; revx; revx; revx; revx; revx; revx; revx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MDblock(MDp,X)
|
/* MDblock(MDp,X)
|
||||||
** Update message digest buffer MDp->buffer using 16-word data block X.
|
** Update message digest buffer MDp->buffer using 16-word data block X.
|
||||||
** Assumes all 16 words of X are full of data.
|
** Assumes all 16 words of X are full of data.
|
||||||
|
@ -145,19 +120,17 @@ revx; revx; revx; revx; revx; revx; revx; revx;
|
||||||
** This routine is not user-callable.
|
** This routine is not user-callable.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
MDblock(MDp,X)
|
MDblock(MDp,Xb)
|
||||||
MDptr MDp;
|
MD4_CTX *MDp;
|
||||||
unsigned int *X;
|
unsigned char *Xb;
|
||||||
{
|
{
|
||||||
register unsigned int tmp, A, B, C, D;
|
register unsigned int tmp, A, B, C, D;
|
||||||
static int low_byte_first = -1;
|
unsigned int X[16];
|
||||||
|
int i;
|
||||||
|
|
||||||
if (low_byte_first == -1) {
|
for (i = 0; i < 16; ++i) {
|
||||||
low_byte_first = (htons((unsigned short int)1) != 1);
|
X[i] = Xb[0] + (Xb[1] << 8) + (Xb[2] << 16) + (Xb[3] << 24);
|
||||||
}
|
Xb += 4;
|
||||||
|
|
||||||
if (low_byte_first == 0) {
|
|
||||||
MDreverse(X);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
A = MDp->buffer[0];
|
A = MDp->buffer[0];
|
||||||
|
@ -219,35 +192,37 @@ MDp->buffer[2] += C;
|
||||||
MDp->buffer[3] += D;
|
MDp->buffer[3] += D;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MDupdate(MDp,X,count)
|
/* MD4Update(MDp,X,count)
|
||||||
** Input: MDp -- an MDptr
|
** Input: X -- a pointer to an array of unsigned characters.
|
||||||
** X -- a pointer to an array of unsigned characters.
|
|
||||||
** count -- the number of bits of X to use.
|
** count -- the number of bits of X to use.
|
||||||
** (if not a multiple of 8, uses high bits of last byte.)
|
** (if not a multiple of 8, uses high bits of last byte.)
|
||||||
** Update MDp using the number of bits of X given by count.
|
** Update MDp using the number of bits of X given by count.
|
||||||
** This is the basic input routine for an MD4 user.
|
** This is the basic input routine for an MD4 user.
|
||||||
** The routine completes the MD computation when count < 512, so
|
** The routine completes the MD computation when count < 512, so
|
||||||
** every MD computation should end with one call to MDupdate with a
|
** every MD computation should end with one call to MD4Update with a
|
||||||
** count less than 512. A call with count 0 will be ignored if the
|
** count less than 512. A call with count 0 will be ignored if the
|
||||||
** MD has already been terminated (done != 0), so an extra call with
|
** MD has already been terminated (done != 0), so an extra call with
|
||||||
** count 0 can be given as a "courtesy close" to force termination
|
** count 0 can be given as a "courtesy close" to force termination
|
||||||
** if desired.
|
** if desired.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
MDupdate(MDp,X,count)
|
MD4Update(MDp,X,count)
|
||||||
MDptr MDp;
|
MD4_CTX *MDp;
|
||||||
unsigned char *X;
|
unsigned char *X;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
{ unsigned int i, tmp, bit, byte, mask;
|
{
|
||||||
|
unsigned int i, tmp, bit, byte, mask;
|
||||||
unsigned char XX[64];
|
unsigned char XX[64];
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
|
|
||||||
/* return with no error if this is a courtesy close with count
|
/* return with no error if this is a courtesy close with count
|
||||||
** zero and MDp->done is true.
|
** zero and MDp->done is true.
|
||||||
*/
|
*/
|
||||||
if (count == 0 && MDp->done) return;
|
if (count == 0 && MDp->done) return;
|
||||||
/* check to see if MD is already done and report error */
|
/* check to see if MD is already done and report error */
|
||||||
if (MDp->done)
|
if (MDp->done)
|
||||||
{ printf("\nError: MDupdate MD already done."); return; }
|
{ printf("\nError: MD4Update MD already done."); return; }
|
||||||
|
|
||||||
/* Add count to MDp->count */
|
/* Add count to MDp->count */
|
||||||
tmp = count;
|
tmp = count;
|
||||||
p = MDp->count;
|
p = MDp->count;
|
||||||
|
@ -256,18 +231,21 @@ while (tmp)
|
||||||
*p++ = tmp;
|
*p++ = tmp;
|
||||||
tmp = tmp >> 8;
|
tmp = tmp >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process data */
|
/* Process data */
|
||||||
if (count == 512)
|
if (count == 512)
|
||||||
{ /* Full block of data to handle */
|
{ /* Full block of data to handle */
|
||||||
MDblock(MDp,(unsigned int *)X);
|
MDblock(MDp,X);
|
||||||
}
|
}
|
||||||
else if (count > 512) /* Check for count too large */
|
else if (count > 512) /* Check for count too large */
|
||||||
{ printf("\nError: MDupdate called with illegal count value %d."
|
{
|
||||||
,count);
|
printf("\nError: MD4Update called with illegal count value %d.",
|
||||||
|
count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else /* partial block -- must be last block so finish up */
|
else /* partial block -- must be last block so finish up */
|
||||||
{ /* Find out how many bytes and residual bits there are */
|
{
|
||||||
|
/* Find out how many bytes and residual bits there are */
|
||||||
byte = count >> 3;
|
byte = count >> 3;
|
||||||
bit = count & 7;
|
bit = count & 7;
|
||||||
/* Copy X into XX since we need to modify it */
|
/* Copy X into XX since we need to modify it */
|
||||||
|
@ -278,20 +256,43 @@ else /* partial block -- must be last block so finish up */
|
||||||
XX[byte] = (XX[byte] | mask) & ~( mask - 1);
|
XX[byte] = (XX[byte] | mask) & ~( mask - 1);
|
||||||
/* If room for bit count, finish up with this block */
|
/* If room for bit count, finish up with this block */
|
||||||
if (byte <= 55)
|
if (byte <= 55)
|
||||||
{ for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
|
{
|
||||||
MDblock(MDp,(unsigned int *)XX);
|
for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
|
||||||
|
MDblock(MDp,XX);
|
||||||
}
|
}
|
||||||
else /* need to do two blocks to finish up */
|
else /* need to do two blocks to finish up */
|
||||||
{ MDblock(MDp,(unsigned int *)XX);
|
{
|
||||||
|
MDblock(MDp,XX);
|
||||||
for (i=0;i<56;i++) XX[i] = 0;
|
for (i=0;i<56;i++) XX[i] = 0;
|
||||||
for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
|
for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
|
||||||
MDblock(MDp,(unsigned int *)XX);
|
MDblock(MDp,XX);
|
||||||
}
|
}
|
||||||
/* Set flag saying we're done with MD computation */
|
/* Set flag saying we're done with MD computation */
|
||||||
MDp->done = 1;
|
MDp->done = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Finish up MD4 computation and return message digest.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
MD4Final(buf, MD)
|
||||||
|
unsigned char *buf;
|
||||||
|
MD4_CTX *MD;
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
unsigned int w;
|
||||||
|
|
||||||
|
MD4Update(MD, NULL, 0);
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
w = MD->buffer[i];
|
||||||
|
for (j = 0; j < 4; ++j) {
|
||||||
|
*buf++ = w;
|
||||||
|
w >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** End of md4.c
|
** End of md4.c
|
||||||
****************************(cut)***********************************/
|
****************************(cut)***********************************/
|
||||||
|
|
41
ipppd/md4.h
41
ipppd/md4.h
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** ********************************************************************
|
** ********************************************************************
|
||||||
** md4.h -- Header file for implementation of **
|
** md4.h -- Header file for implementation of **
|
||||||
|
@ -7,44 +8,56 @@
|
||||||
** ********************************************************************
|
** ********************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef __P
|
||||||
|
# if defined(__STDC__) || defined(__GNUC__)
|
||||||
|
# define __P(x) x
|
||||||
|
# else
|
||||||
|
# define __P(x) ()
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* MDstruct is the data structure for a message digest computation.
|
/* MDstruct is the data structure for a message digest computation.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int buffer[4]; /* Holds 4-word result of MD computation */
|
unsigned int buffer[4]; /* Holds 4-word result of MD computation */
|
||||||
unsigned char count[8]; /* Number of bits processed so far */
|
unsigned char count[8]; /* Number of bits processed so far */
|
||||||
unsigned int done; /* Nonzero means MD computation finished */
|
unsigned int done; /* Nonzero means MD computation finished */
|
||||||
} MDstruct, *MDptr;
|
} MD4_CTX;
|
||||||
|
|
||||||
/* MDbegin(MD)
|
/* MD4Init(MD4_CTX *)
|
||||||
** Input: MD -- an MDptr
|
** Initialize the MD4_CTX prepatory to doing a message digest
|
||||||
** Initialize the MDstruct prepatory to doing a message digest
|
|
||||||
** computation.
|
** computation.
|
||||||
*/
|
*/
|
||||||
extern void MDbegin();
|
extern void MD4Init __P((MD4_CTX *MD));
|
||||||
|
|
||||||
/* MDupdate(MD,X,count)
|
/* MD4Update(MD,X,count)
|
||||||
** Input: MD -- an MDptr
|
** Input: X -- a pointer to an array of unsigned characters.
|
||||||
** X -- a pointer to an array of unsigned characters.
|
|
||||||
** count -- the number of bits of X to use (an unsigned int).
|
** count -- the number of bits of X to use (an unsigned int).
|
||||||
** Updates MD using the first "count" bits of X.
|
** Updates MD using the first "count" bits of X.
|
||||||
** The array pointed to by X is not modified.
|
** The array pointed to by X is not modified.
|
||||||
** If count is not a multiple of 8, MDupdate uses high bits of
|
** If count is not a multiple of 8, MD4Update uses high bits of
|
||||||
** last byte.
|
** last byte.
|
||||||
** This is the basic input routine for a user.
|
** This is the basic input routine for a user.
|
||||||
** The routine terminates the MD computation when count < 512, so
|
** The routine terminates the MD computation when count < 512, so
|
||||||
** every MD computation should end with one call to MDupdate with a
|
** every MD computation should end with one call to MD4Update with a
|
||||||
** count less than 512. Zero is OK for a count.
|
** count less than 512. Zero is OK for a count.
|
||||||
*/
|
*/
|
||||||
extern void MDupdate();
|
extern void MD4Update __P((MD4_CTX *MD, unsigned char *X, unsigned int count));
|
||||||
|
|
||||||
/* MDprint(MD)
|
/* MD4Print(MD)
|
||||||
** Input: MD -- an MDptr
|
|
||||||
** Prints message digest buffer MD as 32 hexadecimal digits.
|
** Prints message digest buffer MD as 32 hexadecimal digits.
|
||||||
** Order is from low-order byte of buffer[0] to high-order byte
|
** Order is from low-order byte of buffer[0] to high-order byte
|
||||||
** of buffer[3].
|
** of buffer[3].
|
||||||
** Each byte is printed with high-order hexadecimal digit first.
|
** Each byte is printed with high-order hexadecimal digit first.
|
||||||
*/
|
*/
|
||||||
extern void MDprint();
|
extern void MD4Print __P((MD4_CTX *));
|
||||||
|
|
||||||
|
/* MD4Final(buf, MD)
|
||||||
|
** Returns message digest from MD and terminates the message
|
||||||
|
** digest computation.
|
||||||
|
*/
|
||||||
|
extern void MD4Final __P((unsigned char *, MD4_CTX *));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** End of md4.h
|
** End of md4.h
|
||||||
|
|
Loading…
Reference in New Issue