[comp.sources.misc] v19i018: md4tools - MD4 netnews verification tools, Part02/02

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.