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@
|
||||
COMPILE_FLAGS = @CFLAGS@
|
||||
CFLAGS = -O2 -fomit-frame-pointer -Wall
|
||||
CFLAGS = -O2 -fomit-frame-pointer -Wall -DREQ_SYSOPTIONS=0
|
||||
VER = 2.2.0
|
||||
|
||||
# it's a hack
|
||||
|
|
|
@ -3,6 +3,8 @@ PPP Client Support for Microsoft's CHAP-80
|
|||
|
||||
Eric Rosenquist rosenqui@strataware.com
|
||||
|
||||
(NOTE: ipppd now supports MS-CHAP out of the box -- Paul Slootman 2002-06-25)
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
|
||||
|
|
233
ipppd/chap_ms.c
233
ipppd/chap_ms.c
|
@ -20,36 +20,79 @@
|
|||
* 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 $";
|
||||
|
||||
#ifdef USE_MSCHAP
|
||||
#define CHAPMS 1
|
||||
#define MSLANMAN 1
|
||||
#endif
|
||||
|
||||
#ifdef CHAPMS
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.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 "chap.h"
|
||||
#include "chap_ms.h"
|
||||
#include "md4.h"
|
||||
|
||||
#ifdef USE_SSLDES
|
||||
#include <ssl/des.h>
|
||||
#include <openssl/des.h>
|
||||
#else
|
||||
#include <des.h>
|
||||
#ifndef HAVE_LIBCRYPT
|
||||
#include <des.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
u_char LANManResp[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;
|
||||
#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 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
|
||||
ChallengeResponse(challenge, pwHash, response)
|
||||
|
@ -60,10 +103,11 @@ ChallengeResponse(challenge, pwHash, response)
|
|||
char ZPasswordHash[21];
|
||||
|
||||
BZERO(ZPasswordHash, sizeof(ZPasswordHash));
|
||||
BCOPY(pwHash, ZPasswordHash, 16);
|
||||
BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
|
||||
|
||||
#if 0
|
||||
log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash");
|
||||
dbglog("ChallengeResponse - ZPasswordHash %.*B",
|
||||
sizeof(ZPasswordHash), ZPasswordHash);
|
||||
#endif
|
||||
|
||||
DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
|
||||
|
@ -71,11 +115,42 @@ ChallengeResponse(challenge, pwHash, response)
|
|||
DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
|
||||
|
||||
#if 0
|
||||
log_packet(response, 24, "ChallengeResponse - response");
|
||||
dbglog("ChallengeResponse - response %.24B", response);
|
||||
#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
|
||||
DesEncrypt(clear, key, cipher)
|
||||
u_char *clear; /* IN 8 octets */
|
||||
|
@ -90,18 +165,18 @@ DesEncrypt(clear, key, cipher)
|
|||
des_set_key(&des_key, key_schedule);
|
||||
|
||||
#if 0
|
||||
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X",
|
||||
clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
|
||||
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
|
||||
#endif
|
||||
|
||||
des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
|
||||
|
||||
#if 0
|
||||
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X",
|
||||
cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
|
||||
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBCRYPT */
|
||||
|
||||
|
||||
static u_char Get7Bits(input, startBit)
|
||||
u_char *input;
|
||||
|
@ -117,6 +192,45 @@ static u_char Get7Bits(input, startBit)
|
|||
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)
|
||||
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[7] = Get7Bits(key, 49);
|
||||
|
||||
#ifndef HAVE_LIBCRYPT
|
||||
des_set_odd_parity((des_cblock *)des_key);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X",
|
||||
key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
|
||||
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]));
|
||||
CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key));
|
||||
CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", des_key));
|
||||
#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
|
||||
ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
|
||||
|
@ -150,33 +321,27 @@ ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
|
|||
char *secret;
|
||||
int secret_len;
|
||||
{
|
||||
#ifdef USE_MSCHAP
|
||||
int i;
|
||||
MDstruct md4Context;
|
||||
MS_ChapResponse response;
|
||||
u_char unicodePassword[MAX_NT_PASSWORD * 2];
|
||||
|
||||
#if 0
|
||||
CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
|
||||
#endif
|
||||
|
||||
BZERO(&response, sizeof(response));
|
||||
|
||||
/* 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];
|
||||
/* Calculate both always */
|
||||
ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
|
||||
|
||||
MDbegin(&md4Context);
|
||||
MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */
|
||||
MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */
|
||||
|
||||
ChallengeResponse(rchallenge, (char *)md4Context.buffer, response.NTResp);
|
||||
#ifdef MSLANMAN
|
||||
ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
|
||||
|
||||
/* prefered method is set by option */
|
||||
response.UseNT = !ms_lanman;
|
||||
#else
|
||||
response.UseNT = 1;
|
||||
#endif
|
||||
|
||||
BCOPY(&response, cstate->response, 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.
|
||||
* http://www.strataware.com/
|
||||
|
@ -19,12 +19,14 @@
|
|||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* 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__
|
||||
|
||||
#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 MS_CHAP_RESPONSE_LEN 49
|
||||
|
||||
void ChapMS __P((chap_state *, char *, int, char *, int));
|
||||
|
||||
|
|
347
ipppd/md4.c
347
ipppd/md4.c
|
@ -13,10 +13,10 @@
|
|||
** computation.
|
||||
** -- Initialize MD using MDbegin(&MD)
|
||||
** -- 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.)
|
||||
** -- 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
|
||||
** block terminates the computation, so every MD computation
|
||||
** should terminate by processing a partial block, even if it
|
||||
|
@ -29,17 +29,6 @@
|
|||
|
||||
/* Implementation notes:
|
||||
** 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
|
||||
|
@ -48,7 +37,6 @@
|
|||
/* Compile-time includes
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include "md4.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 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.
|
||||
** Order is from low-order byte of buffer[0] to high-order byte of
|
||||
** buffer[3].
|
||||
|
@ -99,43 +87,30 @@
|
|||
** This is a user-callable routine.
|
||||
*/
|
||||
void
|
||||
MDprint(MDp)
|
||||
MDptr MDp;
|
||||
{ int i,j;
|
||||
for (i=0;i<4;i++)
|
||||
for (j=0;j<32;j=j+8)
|
||||
printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
|
||||
MD4Print(MDp)
|
||||
MD4_CTX *MDp;
|
||||
{
|
||||
int i,j;
|
||||
for (i=0;i<4;i++)
|
||||
for (j=0;j<32;j=j+8)
|
||||
printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
|
||||
}
|
||||
|
||||
/* MDbegin(MDp)
|
||||
/* MD4Init(MDp)
|
||||
** Initialize message digest buffer MDp.
|
||||
** This is a user-callable routine.
|
||||
*/
|
||||
void
|
||||
MDbegin(MDp)
|
||||
MDptr MDp;
|
||||
{ int i;
|
||||
MDp->buffer[0] = I0;
|
||||
MDp->buffer[1] = I1;
|
||||
MDp->buffer[2] = I2;
|
||||
MDp->buffer[3] = I3;
|
||||
for (i=0;i<8;i++) MDp->count[i] = 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;
|
||||
MD4Init(MDp)
|
||||
MD4_CTX *MDp;
|
||||
{
|
||||
int i;
|
||||
MDp->buffer[0] = I0;
|
||||
MDp->buffer[1] = I1;
|
||||
MDp->buffer[2] = I2;
|
||||
MDp->buffer[3] = I3;
|
||||
for (i=0;i<8;i++) MDp->count[i] = 0;
|
||||
MDp->done = 0;
|
||||
}
|
||||
|
||||
/* MDblock(MDp,X)
|
||||
|
@ -145,151 +120,177 @@ revx; revx; revx; revx; revx; revx; revx; revx;
|
|||
** This routine is not user-callable.
|
||||
*/
|
||||
static void
|
||||
MDblock(MDp,X)
|
||||
MDptr MDp;
|
||||
unsigned int *X;
|
||||
MDblock(MDp,Xb)
|
||||
MD4_CTX *MDp;
|
||||
unsigned char *Xb;
|
||||
{
|
||||
register unsigned int tmp, A, B, C, D;
|
||||
static int low_byte_first = -1;
|
||||
register unsigned int tmp, A, B, C, D;
|
||||
unsigned int X[16];
|
||||
int i;
|
||||
|
||||
if (low_byte_first == -1) {
|
||||
low_byte_first = (htons((unsigned short int)1) != 1);
|
||||
for (i = 0; i < 16; ++i) {
|
||||
X[i] = Xb[0] + (Xb[1] << 8) + (Xb[2] << 16) + (Xb[3] << 24);
|
||||
Xb += 4;
|
||||
}
|
||||
|
||||
A = MDp->buffer[0];
|
||||
B = MDp->buffer[1];
|
||||
C = MDp->buffer[2];
|
||||
D = MDp->buffer[3];
|
||||
/* Update the message digest buffer */
|
||||
ff(A , B , C , D , 0 , fs1); /* Round 1 */
|
||||
ff(D , A , B , C , 1 , fs2);
|
||||
ff(C , D , A , B , 2 , fs3);
|
||||
ff(B , C , D , A , 3 , fs4);
|
||||
ff(A , B , C , D , 4 , fs1);
|
||||
ff(D , A , B , C , 5 , fs2);
|
||||
ff(C , D , A , B , 6 , fs3);
|
||||
ff(B , C , D , A , 7 , fs4);
|
||||
ff(A , B , C , D , 8 , fs1);
|
||||
ff(D , A , B , C , 9 , fs2);
|
||||
ff(C , D , A , B , 10 , fs3);
|
||||
ff(B , C , D , A , 11 , fs4);
|
||||
ff(A , B , C , D , 12 , fs1);
|
||||
ff(D , A , B , C , 13 , fs2);
|
||||
ff(C , D , A , B , 14 , fs3);
|
||||
ff(B , C , D , A , 15 , fs4);
|
||||
gg(A , B , C , D , 0 , gs1); /* Round 2 */
|
||||
gg(D , A , B , C , 4 , gs2);
|
||||
gg(C , D , A , B , 8 , gs3);
|
||||
gg(B , C , D , A , 12 , gs4);
|
||||
gg(A , B , C , D , 1 , gs1);
|
||||
gg(D , A , B , C , 5 , gs2);
|
||||
gg(C , D , A , B , 9 , gs3);
|
||||
gg(B , C , D , A , 13 , gs4);
|
||||
gg(A , B , C , D , 2 , gs1);
|
||||
gg(D , A , B , C , 6 , gs2);
|
||||
gg(C , D , A , B , 10 , gs3);
|
||||
gg(B , C , D , A , 14 , gs4);
|
||||
gg(A , B , C , D , 3 , gs1);
|
||||
gg(D , A , B , C , 7 , gs2);
|
||||
gg(C , D , A , B , 11 , gs3);
|
||||
gg(B , C , D , A , 15 , gs4);
|
||||
hh(A , B , C , D , 0 , hs1); /* Round 3 */
|
||||
hh(D , A , B , C , 8 , hs2);
|
||||
hh(C , D , A , B , 4 , hs3);
|
||||
hh(B , C , D , A , 12 , hs4);
|
||||
hh(A , B , C , D , 2 , hs1);
|
||||
hh(D , A , B , C , 10 , hs2);
|
||||
hh(C , D , A , B , 6 , hs3);
|
||||
hh(B , C , D , A , 14 , hs4);
|
||||
hh(A , B , C , D , 1 , hs1);
|
||||
hh(D , A , B , C , 9 , hs2);
|
||||
hh(C , D , A , B , 5 , hs3);
|
||||
hh(B , C , D , A , 13 , hs4);
|
||||
hh(A , B , C , D , 3 , hs1);
|
||||
hh(D , A , B , C , 11 , hs2);
|
||||
hh(C , D , A , B , 7 , hs3);
|
||||
hh(B , C , D , A , 15 , hs4);
|
||||
MDp->buffer[0] += A;
|
||||
MDp->buffer[1] += B;
|
||||
MDp->buffer[2] += C;
|
||||
MDp->buffer[3] += D;
|
||||
}
|
||||
|
||||
if (low_byte_first == 0) {
|
||||
MDreverse(X);
|
||||
}
|
||||
|
||||
A = MDp->buffer[0];
|
||||
B = MDp->buffer[1];
|
||||
C = MDp->buffer[2];
|
||||
D = MDp->buffer[3];
|
||||
/* Update the message digest buffer */
|
||||
ff(A , B , C , D , 0 , fs1); /* Round 1 */
|
||||
ff(D , A , B , C , 1 , fs2);
|
||||
ff(C , D , A , B , 2 , fs3);
|
||||
ff(B , C , D , A , 3 , fs4);
|
||||
ff(A , B , C , D , 4 , fs1);
|
||||
ff(D , A , B , C , 5 , fs2);
|
||||
ff(C , D , A , B , 6 , fs3);
|
||||
ff(B , C , D , A , 7 , fs4);
|
||||
ff(A , B , C , D , 8 , fs1);
|
||||
ff(D , A , B , C , 9 , fs2);
|
||||
ff(C , D , A , B , 10 , fs3);
|
||||
ff(B , C , D , A , 11 , fs4);
|
||||
ff(A , B , C , D , 12 , fs1);
|
||||
ff(D , A , B , C , 13 , fs2);
|
||||
ff(C , D , A , B , 14 , fs3);
|
||||
ff(B , C , D , A , 15 , fs4);
|
||||
gg(A , B , C , D , 0 , gs1); /* Round 2 */
|
||||
gg(D , A , B , C , 4 , gs2);
|
||||
gg(C , D , A , B , 8 , gs3);
|
||||
gg(B , C , D , A , 12 , gs4);
|
||||
gg(A , B , C , D , 1 , gs1);
|
||||
gg(D , A , B , C , 5 , gs2);
|
||||
gg(C , D , A , B , 9 , gs3);
|
||||
gg(B , C , D , A , 13 , gs4);
|
||||
gg(A , B , C , D , 2 , gs1);
|
||||
gg(D , A , B , C , 6 , gs2);
|
||||
gg(C , D , A , B , 10 , gs3);
|
||||
gg(B , C , D , A , 14 , gs4);
|
||||
gg(A , B , C , D , 3 , gs1);
|
||||
gg(D , A , B , C , 7 , gs2);
|
||||
gg(C , D , A , B , 11 , gs3);
|
||||
gg(B , C , D , A , 15 , gs4);
|
||||
hh(A , B , C , D , 0 , hs1); /* Round 3 */
|
||||
hh(D , A , B , C , 8 , hs2);
|
||||
hh(C , D , A , B , 4 , hs3);
|
||||
hh(B , C , D , A , 12 , hs4);
|
||||
hh(A , B , C , D , 2 , hs1);
|
||||
hh(D , A , B , C , 10 , hs2);
|
||||
hh(C , D , A , B , 6 , hs3);
|
||||
hh(B , C , D , A , 14 , hs4);
|
||||
hh(A , B , C , D , 1 , hs1);
|
||||
hh(D , A , B , C , 9 , hs2);
|
||||
hh(C , D , A , B , 5 , hs3);
|
||||
hh(B , C , D , A , 13 , hs4);
|
||||
hh(A , B , C , D , 3 , hs1);
|
||||
hh(D , A , B , C , 11 , hs2);
|
||||
hh(C , D , A , B , 7 , hs3);
|
||||
hh(B , C , D , A , 15 , hs4);
|
||||
MDp->buffer[0] += A;
|
||||
MDp->buffer[1] += B;
|
||||
MDp->buffer[2] += C;
|
||||
MDp->buffer[3] += D;
|
||||
}
|
||||
|
||||
/* MDupdate(MDp,X,count)
|
||||
** Input: MDp -- an MDptr
|
||||
** X -- a pointer to an array of unsigned characters.
|
||||
/* MD4Update(MDp,X,count)
|
||||
** Input: X -- a pointer to an array of unsigned characters.
|
||||
** count -- the number of bits of X to use.
|
||||
** (if not a multiple of 8, uses high bits of last byte.)
|
||||
** Update MDp using the number of bits of X given by count.
|
||||
** This is the basic input routine for an MD4 user.
|
||||
** 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
|
||||
** MD has already been terminated (done != 0), so an extra call with
|
||||
** count 0 can be given as a "courtesy close" to force termination
|
||||
** if desired.
|
||||
*/
|
||||
void
|
||||
MDupdate(MDp,X,count)
|
||||
MDptr MDp;
|
||||
MD4Update(MDp,X,count)
|
||||
MD4_CTX *MDp;
|
||||
unsigned char *X;
|
||||
unsigned int count;
|
||||
{ unsigned int i, tmp, bit, byte, mask;
|
||||
unsigned char XX[64];
|
||||
unsigned char *p;
|
||||
/* return with no error if this is a courtesy close with count
|
||||
** zero and MDp->done is true.
|
||||
{
|
||||
unsigned int i, tmp, bit, byte, mask;
|
||||
unsigned char XX[64];
|
||||
unsigned char *p;
|
||||
|
||||
/* return with no error if this is a courtesy close with count
|
||||
** zero and MDp->done is true.
|
||||
*/
|
||||
if (count == 0 && MDp->done) return;
|
||||
/* check to see if MD is already done and report error */
|
||||
if (MDp->done)
|
||||
{ printf("\nError: MD4Update MD already done."); return; }
|
||||
|
||||
/* Add count to MDp->count */
|
||||
tmp = count;
|
||||
p = MDp->count;
|
||||
while (tmp)
|
||||
{ tmp += *p;
|
||||
*p++ = tmp;
|
||||
tmp = tmp >> 8;
|
||||
}
|
||||
|
||||
/* Process data */
|
||||
if (count == 512)
|
||||
{ /* Full block of data to handle */
|
||||
MDblock(MDp,X);
|
||||
}
|
||||
else if (count > 512) /* Check for count too large */
|
||||
{
|
||||
printf("\nError: MD4Update called with illegal count value %d.",
|
||||
count);
|
||||
return;
|
||||
}
|
||||
else /* partial block -- must be last block so finish up */
|
||||
{
|
||||
/* Find out how many bytes and residual bits there are */
|
||||
byte = count >> 3;
|
||||
bit = count & 7;
|
||||
/* Copy X into XX since we need to modify it */
|
||||
for (i=0;i<=byte;i++) XX[i] = X[i];
|
||||
for (i=byte+1;i<64;i++) XX[i] = 0;
|
||||
/* Add padding '1' bit and low-order zeros in last byte */
|
||||
mask = 1 << (7 - bit);
|
||||
XX[byte] = (XX[byte] | mask) & ~( mask - 1);
|
||||
/* If room for bit count, finish up with this block */
|
||||
if (byte <= 55)
|
||||
{
|
||||
for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
|
||||
MDblock(MDp,XX);
|
||||
}
|
||||
else /* need to do two blocks to finish up */
|
||||
{
|
||||
MDblock(MDp,XX);
|
||||
for (i=0;i<56;i++) XX[i] = 0;
|
||||
for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
|
||||
MDblock(MDp,XX);
|
||||
}
|
||||
/* Set flag saying we're done with MD computation */
|
||||
MDp->done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Finish up MD4 computation and return message digest.
|
||||
*/
|
||||
if (count == 0 && MDp->done) return;
|
||||
/* check to see if MD is already done and report error */
|
||||
if (MDp->done)
|
||||
{ printf("\nError: MDupdate MD already done."); return; }
|
||||
/* Add count to MDp->count */
|
||||
tmp = count;
|
||||
p = MDp->count;
|
||||
while (tmp)
|
||||
{ tmp += *p;
|
||||
*p++ = tmp;
|
||||
tmp = tmp >> 8;
|
||||
}
|
||||
/* Process data */
|
||||
if (count == 512)
|
||||
{ /* Full block of data to handle */
|
||||
MDblock(MDp,(unsigned int *)X);
|
||||
}
|
||||
else if (count > 512) /* Check for count too large */
|
||||
{ printf("\nError: MDupdate called with illegal count value %d."
|
||||
,count);
|
||||
return;
|
||||
}
|
||||
else /* partial block -- must be last block so finish up */
|
||||
{ /* Find out how many bytes and residual bits there are */
|
||||
byte = count >> 3;
|
||||
bit = count & 7;
|
||||
/* Copy X into XX since we need to modify it */
|
||||
for (i=0;i<=byte;i++) XX[i] = X[i];
|
||||
for (i=byte+1;i<64;i++) XX[i] = 0;
|
||||
/* Add padding '1' bit and low-order zeros in last byte */
|
||||
mask = 1 << (7 - bit);
|
||||
XX[byte] = (XX[byte] | mask) & ~( mask - 1);
|
||||
/* If room for bit count, finish up with this block */
|
||||
if (byte <= 55)
|
||||
{ for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
|
||||
MDblock(MDp,(unsigned int *)XX);
|
||||
}
|
||||
else /* need to do two blocks to finish up */
|
||||
{ MDblock(MDp,(unsigned int *)XX);
|
||||
for (i=0;i<56;i++) XX[i] = 0;
|
||||
for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
|
||||
MDblock(MDp,(unsigned int *)XX);
|
||||
}
|
||||
/* Set flag saying we're done with MD computation */
|
||||
MDp->done = 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
47
ipppd/md4.h
47
ipppd/md4.h
|
@ -1,3 +1,4 @@
|
|||
|
||||
/*
|
||||
** ********************************************************************
|
||||
** 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.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int buffer[4]; /* Holds 4-word result of MD computation */
|
||||
unsigned char count[8]; /* Number of bits processed so far */
|
||||
unsigned int done; /* Nonzero means MD computation finished */
|
||||
} MDstruct, *MDptr;
|
||||
unsigned int buffer[4]; /* Holds 4-word result of MD computation */
|
||||
unsigned char count[8]; /* Number of bits processed so far */
|
||||
unsigned int done; /* Nonzero means MD computation finished */
|
||||
} MD4_CTX;
|
||||
|
||||
/* MDbegin(MD)
|
||||
** Input: MD -- an MDptr
|
||||
** Initialize the MDstruct prepatory to doing a message digest
|
||||
/* MD4Init(MD4_CTX *)
|
||||
** Initialize the MD4_CTX prepatory to doing a message digest
|
||||
** computation.
|
||||
*/
|
||||
extern void MDbegin();
|
||||
extern void MD4Init __P((MD4_CTX *MD));
|
||||
|
||||
/* MDupdate(MD,X,count)
|
||||
** Input: MD -- an MDptr
|
||||
** X -- a pointer to an array of unsigned characters.
|
||||
/* MD4Update(MD,X,count)
|
||||
** Input: X -- a pointer to an array of unsigned characters.
|
||||
** count -- the number of bits of X to use (an unsigned int).
|
||||
** Updates MD using the first "count" bits of X.
|
||||
** 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.
|
||||
** This is the basic input routine for a user.
|
||||
** 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.
|
||||
*/
|
||||
extern void MDupdate();
|
||||
extern void MD4Update __P((MD4_CTX *MD, unsigned char *X, unsigned int count));
|
||||
|
||||
/* MDprint(MD)
|
||||
** Input: MD -- an MDptr
|
||||
/* MD4Print(MD)
|
||||
** Prints message digest buffer MD as 32 hexadecimal digits.
|
||||
** Order is from low-order byte of buffer[0] to high-order byte
|
||||
** of buffer[3].
|
||||
** 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
|
||||
|
|
Loading…
Reference in New Issue