--- configure.bak 2003-10-13 10:11:05.000000000 -0500 +++ configure 2003-10-01 12:34:41.000000000 -0500 @@ -25,8 +25,20 @@ MANDIR="" LIBDIRS=`cat /etc/ld.so.conf 2> /dev/null` PREFIX=`echo "$1"|sed 's/.*--prefix=//'` +LIBDES="" echo +echo "Checking for libdes ..." +for i in $LIBDIRS /lib /usr/lib /usr/local/lib /opt/local/lib +do + if [ "X" = "X$LIBDES" ]; then + if [ -f "$i/libdes.a" ]; then + LIBDES="$i/libdes.a" + fi + fi +done + + echo "Checking for openssl ..." for i in $LIBDIRS /lib /usr/lib /usr/local/lib /opt/local/lib \ /*ssl /usr/*ssl /opt/*ssl /usr/local/*ssl /opt/local/*ssl \ @@ -164,6 +176,7 @@ echo "XLIBPATHS=$XLIBPATHS" >> Makefile.in echo "XIPATHS=$XIPATHS" >> Makefile.in echo "PREFIX=$PREFIX" >> Makefile.in +echo "LIBDES=$LIBDES" >> Makefile.in echo >> Makefile.in echo "Generating Makefile ..." --- hydra.c.bak 2003-10-13 10:04:32.000000000 -0500 +++ hydra.c 2003-10-13 10:08:38.000000000 -0500 @@ -11,7 +11,7 @@ #include "hydra.h" -extern void service_telnet(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE *fp, int port); +extern void service_telnet(unsigned long int ip, int sp, unsigned char options, char *iscptr, FILE *fp, int port); extern void service_ftp(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE *fp, int port); extern void service_pop3(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE *fp, int port); extern void service_imap(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE *fp, int port); @@ -26,9 +26,10 @@ extern void service_icq(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE *fp, int port); extern void service_pcnfs(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE *fp, int port); extern void service_smb(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE *fp, int port); +extern void service_smbnt(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE *fp, int port); extern void service_mysql(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE *fp, int port); // ADD NEW SERVICES HERE -#define SERVICES "telnet ftp pop3 imap smb http https cisco cisco-enable ldap mysql nntp vnc rexec socks5 icq pcnfs" +#define SERVICES "telnet ftp pop3 imap smb smbnt http https cisco cisco-enable ldap mysql nntp vnc rexec socks5 icq pcnfs" // ADD NEW SERVICES HERE #define MAXBUF 264 @@ -250,6 +251,13 @@ } i = 1; } + if (strcmp(service, "smbnt") == 0) { + if (tasks > 1) { + fprintf(stderr, "Reduced number of tasks to 1 (smb does not like parallel connections)\n"); + tasks = 1; + } + i = 1; + } if (strcmp(service, "pcnfs") == 0) { i = 1; if (port == 0) { @@ -472,6 +480,7 @@ if (strcmp(service, "icq") == 0) service_icq(ip, socketpairs[i][1], options, miscptr, ofp, port); if (strcmp(service, "pcnfs") == 0) service_pcnfs(ip, socketpairs[i][1], options, miscptr, ofp, port); if (strcmp(service, "smb") == 0) service_smb(ip, socketpairs[i][1], options, miscptr, ofp, port); + if (strcmp(service, "smbnt") == 0) service_smbnt(ip, socketpairs[i][1], options, miscptr, ofp, port); if (strcmp(service, "mysql") == 0) service_mysql(ip, socketpairs[i][1], options, miscptr, ofp, port); // ADD NEW SERVICES HERE return 0; --- hydra-smbnt.c.bak 2003-10-13 10:09:20.000000000 -0500 +++ hydra-smbnt.c 2003-10-13 10:58:05.000000000 -0500 @@ -0,0 +1,379 @@ +#include "hydra-mod.h" +#include "md4.h" +#include + +/* + SMB NTLM Password/HASH Checking Hydra Module + Copyright (C) m0j0.j0j0 + m0j0.j0j0 / m0j0@foofus.net + 09/30/2003 + + Based on code from: SMB Auditing Tool + [Copyright (C) Patrik Karlsson 2001] + + This code allows Hydra to directly test NTLM hashes against + a Windows host via '-m HASH'. This may be useful for an + auditor who has aquired a sam._ or pwdump file and would + like to quickly determine which are valid entries. This + module can also be used to test SMB passwords against devices + that do not allow clear text LanMan passwords. + + See http://www.foofus.net/m0j0/passhash.html for further + examples. + + Greets: Foofus, Phenfen & Fizzgig +*/ + +extern char *HYDRA_EXIT; +char challenge[8]; + +static u_char Get7Bits(u_char *input, int startBit) { + register unsigned int word; + + word = (unsigned)input[startBit / 8] << 8; + word |= (unsigned)input[startBit / 8 + 1]; + + word >>= 15 - (startBit % 8 + 7); + + return word & 0xFE; +} + +// Make the key +static void MakeKey(u_char *key, u_char *des_key) { + des_key[0] = Get7Bits(key, 0); + des_key[1] = Get7Bits(key, 7); + des_key[2] = Get7Bits(key, 14); + des_key[3] = Get7Bits(key, 21); + des_key[4] = Get7Bits(key, 28); + des_key[5] = Get7Bits(key, 35); + des_key[6] = Get7Bits(key, 42); + des_key[7] = Get7Bits(key, 49); + + des_set_odd_parity((des_cblock *)des_key); +} + +// Do the DesEncryption +void DesEncrypt(u_char *clear, u_char *key, u_char *cipher) { + des_cblock des_key; + des_key_schedule key_schedule; + + MakeKey(key, des_key); + des_set_key(&des_key, key_schedule); + des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); +} + +/* + HashNTLM + Function: Create a NTLM hash from the challenge + Variables: + ntlmhash = the hash created from this function + pass = users password + challenge = the challenge recieved from the server +*/ +void HashNTLM(u_char **ntlmhash, u_char *pass, u_char *challenge, char *miscptr) { + MD4_CTX md4Context; + u_char hash[16]; // MD4_SIGNATURE_SIZE = 16 + u_char unicodePassword[256 * 2]; // MAX_NT_PASSWORD = 256 + u_char p21[21]; + u_char ntlm_response[24]; + int i=0,j=0; + int mdlen = strlen(pass) * 2 * 8; + u_char *p; + + /* Use NTLM Hash instead of password */ + if ((miscptr != NULL) && (strcmp(miscptr, "HASH") == 0)) { + // 1000:D42E35E1A1E4C22BD32E2170E4857C20:5E20780DD45857A68402938C7629D3B2::: + p = pass; + while ((*p != '\0') && (i < 2)) { + if (*p == ':') i++; + p++; + } + + if (*p == '\0') { + fprintf(stderr, "Error reading PWDUMP file.\n"); + exit(1); + } + + char HexChar; + int HexValue; + for (i=0; i<16; i++) { + HexValue = 0x0; + for (j=0; j<2; j++) { + HexChar = (char)p[2*i+j]; + + if (HexChar > 0x39) + HexChar = HexChar | 0x20; /* convert upper case to lower */ + + if (!(((HexChar >= 0x30) && (HexChar <= 0x39))|| /* 0 - 9 */ + ((HexChar >= 0x61) && (HexChar <= 0x66)))) { /* a - f */ + //fprintf(stderr, "Error invalid char (%c) for hash.\n", HexChar); + //exit(1); + HexChar = 0x30; + } + + HexChar -= 0x30; + if (HexChar > 0x09) /* HexChar is "a" - "f" */ + HexChar -= 0x27; + + HexValue = (HexValue << 4) | (char)HexChar; + } + hash[i] = (u_char)HexValue; + } + } else { + /* Initialize the Unicode version of the secret (== password). */ + /* This implicitly supports 8-bit ISO8859/1 characters. */ + bzero(unicodePassword, sizeof(unicodePassword)); + for (i = 0; i < strlen(pass); i++) + unicodePassword[i * 2] = (u_char)pass[i]; + + MD4Init(&md4Context); + MD4Update(&md4Context, unicodePassword, mdlen); + MD4Final(hash, &md4Context); /* Tell MD4 we're done */ + } + + memset(p21, '\0', 21); + memcpy(p21, hash, 16); + + DesEncrypt(challenge, p21 + 0, ntlm_response + 0); + DesEncrypt(challenge, p21 + 7, ntlm_response + 8); + DesEncrypt(challenge, p21 + 14, ntlm_response + 16); + + memcpy(*ntlmhash, ntlm_response, 24); +} + +/* + NBS Session Request + Function: Request a new session from the server + Returns: TRUE on success else FALSE. +*/ +int NBSSessionRequest(int s) { + char nb_name[32]; // netbiosname + char nb_local[32]; // netbios localredirector + char rqbuf[7] = {0x81, 0x00, 0x00, 0x48, 0x20, 0x00, 0x20}; + char *buf; + u_char rbuf[400]; + + // convert computer name to netbios name + memset(nb_name, 0, 32); + memset(nb_local, 0, 32); + memcpy(nb_name, "CKFDENECFDEFFCFGEFFCCACACACACACA", 32); // *SMBSERVER + memcpy(nb_local, "EIFJEEFCEBCACACACACACACACACACACA", 32); // HYDRA + + buf = (char *) malloc(100); + memset(buf, 0, 100); + memcpy(buf, rqbuf, 5); + memcpy(buf+5, nb_name, 32); + memcpy(buf+37, rqbuf+5, 2); + memcpy(buf+39, nb_local, 32); + memcpy(buf+71, rqbuf+5, 1); + + hydra_send(s, buf, 72, 0); + free(buf); + + memset(rbuf, 0, 400); + hydra_recv(s, rbuf, sizeof(rbuf)); + + if (rbuf[0] == 0x82) + return 0; /* success */ + else + return -1; /* failed */ +} + + +/* + SMBNegProt + Function: Negotiate protocol with server ... + Actually a pseudo negotiation since the whole + program counts on NTLM support :) + + The challenge is retrieved from the answer + No error checking is performed i.e cross your fingers.... +*/ +int SMBNegProt(int s) { + char buf[168] = {0x00, 0x00, 0x00, 0xa4, 0xff, 0x53, 0x4d, 0x42, + 0x72, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7d, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x81, 0x00, 0x02, + 0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, + 0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52, + 0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, + 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f, 0x46, + 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, + 0x4b, 0x53, 0x20, 0x31, 0x2e, 0x30, 0x33, 0x00, + 0x02, 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f, + 0x46, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, + 0x52, 0x4b, 0x53, 0x20, 0x33, 0x2e, 0x30, 0x00, + 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, + 0x2e, 0x30, 0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e, + 0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x53, + 0x61, 0x6d, 0x62, 0x61, 0x00, 0x02, 0x4e, 0x54, + 0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x20, + 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4e, 0x54, 0x20, + 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32, 0x00}; + + char rbuf[400]; + memset(rbuf, 0, 400); + + hydra_send(s, buf, 168, 0); + hydra_recv(s, rbuf, sizeof(rbuf)); + + // retrieve the challenge + memcpy(challenge, rbuf+73, sizeof(challenge)); + + return 2; +} + + +/* + SMBSessionSetup + Function: Send username + response to the challenge from + the server. + Currently we're sendin ZEROES for the LMHASH since + NT4/2000 doesn't seem to look at this if we got a + valid NTLM hash. + Returns: TRUE on success else FALSE. +*/ +int SMBSessionSetup(int s, char *user, char *pass, char *miscptr) { + char b[137] = {0x00, 0x00, 0x00, 0x85, 0xff, 0x53, 0x4d, + 0x42, 0x73, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x7d, 0x00, 0x00, 0x01, 0x00, 0x0d, 0xff, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x02, 0x00, 0x3c, 0x7d, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x48, 0x00, 0xdf, 0x82, 0xb9, 0x2f, 0xda, 0xdb, + 0x43, 0x47, 0x09, 0xdb, 0x7f, 0xfc, 0xb0, 0xa8, + 0xf0, 0x46, 0xe2, 0xfe, 0x64, 0x6d, 0x67, 0x58, + 0xe0, 0xf9, 0xca, 0x9f, 0x5e, 0xdb, 0xe0, 0x15, + 0x80, 0xf8, 0x54, 0xe3, 0x6e, 0xe9, 0xf8, 0x88, + 0x80, 0x19, 0xb6, 0xf9, 0xae, 0xb7, 0xa6, 0x62, + 0x14, 0xfc, 0x54, 0x45, 0x53, 0x54, 0x00, 0x4d, + 0x59, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x00, 0x55, + 0x6e, 0x69, 0x78, 0x00, 0x53, 0x61, 0x6d, 0x62, + 0x61, 0x00}; + + u_char buf[512]; + u_char *NTLMhash; + u_char LMhash[24]; + u_char workgroup[16]; + u_char rbuf[400]; + int userlen; + + NTLMhash = (u_char *) malloc(24); + + memset(NTLMhash, 0, 24); + memset(LMhash, 0, 24); + memset(workgroup, 0, 16); + memset(rbuf, 0, 400); + + HashNTLM(&NTLMhash, pass, challenge, miscptr); + + memset(buf, 0, 512); + memcpy(buf, b, 89); + memcpy(buf+65, LMhash, 24); + memcpy(buf+89, NTLMhash, 24); + + userlen = strlen(user); + + memcpy(buf+113, user, userlen); + memset(buf+(113+userlen), 0, 1); + memcpy(buf+(114+userlen), workgroup, strlen(workgroup)); + memcpy(buf+(114+userlen+strlen(workgroup)), b+125, 12); + + // set the header length + buf[3] = ( userlen + strlen(workgroup) + 0x7A ) % 256; + buf[2] = ( userlen + strlen(workgroup) + 0x7A ) / 256; + + // set data length + buf[63] = 0x1F + strlen(workgroup) + userlen; + + hydra_send(s, buf, 126+userlen+strlen(workgroup), 0); + + hydra_recv(s, rbuf, sizeof(rbuf)); + return rbuf[9]; +} + +int start_smbnt(int s, int port, unsigned char options, char *miscptr, FILE *fp) { + char *empty = ""; + char *login, *pass; + + if (strlen(login = hydra_get_next_login()) == 0) login = empty; + if (strlen(pass = hydra_get_next_password()) == 0) pass = empty; + + int SMBerr = SMBSessionSetup(s, login, pass, miscptr); + + if ( 0x00 == SMBerr ) { // success + hydra_report_found(port, "smb", fp); + hydra_completed_pair_found(); + } + else if ( 0x24 == SMBerr ) { // change password on next login [success] + hydra_report_found(port, "smb (must change password)", fp); + hydra_completed_pair_found(); + } + else if ( 0x72 == SMBerr ) { // account disabled + hydra_report_found(port, "smb (account disabled)", fp); + hydra_completed_pair(); + } + else if ( 0x34 == SMBerr ) { // account locked out + fprintf(stderr, "[%d][smb] Account: %s is locked out\n", port, login); + hydra_completed_pair(); + } + else { // failed + hydra_completed_pair(); + } + + hydra_disconnect(s); + if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) + return 3; + return 1; +} + +void service_smbnt(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE *fp, int port) { + int run = 1, next_run, sock = -1; + int myport = PORT_SMB, mysslport = PORT_SMB_SSL; + + hydra_register_socket(sp); + if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) + return; + for(;;) { + switch(run) { + case 1: /* connect and service init function */ + if (sock >= 0) + sock = hydra_disconnect(sock); + usleep(300000); + if ((options & OPTION_SSL) == 0) { + if (port != 0) myport = port; + sock = hydra_connect_tcp(ip, myport); + port = myport; + } else { + if (port != 0) mysslport = port; + sock = hydra_connect_ssl(ip, mysslport); + port = mysslport; + } + if (sock < 0) { + fprintf(stderr, "Error: Child with pid %d terminating, can not connect\n", (int)getpid()); + hydra_child_exit(); + } + if ( NBSSessionRequest(sock) < 0 ) { + fprintf(stderr, "Session Setup Failed: "); + fprintf(stderr, "(Is the server service running?)\n"); + exit(-1); + } + next_run = SMBNegProt(sock); + break; + case 2: /* run the cracking function */ + next_run = start_smbnt(sock, port, options, miscptr, fp); + break; + case 3: /* clean exit */ + if (sock >= 0) sock = hydra_disconnect(sock); + hydra_child_exit(); + return; + default: fprintf(stderr,"Caught unknown return code (%d), exiting!\n", run); + hydra_child_exit(); + exit(-1); + } + run = next_run; + } +} --- Makefile.am.bak 2003-10-13 10:10:16.000000000 -0500 +++ Makefile.am 2003-10-01 12:34:41.000000000 -0500 @@ -4,26 +4,26 @@ CC = gcc OPTS = -O2 -I. -Wall -LIBS = +LIBS = DIR = /bin SRC = hydra-vnc.c hydra-pcnfs.c hydra-rexec.c hydra-nntp.c hydra-socks5.c \ hydra-telnet.c hydra-cisco.c hydra-http.c hydra-ftp.c hydra-imap.c \ hydra-pop3.c hydra-smb.c hydra-icq.c hydra-cisco-enable.c hydra-ldap.c \ - hydra-mysql.c d3des.c hydra-mod.c hydra.c + hydra-mysql.c hydra-smbnt.c d3des.c md4.c hydra-mod.c hydra.c OBJ = hydra-vnc.o hydra-pcnfs.o hydra-rexec.o hydra-nntp.o hydra-socks5.o \ hydra-telnet.o hydra-cisco.o hydra-http.o hydra-ftp.o hydra-imap.o \ hydra-pop3.o hydra-smb.o hydra-icq.o hydra-cisco-enable.o hydra-ldap.o \ - hydra-mysql.o d3des.o hydra-mod.o hydra.o + hydra-mysql.o hydra-smbnt.o d3des.o md4.o hydra-mod.o hydra.o BIN = hydra EXTRA_DIST = README CHANGES TODO INSTALL LICENSE.GNU LICENCE.HYDRA \ - hydra-mod.h hydra.h d3des.h + hydra-mod.h hydra.h d3des.h md4.h all: hydra hydra: $(OBJ) - $(CC) $(OPTS) $(LIBS) -o $(BIN) $(OBJ) $(LIB) $(XLIBS) $(XLIBPATHS) + $(CC) $(OPTS) $(LIBS) -o $(BIN) $(OBJ) $(LIB) $(XLIBS) $(XLIBPATHS) $(LIBDES) @echo @echo If men could get pregnant, abortion would be a sacrament @echo --- md4.c.bak 2003-10-13 10:09:31.000000000 -0500 +++ md4.c 2003-10-01 12:34:41.000000000 -0500 @@ -0,0 +1,297 @@ +/* +** ******************************************************************** +** md4.c -- Implementation of MD4 Message Digest Algorithm ** +** Updated: 2/16/90 by Ronald L. Rivest ** +** (C) 1990 RSA Data Security, Inc. ** +** ******************************************************************** +*/ + +/* +** To use MD4: +** -- Include md4.h in your program +** -- Declare an MDstruct MD to hold the state of the digest +** computation. +** -- Initialize MD using MDbegin(&MD) +** -- For each full block (64 bytes) X you wish to process, call +** 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, +** 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 +** has n = 0. +** -- The message digest is available in MD.buffer[0] ... +** MD.buffer[3]. (Least-significant byte of each word +** should be output first.) +** -- You can print out the digest using MDprint(&MD) +*/ + +/* Implementation notes: +** This implementation assumes that ints are 32-bit quantities. +*/ + +#define TRUE 1 +#define FALSE 0 + +/* Compile-time includes +*/ +#include +#include "md4.h" + +/* Compile-time declarations of MD4 "magic constants". +*/ +#define I0 0x67452301 /* Initial values for MD buffer */ +#define I1 0xefcdab89 +#define I2 0x98badcfe +#define I3 0x10325476 +#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */ +#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */ +/* C2 and C3 are from Knuth, The Art of Programming, Volume 2 +** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley. +** Table 2, page 660. +*/ + +#define fs1 3 /* round 1 shift amounts */ +#define fs2 7 +#define fs3 11 +#define fs4 19 +#define gs1 3 /* round 2 shift amounts */ +#define gs2 5 +#define gs3 9 +#define gs4 13 +#define hs1 3 /* round 3 shift amounts */ +#define hs2 9 +#define hs3 11 +#define hs4 15 + +/* Compile-time macro declarations for MD4. +** Note: The "rot" operator uses the variable "tmp". +** It assumes tmp is declared as unsigned int, so that the >> +** operator will shift in zeros rather than extending the sign bit. +*/ +#define f(X,Y,Z) ((X&Y) | ((~X)&Z)) +#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z)) +#define h(X,Y,Z) (X^Y^Z) +#define rot(X,S) (tmp=X,(tmp<>(32-S))) +#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),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) + +/* 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]. +** Each byte is printed with high-order hexadecimal digit first. +** This is a user-callable routine. +*/ +void +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); +} + +/* MD4Init(MDp) +** Initialize message digest buffer MDp. +** This is a user-callable routine. +*/ +void +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) +** Update message digest buffer MDp->buffer using 16-word data block X. +** Assumes all 16 words of X are full of data. +** Does not update MDp->count. +** This routine is not user-callable. +*/ +static void +MDblock(MDp,Xb) +MD4_CTX *MDp; +unsigned char *Xb; +{ + register unsigned int tmp, A, B, C, D; + unsigned int X[16]; + int i; + + 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; +} + +/* 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 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 +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. + */ + 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. +*/ +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 +****************************(cut)***********************************/ --- md4.h.bak 2003-10-13 10:09:34.000000000 -0500 +++ md4.h 2003-10-01 12:34:41.000000000 -0500 @@ -0,0 +1,64 @@ + +/* +** ******************************************************************** +** md4.h -- Header file for implementation of ** +** MD4 Message Digest Algorithm ** +** Updated: 2/13/90 by Ronald L. Rivest ** +** (C) 1990 RSA Data Security, Inc. ** +** ******************************************************************** +*/ + +#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 */ +} MD4_CTX; + +/* MD4Init(MD4_CTX *) +** Initialize the MD4_CTX prepatory to doing a message digest +** computation. +*/ +extern void MD4Init __P((MD4_CTX *MD)); + +/* 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, 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 MD4Update with a +** count less than 512. Zero is OK for a count. +*/ +extern void MD4Update __P((MD4_CTX *MD, unsigned char *X, unsigned int count)); + +/* 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 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 +****************************(cut)***********************************/