home *** CD-ROM | disk | FTP | other *** search
- From: kent@sparky.imd.sterling.com (Kent Landfield)
- Newsgroups: comp.sources.misc
- Subject: v19i017: md4tools - MD4 netnews verification tools, Part01/02
- Message-ID: <1991May9.021044.28164@sparky.IMD.Sterling.COM>
- Date: 9 May 91 02:10:44 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: Kent Landfield <kent@sparky.imd.sterling.com>
- Posting-number: Volume 19, Issue 17
- Archive-name: md4tools/part01
-
- MD4 can be used to apply a fingerprint on an article posted to USENET.
- When run through a verification tool, MD4 will tell you whether an article
- has been corrupted. The use of MD4 does not detect or prevent the complete
- replacement of an article. Think of MD4 as a super-strong checksum. The
- header X-Md4-Signature: contains the value that will be checked against to
- determine if the article is intact.
-
- Starting with this posting, I am going to be using the X-Md4-Signature: on
- all articles posted to comp.sources.misc. While I don't think that this is
- worth doing for most general USENET articles, I think it will be extremely
- useful for archives. The X-Md4-Signature: header is going to replace the
- X-Checksum-Snefru: header previously used in this newsgroup.
-
- I would like to thank Ron Rivest (the author of RFC1186, "The MD4 Message
- Digest Algorithm") for the MD4 code and RSA Data Security, Inc. for giving
- me the permission to post it. I would also like to thank Rich Salz for the
- push to do it and for his snefru code that I hacked...
-
- -Kent+
- ---
- #! /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: README foo md4.c md4_def.h rfc1186
- # Wrapped by kent@sparky on Tue May 7 23:23:53 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 1 (of 2)."'
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(3116 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- 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
- XTo compile, edit the Makefile if you use strchr/strrchr rather than
- Xindex/rindex. Also edit md4.c to determine the byte order of your
- Xmachine. There is also a discussion of how to use the routines in
- Xmd4.c in your own programs.
- 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 USENET articles, I think it will be an interesting experiment for
- Xarchives.
- X
- XEnjoy!
- X -Kent+
- END_OF_FILE
- if test 3116 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'foo' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'foo'\"
- else
- echo shar: Extracting \"'foo'\" \(4 characters\)
- sed "s/^X//" >'foo' <<'END_OF_FILE'
- Xabc
- END_OF_FILE
- if test 4 -ne `wc -c <'foo'`; then
- echo shar: \"'foo'\" unpacked with wrong size!
- fi
- # end of 'foo'
- fi
- if test -f 'md4.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'md4.c'\"
- else
- echo shar: Extracting \"'md4.c'\" \(10725 characters\)
- sed "s/^X//" >'md4.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** md4.c -- Implementation of MD4 Message Digest Algorithm **
- X** Updated: 2/16/90 by Ronald L. Rivest **
- X** (C) 1990 RSA Data Security, Inc. **
- X** ********************************************************************
- X*/
- X
- X/*
- X** To use MD4:
- X** -- Include md4.h in your program
- X** -- Declare an MDstruct MD to hold the state of the digest
- X** computation.
- X** -- Initialize MD using MDbegin(&MD)
- X** -- For each full block (64 bytes) X you wish to process, call
- X** MDupdate(&MD,X,512)
- X** (512 is the number of bits in a full block.)
- X** -- For the last block (less than 64 bytes) you wish to process,
- X** MDupdate(&MD,X,n)
- X** where n is the number of bits in the partial block. A partial
- X** block terminates the computation, so every MD computation
- X** should terminate by processing a partial block, even if it
- X** has n = 0.
- X** -- The message digest is available in MD.buffer[0] ...
- X** MD.buffer[3]. (Least-significant byte of each word
- X** should be output first.)
- X** -- You can print out the digest using MDprint(&MD)
- X*/
- X
- X/* Implementation notes:
- X** This implementation assumes that ints are 32-bit quantities.
- X** If the machine stores the least-significant byte of an int in the
- X** least-addressed byte (e.g., VAX and 8086), then LOWBYTEFIRST
- X** should be set to TRUE. Otherwise (e.g., SUNS), LOWBYTEFIRST
- X** should be set to FALSE. Note that on machines with LOWBYTEFIRST
- X** FALSE the routine MDupdate modifies has a side-effect on its input
- X** array (the order of bytes in each word are reversed). If this is
- X** undesired a call to MDreverse(X) can reverse the bytes of X back
- X** into order after each call to MDupdate.
- X*/
- X
- X/* Compile-time includes
- X*/
- X#include <stdio.h>
- X#include "md4.h"
- X
- X#define TRUE 1
- X#define FALSE 0
- X#define LOWBYTEFIRST FALSE
- X
- X
- X/* Compile-time declarations of MD4 "magic constants".
- X*/
- X#define I0 0x67452301 /* Initial values for MD buffer */
- X#define I1 0xefcdab89
- X#define I2 0x98badcfe
- X#define I3 0x10325476
- X#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
- X#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
- X/* C2 and C3 are from Knuth, The Art of Programming, Volume 2
- X** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
- X** Table 2, page 660.
- X*/
- X#define fs1 3 /* round 1 shift amounts */
- X#define fs2 7
- X#define fs3 11
- X#define fs4 19
- X#define gs1 3 /* round 2 shift amounts */
- X#define gs2 5
- X#define gs3 9
- X#define gs4 13
- X#define hs1 3 /* round 3 shift amounts */
- X#define hs2 9
- X#define hs3 11
- X#define hs4 15
- X
- X/* Compile-time macro declarations for MD4.
- X** Note: The "rot" operator uses the variable "tmp".
- X** It assumes tmp is declared as unsigned int, so that the >>
- X** operator will shift in zeros rather than extending the sign bit.
- X*/
- X#define f(X,Y,Z) ((X&Y) | ((~X)&Z))
- X#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z))
- X#define h(X,Y,Z) (X^Y^Z)
- X#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S)))
- X#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
- X#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
- X#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
- X
- X/* MDprint(MDp)
- X** Print message digest buffer MDp as 32 hexadecimal digits.
- X** Order is from low-order byte of buffer[0] to high-order byte of
- X** buffer[3].
- X** Each byte is printed with high-order hexadecimal digit first.
- X** This is a user-callable routine.
- X*/
- Xvoid
- XMDprint(MDp)
- XMDptr MDp;
- X{ int i,j;
- X for (i=0;i<4;i++)
- X for (j=0;j<32;j=j+8)
- X printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
- X}
- X
- X/* MDbegin(MDp)
- X** Initialize message digest buffer MDp.
- X** This is a user-callable routine.
- X*/
- Xvoid
- XMDbegin(MDp)
- XMDptr MDp;
- X{ int i;
- X MDp->buffer[0] = I0;
- X MDp->buffer[1] = I1;
- X MDp->buffer[2] = I2;
- X MDp->buffer[3] = I3;
- X for (i=0;i<8;i++) MDp->count[i] = 0;
- X MDp->done = 0;
- X}
- X
- X/* MDreverse(X)
- X** Reverse the byte-ordering of every int in X.
- X** Assumes X is an array of 16 ints.
- X** The macro revx reverses the byte-ordering of the next word of X.
- X*/
- X#define revx { t = (*X << 16) | (*X >> 16); \
- X *X++ = ((t & 0xFF00FF00) >> 8) | ((t & 0x00FF00FF) << 8); }
- XMDreverse(X)
- Xunsigned int *X;
- X{ register unsigned int t;
- X revx; revx; revx; revx; revx; revx; revx; revx;
- X revx; revx; revx; revx; revx; revx; revx; revx;
- X}
- X
- X/* MDblock(MDp,X)
- X** Update message digest buffer MDp->buffer using 16-word data block X.
- X** Assumes all 16 words of X are full of data.
- X** Does not update MDp->count.
- X** This routine is not user-callable.
- X*/
- Xstatic void
- XMDblock(MDp,X)
- XMDptr MDp;
- Xunsigned int *X;
- X{
- X register unsigned int tmp, A, B, C, D;
- X#if LOWBYTEFIRST == FALSE
- X MDreverse(X);
- X#endif
- X A = MDp->buffer[0];
- X B = MDp->buffer[1];
- X C = MDp->buffer[2];
- X D = MDp->buffer[3];
- X /* Update the message digest buffer */
- X ff(A , B , C , D , 0 , fs1); /* Round 1 */
- X ff(D , A , B , C , 1 , fs2);
- X ff(C , D , A , B , 2 , fs3);
- X ff(B , C , D , A , 3 , fs4);
- X ff(A , B , C , D , 4 , fs1);
- X ff(D , A , B , C , 5 , fs2);
- X ff(C , D , A , B , 6 , fs3);
- X ff(B , C , D , A , 7 , fs4);
- X ff(A , B , C , D , 8 , fs1);
- X ff(D , A , B , C , 9 , fs2);
- X ff(C , D , A , B , 10 , fs3);
- X ff(B , C , D , A , 11 , fs4);
- X ff(A , B , C , D , 12 , fs1);
- X ff(D , A , B , C , 13 , fs2);
- X ff(C , D , A , B , 14 , fs3);
- X ff(B , C , D , A , 15 , fs4);
- X gg(A , B , C , D , 0 , gs1); /* Round 2 */
- X gg(D , A , B , C , 4 , gs2);
- X gg(C , D , A , B , 8 , gs3);
- X gg(B , C , D , A , 12 , gs4);
- X gg(A , B , C , D , 1 , gs1);
- X gg(D , A , B , C , 5 , gs2);
- X gg(C , D , A , B , 9 , gs3);
- X gg(B , C , D , A , 13 , gs4);
- X gg(A , B , C , D , 2 , gs1);
- X gg(D , A , B , C , 6 , gs2);
- X gg(C , D , A , B , 10 , gs3);
- X gg(B , C , D , A , 14 , gs4);
- X gg(A , B , C , D , 3 , gs1);
- X gg(D , A , B , C , 7 , gs2);
- X gg(C , D , A , B , 11 , gs3);
- X gg(B , C , D , A , 15 , gs4);
- X hh(A , B , C , D , 0 , hs1); /* Round 3 */
- X hh(D , A , B , C , 8 , hs2);
- X hh(C , D , A , B , 4 , hs3);
- X hh(B , C , D , A , 12 , hs4);
- X hh(A , B , C , D , 2 , hs1);
- X hh(D , A , B , C , 10 , hs2);
- X hh(C , D , A , B , 6 , hs3);
- X hh(B , C , D , A , 14 , hs4);
- X hh(A , B , C , D , 1 , hs1);
- X hh(D , A , B , C , 9 , hs2);
- X hh(C , D , A , B , 5 , hs3);
- X hh(B , C , D , A , 13 , hs4);
- X hh(A , B , C , D , 3 , hs1);
- X hh(D , A , B , C , 11 , hs2);
- X hh(C , D , A , B , 7 , hs3);
- X hh(B , C , D , A , 15 , hs4);
- X MDp->buffer[0] += A;
- X MDp->buffer[1] += B;
- X MDp->buffer[2] += C;
- X MDp->buffer[3] += D;
- X}
- X
- X/* MDupdate(MDp,X,count)
- X** Input: MDp -- an MDptr
- X** X -- a pointer to an array of unsigned characters.
- X** count -- the number of bits of X to use.
- X** (if not a multiple of 8, uses high bits of last byte.)
- X** Update MDp using the number of bits of X given by count.
- X** This is the basic input routine for an MD4 user.
- X** The routine completes 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. A call with count 0 will be ignored if the
- X** MD has already been terminated (done != 0), so an extra call with
- X** count 0 can be given as a "courtesy close" to force termination
- X** if desired.
- X*/
- Xvoid
- XMDupdate(MDp,X,count)
- XMDptr MDp;
- Xunsigned char *X;
- Xunsigned int count;
- X{ unsigned int i, tmp, bit, byte, mask;
- X unsigned char XX[64];
- X unsigned char *p;
- X /* return with no error if this is a courtesy close with count
- X ** zero and MDp->done is true.
- X */
- X if (count == 0 && MDp->done) return;
- X /* check to see if MD is already done and report error */
- X if (MDp->done)
- X { printf("\nError: MDupdate MD already done."); return; }
- X /* Add count to MDp->count */
- X tmp = count;
- X p = MDp->count;
- X while (tmp)
- X { tmp += *p;
- X *p++ = tmp;
- X tmp = tmp >> 8;
- X }
- X /* Process data */
- X if (count == 512)
- X { /* Full block of data to handle */
- X MDblock(MDp,(unsigned int *)X);
- X }
- X else if (count > 512) /* Check for count too large */
- X { printf("\nError: MDupdate called with illegal count value %d."
- X ,count);
- X return;
- X }
- X else /* partial block -- must be last block so finish up */
- X { /* Find out how many bytes and residual bits there are */
- X byte = count >> 3;
- X bit = count & 7;
- X /* Copy X into XX since we need to modify it */
- X for (i=0;i<=byte;i++) XX[i] = X[i];
- X for (i=byte+1;i<64;i++) XX[i] = 0;
- X /* Add padding '1' bit and low-order zeros in last byte */
- X mask = 1 << (7 - bit);
- X XX[byte] = (XX[byte] | mask) & ~( mask - 1);
- X /* If room for bit count, finish up with this block */
- X if (byte <= 55)
- X { for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
- X MDblock(MDp,(unsigned int *)XX);
- X }
- X else /* need to do two blocks to finish up */
- X { MDblock(MDp,(unsigned int *)XX);
- X for (i=0;i<56;i++) XX[i] = 0;
- X for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
- X MDblock(MDp,(unsigned int *)XX);
- X }
- X /* Set flag saying we're done with MD computation */
- X MDp->done = 1;
- X }
- X}
- X
- X/*
- X** End of md4.c
- X*/
- END_OF_FILE
- if test 10725 -ne `wc -c <'md4.c'`; then
- echo shar: \"'md4.c'\" unpacked with wrong size!
- fi
- # end of 'md4.c'
- fi
- if test -f 'md4_def.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'md4_def.h'\"
- else
- echo shar: Extracting \"'md4_def.h'\" \(194 characters\)
- sed "s/^X//" >'md4_def.h' <<'END_OF_FILE'
- X/*
- X** Include file for hashmd4/checkmd4
- X*/
- X
- X#define CHECKSUMHDR "X-Md4-Signature"
- X#define HDRFIRSTCHAR 'X'
- X#define TRUE 1
- X#define FALSE 0
- X#define HDRTEXTSIZE 32
- X
- END_OF_FILE
- if test 194 -ne `wc -c <'md4_def.h'`; then
- echo shar: \"'md4_def.h'\" unpacked with wrong size!
- fi
- # end of 'md4_def.h'
- fi
- if test -f 'rfc1186' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rfc1186'\"
- else
- echo shar: Extracting \"'rfc1186'\" \(34579 characters\)
- sed "s/^X//" >'rfc1186' <<'END_OF_FILE'
- X
- X
- X
- X
- X
- X
- XNetwork Working Group R. Rivest
- XRequest for Comments: 1186 MIT Laboratory for Computer Science
- X October 1990
- X
- X
- X The MD4 Message Digest Algorithm
- X
- XStatus of this Memo
- X
- X This RFC is the specification of the MD4 Digest Algorithm. If you
- X are going to implement MD4, it is suggested you do it this way. This
- X memo is for informational use and does not constitute a standard.
- X Distribution of this memo is unlimited.
- X
- XTable of Contents
- X
- X 1. Abstract .................................................... 1
- X 2. Terminology and Notation .................................... 2
- X 3. MD4 Algorithm Description ................................... 2
- X 4. Extensions .................................................. 6
- X 5. Summary ..................................................... 7
- X 6. Acknowledgements ............................................ 7
- X APPENDIX - Reference Implementation ............................. 7
- X Security Considerations.......................................... 18
- X Author's Address................................................. 18
- X
- X1. Abstract
- 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
- X The MD4 algorithm is designed to be quite fast on 32-bit machines.
- X On a SUN Sparc station, MD4 runs at 1,450,000 bytes/second. On a DEC
- X MicroVax II, MD4 runs at approximately 70,000 bytes/second. On a
- X 20MHz 80286, MD4 runs at approximately 32,000 bytes/second. In
- X addition, the MD4 algorithm does not require any large substitution
- X tables; the algorithm can be coded quite compactly.
- X
- X The MD4 algorithm is being placed in the public domain for review and
- X possible adoption as a standard.
- X
- X
- X
- X
- XRivest [Page 1]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X (Note: The document supersedes an earlier draft. The algorithm
- X described here is a slight modification of the one described in the
- X draft.)
- X
- X2. Terminology and Notation
- X
- X In this note a "word" is a 32-bit quantity and a byte is an 8-bit
- X quantity. A sequence of bits can be interpreted in a natural manner
- X as a sequence of bytes, where each consecutive group of 8 bits is
- X interpreted as a byte with the high-order (most significant) bit of
- X each byte listed first. Similarly, a sequence of bytes can be
- X interpreted as a sequence of 32-bit words, where each consecutive
- X group of 4 bytes is interpreted as a word with the low-order (least
- X significant) byte given first.
- X
- X Let x_i denote "x sub i". If the subscript is an expression, we
- X surround it in braces, as in x_{i+1}. Similarly, we use ^ for
- X superscripts (exponentiation), so that x^i denotes x to the i-th
- X power.
- X
- X Let the symbol "+" denote addition of words (i.e., modulo- 2^32
- X addition). Let X <<< s denote the 32-bit value obtained by circularly
- X shifting (rotating) X left by s bit positions. Let not(X) denote the
- X bit-wise complement of X, and let X v Y denote the bit-wise OR of X
- X and Y. Let X xor Y denote the bit-wise XOR of X and Y, and let XY
- X denote the bit-wise AND of X and Y.
- X
- X3. MD4 Algorithm Description
- X
- X We begin by supposing that we have a b-bit message as input, and that
- X we wish to find its message digest. Here b is an arbitrary
- X nonnegative integer; b may be zero, it need not be a multiple of 8,
- X and it may be arbitrarily large. We imagine the bits of the message
- X written down as follows:
- X
- X m_0 m_1 ... m_{b-1} .
- X
- X The following five steps are performed to compute the message digest
- X of the message.
- X
- X Step 1. Append padding bits
- X
- X The message is "padded" (extended) so that its length (in bits)
- X is congruent to 448, modulo 512. That is, the message is
- X extended so that it is just 64 bits shy of being a multiple of
- X 512 bits long. Padding is always performed, even if the length
- X of the message is already congruent to 448, modulo 512 (in
- X which case 512 bits of padding are added).
- X
- X
- X
- XRivest [Page 2]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X Padding is performed as follows: a single "1" bit is appended
- X to the message, and then enough zero bits are appended so that
- X the length in bits of the padded message becomes congruent to
- X 448, modulo 512.
- X
- X Step 2. Append length
- X
- X A 64-bit representation of b (the length of the message before
- X the padding bits were added) is appended to the result of the
- X previous step. In the unlikely event that b is greater than
- X 2^64, then only the low-order 64 bits of b are used. (These
- X bits are appended as two 32-bit words and appended low-order
- X word first in accordance with the previous conventions.)
- X
- X At this point the resulting message (after padding with bits
- X and with b) has a length that is an exact multiple of 512 bits.
- X Equivalently, this message has a length that is an exact
- X multiple of 16 (32-bit) words. Let M[0 ... N-1] denote the
- X words of the resulting message, where N is a multiple of 16.
- X
- X Step 3. Initialize MD buffer
- X
- X A 4-word buffer (A,B,C,D) is used to compute the message
- X digest. Here each of A,B,C,D are 32-bit registers. These
- X registers are initialized to the following values in
- X hexadecimal, low-order bytes first):
- X
- X word A: 01 23 45 67
- X word B: 89 ab cd ef
- X word C: fe dc ba 98
- X word D: 76 54 32 10
- X
- X Step 4. Process message in 16-word blocks
- X
- X We first define three auxiliary functions that each take
- X as input three 32-bit words and produce as output one
- X 32-bit word.
- X
- X f(X,Y,Z) = XY v not(X)Z
- X g(X,Y,Z) = XY v XZ v YZ
- X h(X,Y,Z) = X xor Y xor Z
- X
- X In each bit position f acts as a conditional: if x then y else
- X z. (The function f could have been defined using + instead of
- X v since XY and not(X)Z will never have 1's in the same bit
- X position.) In each bit position g acts as a majority function:
- X if at least two of x, y, z are on, then g has a one in that bit
- X position, else g has a zero. It is interesting to note that if
- X
- X
- X
- XRivest [Page 3]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X the bits of X, Y, and Z are independent and unbiased, the each
- X bit of f(X,Y,Z) will be independent and unbiased, and similarly
- X each bit of g(X,Y,Z) will be independent and unbiased. The
- X function h is the bit-wise "xor" or "parity" function; it has
- X properties similar to those of f and g.
- X
- X Do the following:
- X
- X For i = 0 to N/16-1 do /* process each 16-word block */
- X For j = 0 to 15 do: /* copy block i into X */
- X Set X[j] to M[i*16+j].
- X end /* of loop on j */
- X Save A as AA, B as BB, C as CC, and D as DD.
- X
- X [Round 1]
- X Let [A B C D i s] denote the operation
- X A = (A + f(B,C,D) + X[i]) <<< s .
- X Do the following 16 operations:
- X [A B C D 0 3]
- X [D A B C 1 7]
- X [C D A B 2 11]
- X [B C D A 3 19]
- X [A B C D 4 3]
- X [D A B C 5 7]
- X [C D A B 6 11]
- X [B C D A 7 19]
- X [A B C D 8 3]
- X [D A B C 9 7]
- X [C D A B 10 11]
- X [B C D A 11 19]
- X [A B C D 12 3]
- X [D A B C 13 7]
- X [C D A B 14 11]
- X [B C D A 15 19]
- X
- X [Round 2]
- X Let [A B C D i s] denote the operation
- X A = (A + g(B,C,D) + X[i] + 5A827999) <<< s .
- X (The value 5A..99 is a hexadecimal 32-bit
- X constant, written with the high-order digit
- X first. This constant represents the square
- X root of 2. The octal value of this constant
- X is 013240474631. See Knuth, The Art of
- X Programming, Volume 2 (Seminumerical
- X Algorithms), Second Edition (1981),
- X Addison-Wesley. Table 2, page 660.)
- X Do the following 16 operations:
- X [A B C D 0 3]
- X
- X
- X
- XRivest [Page 4]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X [D A B C 4 5]
- X [C D A B 8 9]
- X [B C D A 12 13]
- X [A B C D 1 3]
- X [D A B C 5 5]
- X [C D A B 9 9]
- X [B C D A 13 13]
- X [A B C D 2 3]
- X [D A B C 6 5]
- X [C D A B 10 9]
- X [B C D A 14 13]
- X [A B C D 3 3]
- X [D A B C 7 5]
- X [C D A B 11 9]
- X [B C D A 15 13]
- X
- X [Round 3]
- X Let [A B C D i s] denote the operation
- X A = (A + h(B,C,D) + X[i] + 6ED9EBA1) <<< s .
- X (The value 6E..A1 is a hexadecimal 32-bit
- X constant, written with the high-order digit
- X first. This constant represents the square
- X root of 3. The octal value of this constant
- X is 015666365641. See Knuth, The Art of
- X Programming, Volume 2 (Seminumerical
- X Algorithms), Second Edition (1981),
- X Addison-Wesley. Table 2, page 660.)
- X Do the following 16 operations:
- X [A B C D 0 3]
- X [D A B C 8 9]
- X [C D A B 4 11]
- X [B C D A 12 15]
- X [A B C D 2 3]
- X [D A B C 10 9]
- X [C D A B 6 11]
- X [B C D A 14 15]
- X [A B C D 1 3]
- X [D A B C 9 9]
- X [C D A B 5 11]
- X [B C D A 13 15]
- X [A B C D 3 3]
- X [D A B C 11 9]
- X [C D A B 7 11]
- X [B C D A 15 15]
- X
- X Then perform the following additions:
- X A = A + AA
- X B = B + BB
- X
- X
- X
- XRivest [Page 5]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X C = C + CC
- X D = D + DD
- X (That is, each of the four registers is incremented by
- X the value it had before this block was started.)
- X
- X end /* of loop on i */
- X
- X Step 5. Output
- X
- X The message digest produced as output is A,B,C,D. That is, we
- X begin with the low-order byte of A, and end with the high-order
- X byte of D.
- X
- X This completes the description of MD4. A reference
- X implementation in C is given in the Appendix.
- X
- X4. Extensions
- X
- X If more than 128 bits of output are required, then the following
- X procedure is recommended to obtain a 256-bit output. (There is no
- X provision made for obtaining more than 256 bits.)
- X
- X Two copies of MD4 are run in parallel over the input. The first copy
- X is standard as described above. The second copy is modified as
- X follows.
- X
- X The initial state of the second copy is:
- X word A: 00 11 22 33
- X word B: 44 55 66 77
- X word C: 88 99 aa bb
- X word D: cc dd ee ff
- X
- X The magic constants in rounds 2 and 3 for the second copy of MD4 are
- X changed from sqrt(2) and sqrt(3) to cuberoot(2) and cuberoot(3):
- X
- X Octal Hex
- X Round 2 constant 012050505746 50a28be6
- X Round 3 constant 013423350444 5c4dd124
- X
- X Finally, after every 16-word block is processed (including the last
- X block), the values of the A registers in the two copies are
- X exchanged.
- X
- X The final message digest is obtaining by appending the result of the
- X second copy of MD4 to the end of the result of the first copy of MD4.
- X
- X
- X
- X
- X
- X
- XRivest [Page 6]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X5. Summary
- X
- X The MD4 message digest algorithm is simple to implement, and provides
- X a "fingerprint" or message digest of a message of arbitrary length.
- X
- X It is conjectured that the difficulty of coming up with two messages
- X having the same message digest is on the order of 2^64 operations,
- X and that the difficulty of coming up with any message having a given
- X message digest is on the order of 2^128 operations. The MD4
- X algorithm has been carefully scrutinized for weaknesses. It is,
- X however, a relatively new algorithm and further security analysis is
- X of course justified, as is the case with any new proposal of this
- X sort. The level of security provided by MD4 should be sufficient for
- X implementing very high security hybrid digital signature schemes
- X based on MD4 and the RSA public-key cryptosystem.
- X
- X6. Acknowledgements
- X
- X I'd like to thank Don Coppersmith, Burt Kaliski, Ralph Merkle, and
- X Noam Nisan for numerous helpful comments and suggestions.
- X
- XAPPENDIX - Reference Implementation
- X
- XThis appendix contains the following files:
- X
- X md4.h -- header file for using MD4 implementation
- X md4.c -- the source code for MD4 routines
- X md4driver.c -- a sample "user" routine
- X session -- sample results of running md4driver
- X
- 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 */
- X typedef 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
- X
- X
- XRivest [Page 7]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X ** Input: MD -- an MDptr
- X ** Initialize the MDstruct prepatory to doing a message digest
- X ** computation.
- X */
- X extern 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 */
- X extern 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 */
- X extern void MDprint();
- X
- X /*
- X ** End of md4.h
- X ****************************(cut)***********************************/
- X
- X /*
- X ** ********************************************************************
- X ** md4.c -- Implementation of MD4 Message Digest Algorithm **
- X ** Updated: 2/16/90 by Ronald L. Rivest **
- X ** (C) 1990 RSA Data Security, Inc. **
- X ** ********************************************************************
- X */
- X
- X /*
- X ** To use MD4:
- X ** -- Include md4.h in your program
- X ** -- Declare an MDstruct MD to hold the state of the digest
- X ** computation.
- X ** -- Initialize MD using MDbegin(&MD)
- X
- X
- X
- XRivest [Page 8]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X ** -- For each full block (64 bytes) X you wish to process, call
- X ** MDupdate(&MD,X,512)
- X ** (512 is the number of bits in a full block.)
- X ** -- For the last block (less than 64 bytes) you wish to process,
- X ** MDupdate(&MD,X,n)
- X ** where n is the number of bits in the partial block. A partial
- X ** block terminates the computation, so every MD computation
- X ** should terminate by processing a partial block, even if it
- X ** has n = 0.
- X ** -- The message digest is available in MD.buffer[0] ...
- X ** MD.buffer[3]. (Least-significant byte of each word
- X ** should be output first.)
- X ** -- You can print out the digest using MDprint(&MD)
- X */
- X
- X /* Implementation notes:
- X ** This implementation assumes that ints are 32-bit quantities.
- X ** If the machine stores the least-significant byte of an int in the
- X ** least-addressed byte (e.g., VAX and 8086), then LOWBYTEFIRST
- X ** should be set to TRUE. Otherwise (e.g., SUNS), LOWBYTEFIRST
- X ** should be set to FALSE. Note that on machines with LOWBYTEFIRST
- X ** FALSE the routine MDupdate modifies has a side-effect on its input
- X ** array (the order of bytes in each word are reversed). If this is
- X ** undesired a call to MDreverse(X) can reverse the bytes of X back
- X ** into order after each call to MDupdate.
- X
- X */
- X #define TRUE 1
- X #define FALSE 0
- X #define LOWBYTEFIRST FALSE
- X
- X /* Compile-time includes
- X */
- X #include <stdio.h>
- X #include "md4.h"
- X
- X /* Compile-time declarations of MD4 "magic constants".
- X */
- X #define I0 0x67452301 /* Initial values for MD buffer */
- X #define I1 0xefcdab89
- X #define I2 0x98badcfe
- X #define I3 0x10325476
- X #define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
- X #define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
- X /* C2 and C3 are from Knuth, The Art of Programming, Volume 2
- X ** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
- X ** Table 2, page 660.
- X */
- X
- X
- X
- XRivest [Page 9]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X #define fs1 3 /* round 1 shift amounts */
- X #define fs2 7
- X #define fs3 11
- X #define fs4 19
- X #define gs1 3 /* round 2 shift amounts */
- X #define gs2 5
- X #define gs3 9
- X #define gs4 13
- X #define hs1 3 /* round 3 shift amounts */
- X #define hs2 9
- X #define hs3 11
- X #define hs4 15
- X
- X /* Compile-time macro declarations for MD4.
- X ** Note: The "rot" operator uses the variable "tmp".
- X ** It assumes tmp is declared as unsigned int, so that the >>
- X ** operator will shift in zeros rather than extending the sign bit.
- X */
- X #define f(X,Y,Z) ((X&Y) | ((~X)&Z))
- X #define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z))
- X #define h(X,Y,Z) (X^Y^Z)
- X #define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S)))
- X #define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
- X #define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
- X #define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
- X
- X /* MDprint(MDp)
- X ** Print message digest buffer MDp as 32 hexadecimal digits.
- X ** Order is from low-order byte of buffer[0] to high-order byte of
- X ** buffer[3].
- X ** Each byte is printed with high-order hexadecimal digit first.
- X ** This is a user-callable routine.
- X */
- X void
- X MDprint(MDp)
- X MDptr MDp;
- X { int i,j;
- X for (i=0;i<4;i++)
- X for (j=0;j<32;j=j+8)
- X printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
- X }
- X
- X /* MDbegin(MDp)
- X ** Initialize message digest buffer MDp.
- X ** This is a user-callable routine.
- X */
- X void
- X MDbegin(MDp)
- X
- X
- X
- XRivest [Page 10]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X MDptr MDp;
- X { int i;
- X MDp->buffer[0] = I0;
- X MDp->buffer[1] = I1;
- X MDp->buffer[2] = I2;
- X MDp->buffer[3] = I3;
- X for (i=0;i<8;i++) MDp->count[i] = 0;
- X MDp->done = 0;
- X }
- X
- X /* MDreverse(X)
- X ** Reverse the byte-ordering of every int in X.
- X ** Assumes X is an array of 16 ints.
- X ** The macro revx reverses the byte-ordering of the next word of X.
- X */
- X #define revx { t = (*X << 16) | (*X >> 16); \
- X *X++ = ((t & 0xFF00FF00) >> 8) | ((t & 0x00FF00FF) << 8); }
- X MDreverse(X)
- X unsigned int *X;
- X { register unsigned int t;
- X revx; revx; revx; revx; revx; revx; revx; revx;
- X revx; revx; revx; revx; revx; revx; revx; revx;
- X }
- X
- X /* MDblock(MDp,X)
- X ** Update message digest buffer MDp->buffer using 16-word data block X.
- X ** Assumes all 16 words of X are full of data.
- X ** Does not update MDp->count.
- X ** This routine is not user-callable.
- X */
- X static void
- X MDblock(MDp,X)
- X MDptr MDp;
- X unsigned int *X;
- X {
- X register unsigned int tmp, A, B, C, D;
- X #if LOWBYTEFIRST == FALSE
- X MDreverse(X);
- X #endif
- X A = MDp->buffer[0];
- X B = MDp->buffer[1];
- X C = MDp->buffer[2];
- X D = MDp->buffer[3];
- X /* Update the message digest buffer */
- X ff(A , B , C , D , 0 , fs1); /* Round 1 */
- X ff(D , A , B , C , 1 , fs2);
- X ff(C , D , A , B , 2 , fs3);
- X ff(B , C , D , A , 3 , fs4);
- X
- X
- X
- XRivest [Page 11]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X ff(A , B , C , D , 4 , fs1);
- X ff(D , A , B , C , 5 , fs2);
- X ff(C , D , A , B , 6 , fs3);
- X ff(B , C , D , A , 7 , fs4);
- X ff(A , B , C , D , 8 , fs1);
- X ff(D , A , B , C , 9 , fs2);
- X ff(C , D , A , B , 10 , fs3);
- X ff(B , C , D , A , 11 , fs4);
- X ff(A , B , C , D , 12 , fs1);
- X ff(D , A , B , C , 13 , fs2);
- X ff(C , D , A , B , 14 , fs3);
- X ff(B , C , D , A , 15 , fs4);
- X gg(A , B , C , D , 0 , gs1); /* Round 2 */
- X gg(D , A , B , C , 4 , gs2);
- X gg(C , D , A , B , 8 , gs3);
- X gg(B , C , D , A , 12 , gs4);
- X gg(A , B , C , D , 1 , gs1);
- X gg(D , A , B , C , 5 , gs2);
- X gg(C , D , A , B , 9 , gs3);
- X gg(B , C , D , A , 13 , gs4);
- X gg(A , B , C , D , 2 , gs1);
- X gg(D , A , B , C , 6 , gs2);
- X gg(C , D , A , B , 10 , gs3);
- X gg(B , C , D , A , 14 , gs4);
- X gg(A , B , C , D , 3 , gs1);
- X gg(D , A , B , C , 7 , gs2);
- X gg(C , D , A , B , 11 , gs3);
- X gg(B , C , D , A , 15 , gs4);
- X hh(A , B , C , D , 0 , hs1); /* Round 3 */
- X hh(D , A , B , C , 8 , hs2);
- X hh(C , D , A , B , 4 , hs3);
- X hh(B , C , D , A , 12 , hs4);
- X hh(A , B , C , D , 2 , hs1);
- X hh(D , A , B , C , 10 , hs2);
- X hh(C , D , A , B , 6 , hs3);
- X hh(B , C , D , A , 14 , hs4);
- X hh(A , B , C , D , 1 , hs1);
- X hh(D , A , B , C , 9 , hs2);
- X hh(C , D , A , B , 5 , hs3);
- X hh(B , C , D , A , 13 , hs4);
- X hh(A , B , C , D , 3 , hs1);
- X hh(D , A , B , C , 11 , hs2);
- X hh(C , D , A , B , 7 , hs3);
- X hh(B , C , D , A , 15 , hs4);
- X MDp->buffer[0] += A;
- X MDp->buffer[1] += B;
- X MDp->buffer[2] += C;
- X MDp->buffer[3] += D;
- X
- X
- X
- XRivest [Page 12]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X }
- X
- X /* MDupdate(MDp,X,count)
- X ** Input: MDp -- an MDptr
- X ** X -- a pointer to an array of unsigned characters.
- X ** count -- the number of bits of X to use.
- X ** (if not a multiple of 8, uses high bits of last byte.)
- X ** Update MDp using the number of bits of X given by count.
- X ** This is the basic input routine for an MD4 user.
- X ** The routine completes 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. A call with count 0 will be ignored if the
- X ** MD has already been terminated (done != 0), so an extra call with
- X ** count 0 can be given as a "courtesy close" to force termination
- X ** if desired.
- X */
- X void
- X MDupdate(MDp,X,count)
- X MDptr MDp;
- X unsigned char *X;
- X unsigned int count;
- X { unsigned int i, tmp, bit, byte, mask;
- X unsigned char XX[64];
- X unsigned char *p;
- X /* return with no error if this is a courtesy close with count
- X ** zero and MDp->done is true.
- X */
- X if (count == 0 && MDp->done) return;
- X /* check to see if MD is already done and report error */
- X if (MDp->done)
- X { printf("\nError: MDupdate MD already done."); return; }
- X /* Add count to MDp->count */
- X tmp = count;
- X p = MDp->count;
- X while (tmp)
- X { tmp += *p;
- X *p++ = tmp;
- X tmp = tmp >> 8;
- X }
- X /* Process data */
- X if (count == 512)
- X { /* Full block of data to handle */
- X MDblock(MDp,(unsigned int *)X);
- X }
- X else if (count > 512) /* Check for count too large */
- X { printf("\nError: MDupdate called with illegal count value %d."
- X ,count);
- X return;
- X
- X
- X
- XRivest [Page 13]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X }
- X else /* partial block -- must be last block so finish up */
- X { /* Find out how many bytes and residual bits there are */
- X byte = count >> 3;
- X bit = count & 7;
- X /* Copy X into XX since we need to modify it */
- X for (i=0;i<=byte;i++) XX[i] = X[i];
- X for (i=byte+1;i<64;i++) XX[i] = 0;
- X /* Add padding '1' bit and low-order zeros in last byte */
- X mask = 1 << (7 - bit);
- X XX[byte] = (XX[byte] | mask) & ~( mask - 1);
- X /* If room for bit count, finish up with this block */
- X if (byte <= 55)
- X { for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
- X MDblock(MDp,(unsigned int *)XX);
- X }
- X else /* need to do two blocks to finish up */
- X { MDblock(MDp,(unsigned int *)XX);
- X for (i=0;i<56;i++) XX[i] = 0;
- X for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
- X MDblock(MDp,(unsigned int *)XX);
- X }
- X /* Set flag saying we're done with MD computation */
- X MDp->done = 1;
- X }
- X }
- X
- X /*
- X ** End of md4.c
- X ****************************(cut)***********************************/
- X
- 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 */
- X MDtimetrial()
- X
- X
- X
- XRivest [Page 14]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- 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 */
- X MDstring(s)
- X unsigned 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 */
- X MDfile(filename)
- X char *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
- X
- X
- XRivest [Page 15]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- 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 */
- X MDfilter()
- 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 */
- X MDtestsuite()
- 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
- X main(argc,argv)
- X int argc;
- X char *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
- X
- X
- XRivest [Page 16]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- 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 ****************************(cut)***********************************/
- X
- X
- X --------------------------------------------------------------------
- X --- Sample session. Compiling and using MD4 on SUN Sparcstation ---
- X --------------------------------------------------------------------
- X >ls
- X total 66
- X -rw-rw-r-- 1 rivest 3 Feb 14 17:40 abcfile
- X -rwxrwxr-x 1 rivest 24576 Feb 17 12:28 md4
- X -rw-rw-r-- 1 rivest 9347 Feb 17 00:37 md4.c
- X -rw-rw-r-- 1 rivest 25150 Feb 17 12:25 md4.doc
- X -rw-rw-r-- 1 rivest 1844 Feb 16 21:21 md4.h
- X -rw-rw-r-- 1 rivest 3497 Feb 17 12:27 md4driver.c
- X >
- X >cc -o md4 -O4 md4.c md4driver.c
- X md4.c:
- X md4driver.c:
- X Linking:
- X >
- X >md4 -x
- X MD4 test suite results:
- X 31d6cfe0d16ae931b73c59d7e0c089c0 ""
- X bde52cb31de33e46245e05fbdbd6fb24 "a"
- X a448017aaf21d8525fc10ae87aa6729d "abc"
- X d9130a8164549fe818874806e1c7014b "message digest"
- X d79e1c308aa5bbcdeea8ed63df412da9 "abcdefghijklmnopqrstuvwxyz"
- X 043f8582f241db351ce627e153e7f0e4
- X "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
- X a448017aaf21d8525fc10ae87aa6729d abcfile
- X >
- X >md4 -sabc -shi
- X a448017aaf21d8525fc10ae87aa6729d "abc"
- X cfaee2512bd25eb033236f0cd054e308 "hi"
- X >
- X >md4 *
- X a448017aaf21d8525fc10ae87aa6729d abcfile
- X
- X
- X
- XRivest [Page 17]
- X
- XRFC 1186 MD4 Message Digest Algorithm October 1990
- X
- X
- X d316f994da0e951cf9502928a1f73300 md4
- X 379adb39eada0dfdbbdfdcd0d9def8c4 md4.c
- X 9a3f73327c65954198b1f45a3aa12665 md4.doc
- X 37fe165ac177b461ff78b86d10e4ff33 md4.h
- X 7dcba2e2dc4d8f1408d08beb17dabb2a md4.o
- X 08790161bfddc6f5788b4353875cb1c3 md4driver.c
- X 1f84a7f690b0545d2d0480d5d3c26eea md4driver.o
- X >
- X >cat abcfile | md4
- X a448017aaf21d8525fc10ae87aa6729d
- X >
- X >md4 -t
- X MD4 time trial. Processing 1 million 64-character blocks...
- X 6325bf77e5891c7c0d8104b64cc6e9ef is digest of 64M byte test input.
- X Seconds to process test input: 44.0982
- X Characters processed per second: 1451305.
- X >
- X >
- X ------------------------ end of sample session --------------------
- X
- X Note: A version of this document including the C source code is
- X available for FTP from THEORY.LSC.MIT.EDU in the file "md4.doc".
- X
- XSecurity Considerations
- X
- X The level of security discussed in this memo by MD4 is considered to
- X be sufficient for implementing very high security hybrid digital
- X signature schemes based on MD4 and the RSA public-key cryptosystem.
- X
- XAuthor's Address
- X
- X Ronald L. Rivest
- X Massachusetts Institute of Technology
- X Laboratory for Computer Science
- X NE43-324
- X 545 Technology Square
- X Cambridge, MA 02139-1986
- X
- X Phone: (617) 253-5880
- X
- X EMail: rivest@theory.lcs.mit.edu
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- XRivest [Page 18]
- X
- END_OF_FILE
- if test 34579 -ne `wc -c <'rfc1186'`; then
- echo shar: \"'rfc1186'\" unpacked with wrong size!
- fi
- # end of 'rfc1186'
- fi
- echo shar: End of archive 1 \(of 2\).
- cp /dev/null ark1isdone
- 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.
-