kent@sparky.imd.sterling.com (Kent Landfield) (05/09/91)
Submitted-by: Kent Landfield <kent@sparky.imd.sterling.com> Posting-number: Volume 19, Issue 18 Archive-name: md4tools/part02 #! /bin/sh # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: Makefile TestArticle checkmd4.1 checkmd4.c hashmd4.1 # hashmd4.c md4.h md4driver.c pipeit.c # Wrapped by kent@sparky on Tue May 7 23:23:54 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive 2 (of 2)."' if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(1496 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# X# Makefile for md4 X# X XINSTALLDIR=/usr/local/bin XMAN_DIR=/usr/man/manl XMAN_SEC=l X XPROGS = md4 checkmd4 hashmd4 X Xall: $(PROGS) X Xmd4: md4.o md4driver.o X $(CC) $(CFLAGS) -o $@ md4.o md4driver.o X Xcheckmd4: checkmd4.o pipeit.o X $(CC) $(CFLAGS) -o $@ checkmd4.o pipeit.o X Xhashmd4: hashmd4.o pipeit.o X $(CC) $(CFLAGS) -o $@ hashmd4.o pipeit.o X Xmd4.o: md4.c md4.h md4driver.c Xcheckmd4.o: checkmd4.c md4_def.h Xhashmd4: hashmd4.c md4_def.h Xpipeit.o: pipeit.c md4_def.h X Xclean: X rm -f md4driver.o md4.o X rm -f checkmd4.o hashmd4.o pipeit.o X Xclobber: clean X rm -f $(PROGS) X Xprint: print_md4 print_tools print_rfc X cprint README | lpr X cprint TestArticle | lpr X cprint Makefile | lpr X Xprint_tools: X cprint checkmd4.c | lpr X cprint hashmd4.c | lpr X cprint pipeit.c | lpr X cprint md4_def.h | lpr X psroff -man checkmd4.1 X psroff -man hashmd4.1 X Xprint_md4: X cprint md4.h | lpr X cprint md4.c | lpr X cprint md4driver.c | lpr X Xprint_rfc: X cprint rfc1186 | lpr X Xinstall: all X @echo Installing according to local convention X# strip md4 checkmd4 hashmd4 X# cp md4 checkmd4 hashmd4 $(INSTALLDIR) X# chown bin $(INSTALLDIR)/md4 X# chgrp bin $(INSTALLDIR)/md4 X# chmod 755 $(INSTALLDIR)/md4 X# chown bin $(INSTALLDIR)/checkmd4 X# chgrp bin $(INSTALLDIR)/checkmd4 X# chmod 755 $(INSTALLDIR)/checkmd4 X# chown bin $(INSTALLDIR)/hashmd4 X# chgrp bin $(INSTALLDIR)/hashmd4 X# chmod 755 $(INSTALLDIR)/hashmd4 X# cp checkmd4.1 $(MAN_DIR)/checkmd4.$(MAN_SEC) X# cp hashmd4.1 $(MAN_DIR)/hashmd4.$(MAN_SEC) X# END_OF_FILE if test 1496 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'TestArticle' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'TestArticle'\" else echo shar: Extracting \"'TestArticle'\" \(3146 characters\) sed "s/^X//" >'TestArticle' <<'END_OF_FILE' XPath: sparky!kent XFrom: kent@sparky.imd.sterling.com (Kent Landfield) XNewsgroups: sterling.test XSubject: This is a test of the MD4 fingerprint function XOrganization: Sterling Intelligence and Military Division XX-Md4-Signature: ea6ec5dcd12eb080587e12a6b4ceae23 X XAs stated in RFC1186: X X This note describes the MD4 message digest algorithm. The algorithm X takes as input an input message of arbitrary length and produces as X output a 128-bit "fingerprint" or "message digest" of the input. It X is conjectured that it is computationally infeasible to produce two X messages having the same message digest, or to produce any message X having a given prespecified target message digest. The MD4 algorithm X is thus ideal for digital signature applications, where a large file X must be "compressed" in a secure manner before being signed with the X RSA public-key cryptosystem. X XMD4 can be used to apply a fingerprint on an article posted to USENET that, Xwhen run through a verification tool, will tell you whether an article has Xbeen corrupted. It does not detect or prevent complete replacement of the Xarticle. Think of MD4 as a super-strong checksum. X XThis package is an "assembled" set of tools that uses the MD4 Message XDigest Algorithm specified in RFC1186. There are three parts to the package. X Xmd4 - This is the heart of the tools. The code was taken from RFC1186, X "The MD4 Message Digest Algorithm" authored by Ronald L. Rivest. X XI *completely* and shamefully stole the MD4 code from the RFC and as such it Xmust be distributed under the terms specified in md4.c, md4.h and md4driver.c. XThanks to Ron for the code and to RSA Data Security, Inc. for giving me the Xpermission to post it. X Xhashmd4 - This program is used to apply an MD4 digest on a specified X USENET article. A new header is added to the article. The X header X-Md4-Signature: contains the value that will be checked X against to determine if the article is intact. X Xcheckmd4 - This is the program used to check whether the MD4 digest X of a USENET article indicates whether or not the article X has been tampered with. X XI would like to thank Rich Salz for posting snefru and giving me something Xto "hack".. :-) checkmd4 and hashmd4 look almost exactly like Rich's code Xfor good reason. They are... I did the bare minimum to get this working. XThat's all I had to do... :-) For those of you currently using hashnews Xand checknews, this (other than the names) should be a plug amd play... X XThere are manual pages for checkmd4 and for hashmd4 supplied. The actual XRFC1186 is supplied as a reference for MD4. X XCode that does not contain an explicit RSA copyright was derived from XRich Salz's code that was already in the public domain. Feel free to do Xwhat you want with those pieces. X XThis code needs a 32bit machine; good luck if you've only got 16 bits! X XStarting with this posting, I am going to be using hashmd4 on all my Xc.s.m articles. While I don't think that this is worth doing for most Xgeneral Usenix articles, I think it will be an interesting experiment for Xarchives. X XEnjoy! X -Kent+ END_OF_FILE if test 3146 -ne `wc -c <'TestArticle'`; then echo shar: \"'TestArticle'\" unpacked with wrong size! fi # end of 'TestArticle' fi if test -f 'checkmd4.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'checkmd4.1'\" else echo shar: Extracting \"'checkmd4.1'\" \(1024 characters\) sed "s/^X//" >'checkmd4.1' <<'END_OF_FILE' X.TH CHECKMD4 1 LOCAL X.SH NAME Xcheckmd4 \- Check the MD4 hash code on a Usenet article X.SH SYNOPSIS X.B checkmd4 X[ X.B \-n X] [ X.I input X] X.SH DESCRIPTION X.I Checkmd4 Xreads a Usenet article from the named file, or standard input if no file Xis given. XIt filters out the headers and calls X.IR md4 X(see RFC1186) to generate a one-way hash signature or "message digest" for Xthe article. It compares this with the value specified in the X-Md4-Signature: Xheader, and prints a message indicating whether they match or not. XTo suppress the message, use the ``\-s'' flag. X.PP XThe program will exit with status zero if the article is okay. An exit value Xof one is returned if the signatures don't match, or a two if no XX-Md4-Signature header can be found. X.SH WARNING X.I Checkmd4 Xwill only prove if an article has been tampered with; it does not Xprovide any authentication. X.SH AUTHOR X.nf XOriginally written by Rich Salz <rsalz@bbn.com> XHacked by Kent Landfield <kent@sparky.imd.sterling.com> X.fi X.SH "SEE ALSO" Xhashmd4(1L), RFC1186. END_OF_FILE if test 1024 -ne `wc -c <'checkmd4.1'`; then echo shar: \"'checkmd4.1'\" unpacked with wrong size! fi # end of 'checkmd4.1' fi if test -f 'checkmd4.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'checkmd4.c'\" else echo shar: Extracting \"'checkmd4.c'\" \(2713 characters\) sed "s/^X//" >'checkmd4.c' <<'END_OF_FILE' X/* X** Verify a Usenet article with a MD4 hash header. X*/ X#include <stdio.h> X#include <ctype.h> X#include "md4_def.h" X X#ifndef isascii X#define isascii(c) (1) X#endif /* isascii */ X Xextern char *optarg; Xextern int optind; X Xextern char *mktemp(); Xextern char *Md4Close(); Xextern char *strcpy(); Xextern FILE *Md4Open(); X X Xstatic void XUsage() X{ X (void)fprintf(stderr, "Usage: checkhash [filename]\n"); X exit(1); X} X X Xmain(ac, av) X int ac; X char *av[]; X{ X char *p; X char buff[BUFSIZ]; X char Checksum[40]; X FILE *Input; X FILE *Md4; X int i; X int Silent; X X /* Set defaults. */ X Silent = FALSE; X X /* Parse JCL. */ X while ((i = getopt(ac, av, "s")) != EOF) X switch (i) { X default: X Usage(); X /* NOTREACHED */ X case 's': X Silent = TRUE; X break; X } X X /* Get input. */ X ac -= optind; X av += optind; X switch (ac) { X default: X Usage(); X case 0: X Input = stdin; X break; X case 1: X if ((Input = fopen(av[0], "r")) == NULL) { X perror("No input"); X (void)fprintf(stderr, "Can't open \"%s\" for reading.\n", av[0]); X exit(1); X } X break; X } X X /* Read headers, looking for the checksum. */ X Checksum[0] = '\0'; X while (fgets(buff, sizeof buff, Input)) { X if (buff[0] == '\n') X break; X if (buff[0] == HDRFIRSTCHAR X && strncmp(buff, CHECKSUMHDR, sizeof CHECKSUMHDR - 1) == 0) { X p = &buff[sizeof CHECKSUMHDR] + 1; X /* Right length, allowing for the newline? */ X if (strlen(p) != HDRTEXTSIZE + 1) { X if (!Silent) X (void)printf("%d Wrong length:\n\t%s", strlen(p) ,buff); X continue; X } X (void)strcpy(Checksum, p); X Checksum[HDRTEXTSIZE] = '\0'; X for (p = Checksum; *p; p++) X if (*p != ' ' && !(isascii(*p) && isxdigit(*p))) X break; X if (*p) { X if (!Silent) X (void)printf("Bad character '%c':\n\t%s", *p, buff); X /* Broke out before reaching the end, invalid header. */ X Checksum[0] = '\0'; X } X } X } X X if (Checksum[0] == '\0') { X if (!Silent) X (void)printf("No valid checksum header found.\n"); X exit(2); X } X X /* Call up Md4. */ X if ((Md4 = Md4Open()) == NULL) { X if (!Silent) X perror("Can't open pipe to md4"); X exit(2); X } X X /* Send the rest of the article down the pipe. */ X while (fgets(buff, sizeof buff, Input)) X (void)fputs(buff, Md4); X (void)fclose(Input); X X if ((p = Md4Close()) == NULL) { X if (!Silent) X perror("Can't open tempfile"); X exit(2); X } X X /* Compare them. */ X if (strcmp(p, Checksum) == 0) { X if (!Silent) X (void)printf("Valid.\n"); X exit(0); X } X if (!Silent) { X (void)printf("Invalid!\n"); X (void)printf("Computed: %s\n", p); X (void)printf(" Posted: %s\n", Checksum); X } X exit(1); X} END_OF_FILE if test 2713 -ne `wc -c <'checkmd4.c'`; then echo shar: \"'checkmd4.c'\" unpacked with wrong size! fi # end of 'checkmd4.c' fi if test -f 'hashmd4.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hashmd4.1'\" else echo shar: Extracting \"'hashmd4.1'\" \(1586 characters\) sed "s/^X//" >'hashmd4.1' <<'END_OF_FILE' X.TH HASHMD4 1 LOCAL X.SH NAME Xhashmd4 \- add a MD4 hash to a Usenet article X.SH SYNOPSIS X.B hashmd4 X[ X.B \-n X] [ X.I input X] X.SH DESCRIPTION XThis program is used to apply an MD4 digest, or fingerprint, on an article Xintended to be posted to USENET. X.I Hashmd4 Xadds the X-Md4-Signature: header to the article. The header contains Xthe article's MD4 signature value that will be checked by X.IR checkmd4 Xto determine if the article is intact. X.I Hashmd4 Xcalls X.IR md4 X(See RFC1186) to generate a one-way hash signature for the article. X.PP XIf a file is named on the command line, then X.I hashmd4 Xwill overwrite the named file after inserting the md4 hashcode. XIf no file is named, the program will read the article from standard Xinput, and write the new article on standard output; this makes it Xconvenient to do ``:%!hashmd4'' from X.IR vi (1) Xjust before exiting the editor with your article in it. X.PP XBy default, X.I hashmd4 Xwill try to read the file ``.signature'' in your home directory and Xappend it to the article. XIt tries to simulate the actions of B2.11 X.IR inews (8). XTo suppress this check (for example, if you append your own signature), Xuse the ``\-n'' flag. XThe header that hashmd4 puts on an article is of the form X.IP XX-Md4-Signature: value X.SH WARNING X.I Hashmd4 Xusage will only prove if an article has or has no been tampered with. It Xdoes not provide any authentication. X.SH AUTHOR X.nf XOriginally written as hashnews for snefru by Rich Salz <rsalz@bbn.com> XHacked into hashmd4 by Kent Landfield <kent@sparky.imd.sterling.com> X.fi X.SH "SEE ALSO" Xcheckmd4(1L), RFC1186. END_OF_FILE if test 1586 -ne `wc -c <'hashmd4.1'`; then echo shar: \"'hashmd4.1'\" unpacked with wrong size! fi # end of 'hashmd4.1' fi if test -f 'hashmd4.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hashmd4.c'\" else echo shar: Extracting \"'hashmd4.c'\" \(4909 characters\) sed "s/^X//" >'hashmd4.c' <<'END_OF_FILE' X/* X** Call MD4 on something about to be feed into INEWS. Then, rewrite X** the file to add the X-Md4-Signature header. X*/ X#include <stdio.h> X#include <pwd.h> X#include "md4_def.h" X X#ifdef USE_STRCHR X#define IDX strchr X#else X#define IDX index X#endif /* USE_STRCHR */ X X#ifndef SEEK_ABS X#define SEEK_ABS 0 X#endif /* SEEK_ABS */ X Xextern char *optarg; Xextern int optind; X Xextern char *getenv(); Xextern char *IDX(); Xextern char *mktemp(); Xextern char *Md4Close(); Xextern char *strcpy(); Xextern FILE *Md4Open(); Xextern long ftell(); Xextern struct passwd *getpwuid(); X#ifdef CHARPSPRINTF Xextern char *sprintf(); X#endif /* CHARPSPRINTF */ X Xstatic void XUsage() X{ X (void)fprintf(stderr, "Usage: hashmd4 articlename\n"); X exit(1); X} X X X/* X** Simulate what B2.11 inews does for appending signatures. X*/ Xstatic int XAppendSignature(Md4) X FILE *Md4; X{ X char *p; X char buff[256]; X FILE *F; X int i; X struct passwd *pwd; X X if ((p = getenv("HOME")) == NULL X && (p = getenv("LOGDIR")) == NULL) { X if ((pwd = getpwuid(getuid())) == NULL) X return 0; X p = pwd->pw_dir; X } X (void)sprintf(buff, "%s/.signature", p); X if ((F = fopen(buff, "r")) == NULL) X return 0; X for (i = 0; fgets(buff, sizeof buff, F); i++) X if (IDX(buff, '\n') == NULL) { X i = 0; X break; X } X if (i > 5 || i == 0) { X (void)fclose(F); X return 0; X } X (void)fprintf(Md4, "-- \n"); X rewind(F); X while (fgets(buff, sizeof buff, F)) X (void)fputs(buff, Md4); X (void)fclose(F); X return i; X} X X Xmain(ac, av) X int ac; X char *av[]; X{ X int i; X int CheckSignature; X FILE *Input; X FILE *Md4; X FILE *Output; X FILE *Body; X char buff[BUFSIZ]; X char *p; X char tempfile[20]; X char bodyfile[20]; X long cookie; X X /* Set defaults. */ X CheckSignature = TRUE; X X /* Parse JCL. */ X while ((i = getopt(ac, av, "n")) != EOF) X switch (i) { X default: X Usage(); X case 'n': X CheckSignature = FALSE; X break; X } X X /* Get input. */ X ac -= optind; X av += optind; X switch (ac) { X default: X Usage(); X /* NOTREACHED */ X case 0: X /* We're being piped into. Create a temp file to hold the X * article body. */ X Input = stdin; X (void)strcpy(bodyfile, "/tmp/hashBXXXXXX"); X (void)mktemp(bodyfile); X if ((Body = fopen(bodyfile, "w")) == NULL) { X perror("No temporary"); X (void)fprintf(stderr, "Can't open \"%s\" for writing.\n", X bodyfile); X exit(1); X } X break; X case 1: X if ((Input = fopen(av[0], "r")) == NULL) { X perror("No input"); X (void)fprintf(stderr, "Can't open \"%s\" for reading.\n", av[0]); X exit(1); X } X Body = NULL; X break; X } X X /* Get output file. */ X (void)strcpy(tempfile, "/tmp/hashHXXXXXX"); X (void)mktemp(tempfile); X if ((Output = fopen(tempfile, "w")) == NULL) { X perror("No output"); X (void)fprintf(stderr, "Can't open \"%s\" for writing.\n", tempfile); X exit(1); X } X X /* Open stream to md4. */ X if ((Md4 = Md4Open()) == NULL) { X perror("Can't open pipe to md4"); X (void)fclose(Output); X (void)unlink(tempfile); X exit(1); X } X X /* Read article, skipping headers. */ X while (fgets(buff, sizeof buff, Input)) { X if (buff[strlen(buff) - 1] != '\n') X (void)fprintf(stderr, "Warning, line truncated:\n%s\n", X buff); X if (buff[0] == '\n') X break; X (void)fputs(buff, Output); X } X X /* If not from stdin we can seek, so remember where the headers end. */ X if (Body == NULL) X cookie = ftell(Input); X X /* Send rest of article to md4. */ X while (fgets(buff, sizeof buff, Input)) { X if (buff[strlen(buff) - 1] != '\n') X (void)fprintf(stderr, "Warning, line truncated:\n%s\n", X buff); X (void)fputs(buff, Md4); X if (Body) X (void)fputs(buff, Body); X } X X /* Do the signature? */ X if (CheckSignature) { X if ((i = AppendSignature(Md4)) == 0) X (void)fprintf(stderr, ".signature unreadable or too long...\n"); X } X X (void)fclose(Input); X X /* Write the checksum. */ X if (p = Md4Close()) X (void)fprintf(Output, "%s: %s\n", CHECKSUMHDR, p); X else X (void)fprintf(stderr, "Md4 checksum lost!?\n"); X X /* Send the article body. */ X if (Body) { X (void)fclose(Body); X Input = fopen(bodyfile, "r"); X } X else { X Input = fopen(av[0], "r"); X (void)fseek(Input, cookie, SEEK_ABS); X } X (void)fputs("\n", Output); X while (fgets(buff, sizeof buff, Input)) X (void)fputs(buff, Output); X (void)fclose(Output); X X if (Input == stdin) X /* Input is stdin, so send output to stdout. */ X Output = stdout; X else if ((Output = fopen(av[0], "w")) == NULL) { X perror("Can't rewrite file"); X (void)fprintf(stderr, X "Can't overwrite \"%s\", output is in \"%s\".\n", X av[0], tempfile); X exit(1); X } X X Input = fopen(tempfile, "r"); X while (fgets(buff, sizeof buff, Input)) X (void)fputs(buff, Output); X X if (Output != stdout); X (void)unlink(tempfile); X (void)fclose(Output); X exit(0); X} END_OF_FILE if test 4909 -ne `wc -c <'hashmd4.c'`; then echo shar: \"'hashmd4.c'\" unpacked with wrong size! fi # end of 'hashmd4.c' fi if test -f 'md4.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'md4.h'\" else echo shar: Extracting \"'md4.h'\" \(3266 characters\) sed "s/^X//" >'md4.h' <<'END_OF_FILE' X/* X*--------------------------------------------------------------------------* X* (C) Copyright 1990, RSA Data Security, Inc. All rights reserved. * X* License to copy and use this software is granted provided it is * X* identified as the "RSA Data Security, Inc. MD4 message digest algorithm" * X* in all material mentioning or referencing this software or function. * X* * X* License is also granted to make and use derivative works provided such * X* works are identified as "derived from the RSA Data Securitry, Inc. MD4 * X* message digest algorithm" in all material mentioning or referencing the * X* derived work. * X* * X* RSA Data Security, Inc. makes no representations concerning the * X* merchantability of this software or the suitability of the software * X* for any particular purpose. It is provided "as is" without express * X* or implied warranty of any kind. * X* * X* These notices must be retained in any copies of any part of this * X* documentation and/or software. * X*--------------------------------------------------------------------------* X** ******************************************************************** X** md4.h -- Header file for implementation of ** X** MD4 Message Digest Algorithm ** X** Updated: 2/13/90 by Ronald L. Rivest ** X** (C) 1990 RSA Data Security, Inc. ** X** ******************************************************************** X*/ X X/* MDstruct is the data structure for a message digest computation. X*/ Xtypedef struct { X unsigned int buffer[4]; /* Holds 4-word result of MD computation */ X unsigned char count[8]; /* Number of bits processed so far */ X unsigned int done; /* Nonzero means MD computation finished */ X} MDstruct, *MDptr; X X/* MDbegin(MD) X** Input: MD -- an MDptr X** Initialize the MDstruct prepatory to doing a message digest X** computation. X*/ Xextern void MDbegin(); X X/* MDupdate(MD,X,count) X** Input: MD -- an MDptr X** X -- a pointer to an array of unsigned characters. X** count -- the number of bits of X to use (an unsigned int). X** Updates MD using the first "count" bits of X. X** The array pointed to by X is not modified. X** If count is not a multiple of 8, MDupdate uses high bits of X** last byte. X** This is the basic input routine for a user. X** The routine terminates the MD computation when count < 512, so X** every MD computation should end with one call to MDupdate with a X** count less than 512. Zero is OK for a count. X*/ Xextern void MDupdate(); X X/* MDprint(MD) X** Input: MD -- an MDptr X** Prints message digest buffer MD as 32 hexadecimal digits. X** Order is from low-order byte of buffer[0] to high-order byte X** of buffer[3]. X** Each byte is printed with high-order hexadecimal digit first. X*/ Xextern void MDprint(); X X/* X** End of md4.h X*/ END_OF_FILE if test 3266 -ne `wc -c <'md4.h'`; then echo shar: \"'md4.h'\" unpacked with wrong size! fi # end of 'md4.h' fi if test -f 'md4driver.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'md4driver.c'\" else echo shar: Extracting \"'md4driver.c'\" \(4915 characters\) sed "s/^X//" >'md4driver.c' <<'END_OF_FILE' X/* X*--------------------------------------------------------------------------* X* (C) Copyright 1990, RSA Data Security, Inc. All rights reserved. * X* License to copy and use this software is granted provided it is * X* identified as the "RSA Data Security, Inc. MD4 message digest algorithm" * X* in all material mentioning or referencing this software or function. * X* * X* License is also granted to make and use derivative works provided such * X* works are identified as "derived from the RSA Data Securitry, Inc. MD4 * X* message digest algorithm" in all material mentioning or referencing the * X* derived work. * X* * X* RSA Data Security, Inc. makes no representations concerning the * X* merchantability of this software or the suitability of the software * X* for any particular purpose. It is provided "as is" without express * X* or implied warranty of any kind. * X* * X* These notices must be retained in any copies of any part of this * X* documentation and/or software. * X*--------------------------------------------------------------------------* X** ******************************************************************** X** md4driver.c -- sample routines to test ** X** MD4 message digest algorithm. ** X** Updated: 2/16/90 by Ronald L. Rivest ** X** (C) 1990 RSA Data Security, Inc. ** X** ******************************************************************** X*/ X X#include <stdio.h> X#include "md4.h" X X/* MDtimetrial() X** A time trial routine, to measure the speed of MD4. X** Measures speed for 1M blocks = 64M bytes. X*/ XMDtimetrial() X{ unsigned int X[16]; X MDstruct MD; X int i; X double t; X for (i=0;i<16;i++) X[i] = 0x01234567 + i; X printf X ("MD4 time trial. Processing 1 million 64-character blocks...\n"); X clock(); X MDbegin(&MD); X for (i=0;i<1000000;i++) MDupdate(&MD,X,512); X MDupdate(&MD,X,0); X t = (double) clock(); /* in microseconds */ X MDprint(&MD); printf(" is digest of 64M byte test input.\n"); X printf("Seconds to process test input: %g\n",t/1e6); X printf("Characters processed per second: %ld.\n",(int)(64e12/t)); X} X X/* MDstring(s) X** Computes the message digest for string s. X** Prints out message digest, a space, the string (in quotes) and a X** carriage return. X*/ XMDstring(s) Xunsigned char *s; X{ unsigned int i, len = strlen(s); X MDstruct MD; X MDbegin(&MD); X for (i=0;i+64<=len;i=i+64) MDupdate(&MD,s+i,512); X MDupdate(&MD,s+i,(len-i)*8); X MDprint(&MD); X printf(" \"%s\"\n",s); X} X X/* MDfile(filename) X** Computes the message digest for a specified file. X** Prints out message digest, a space, the file name, and a X** carriage return. X*/ XMDfile(filename) Xchar *filename; X{ FILE *f = fopen(filename,"rb"); X unsigned char X[64]; X MDstruct MD; X int b; X if (f == NULL) X { printf("%s can't be opened.\n",filename); return; } X MDbegin(&MD); X while ((b=fread(X,1,64,f))!=0) MDupdate(&MD,X,b*8); X MDupdate(&MD,X,0); X MDprint(&MD); X printf(" %s\n",filename); X fclose(f); X} X X/* MDfilter() X** Writes the message digest of the data from stdin onto stdout, X** followed by a carriage return. X*/ XMDfilter() X{ unsigned char X[64]; X MDstruct MD; X int b; X MDbegin(&MD); X while ((b=fread(X,1,64,stdin))!=0) MDupdate(&MD,X,b*8); X MDupdate(&MD,X,0); X MDprint(&MD); X printf("\n"); X} X X/* MDtestsuite() X** Run a standard suite of test data. X*/ XMDtestsuite() X{ X printf("MD4 test suite results:\n"); X MDstring(""); X MDstring("a"); X MDstring("abc"); X MDstring("message digest"); X MDstring("abcdefghijklmnopqrstuvwxyz"); X MDstring X ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); X MDfile("foo"); /* Contents of file foo are "abc" */ X} X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ int i; X /* For each command line argument in turn: X ** filename -- prints message digest and name of file X ** -sstring -- prints message digest and contents of string X ** -t -- prints time trial statistics for 64M bytes X ** -x -- execute a standard suite of test data X ** (no args) -- writes messages digest of stdin onto stdout X */ X if (argc==1) MDfilter(); X else X for (i=1;i<argc;i++) X if (argv[i][0]=='-' && argv[i][1]=='s') MDstring(argv[i]+2); X else if (strcmp(argv[i],"-t")==0) MDtimetrial(); X else if (strcmp(argv[i],"-x")==0) MDtestsuite(); X else MDfile(argv[i]); X} X X/* X** end of md4driver.c X*/ END_OF_FILE if test 4915 -ne `wc -c <'md4driver.c'`; then echo shar: \"'md4driver.c'\" unpacked with wrong size! fi # end of 'md4driver.c' fi if test -f 'pipeit.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'pipeit.c'\" else echo shar: Extracting \"'pipeit.c'\" \(1266 characters\) sed "s/^X//" >'pipeit.c' <<'END_OF_FILE' X/* X** Utility routines to interface to the MD4 program as a filter. X*/ X#include <stdio.h> X#include "md4_def.h" X X#ifdef USE_STRCHR X#define RDX strrchr X#else X#define RDX rindex X#endif /* USE_STRCHR */ X Xstatic char OutputFile[] = "/tmp/hashcodeXXXXXX"; Xstatic char ChecksumBuffer[HDRTEXTSIZE + 2]; Xstatic FILE *Stream; X Xextern char *RDX(); Xextern char *mktemp(); X#ifdef CHARPSPRINTF Xextern char *sprintf(); X#endif /* CHARPSPRINTF */ X X X/* X** Spawn a MD4 that has its output redirected. X*/ XFILE * XMd4Open() X{ X char buff[sizeof OutputFile + 20]; X X /* Open stream to md4. */ X (void)mktemp(OutputFile); X (void)sprintf(buff, "md4 >%s", OutputFile); X if ((Stream = popen(buff, "w")) == NULL) X (void)unlink(OutputFile); X return Stream; X} X X X/* X** Close the pipe and read in the Md4's output. X*/ Xchar * XMd4Close() X{ X FILE *F; X char *p; X X (void)pclose(Stream); X X /* Open the output file, read the one line. */ X if ((F = fopen(OutputFile, "r")) == NULL) X return NULL; X p = fgets(ChecksumBuffer, sizeof ChecksumBuffer, F); X (void)fclose(F); X (void)unlink(OutputFile); X if (p == NULL) X return NULL; X X /* Kill the newline. */ X if ((p = RDX(ChecksumBuffer, '\n')) == NULL) X return NULL; X *p = '\0'; X return ChecksumBuffer; X} END_OF_FILE if test 1266 -ne `wc -c <'pipeit.c'`; then echo shar: \"'pipeit.c'\" unpacked with wrong size! fi # end of 'pipeit.c' fi echo shar: End of archive 2 \(of 2\). cp /dev/null ark2isdone MISSING="" for I in 1 2 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked both archives. rm -f ark[1-9]isdone else echo You still must unpack the following archives: echo " " ${MISSING} fi exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net. exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.