diff options
author | Thomas Voss <mail@thomasvoss.com> | 2024-11-27 20:54:24 +0100 |
---|---|---|
committer | Thomas Voss <mail@thomasvoss.com> | 2024-11-27 20:54:24 +0100 |
commit | 4bfd864f10b68b71482b35c818559068ef8d5797 (patch) | |
tree | e3989f47a7994642eb325063d46e8f08ffa681dc /doc/rfc/rfc1186.txt | |
parent | ea76e11061bda059ae9f9ad130a9895cc85607db (diff) |
doc: Add RFC documents
Diffstat (limited to 'doc/rfc/rfc1186.txt')
-rw-r--r-- | doc/rfc/rfc1186.txt | 1011 |
1 files changed, 1011 insertions, 0 deletions
diff --git a/doc/rfc/rfc1186.txt b/doc/rfc/rfc1186.txt new file mode 100644 index 0000000..5c0d941 --- /dev/null +++ b/doc/rfc/rfc1186.txt @@ -0,0 +1,1011 @@ + + + + + + +Network Working Group R. Rivest +Request for Comments: 1186 MIT Laboratory for Computer Science + October 1990 + + + The MD4 Message Digest Algorithm + +Status of this Memo + + This RFC is the specification of the MD4 Digest Algorithm. If you + are going to implement MD4, it is suggested you do it this way. This + memo is for informational use and does not constitute a standard. + Distribution of this memo is unlimited. + +Table of Contents + + 1. Abstract .................................................... 1 + 2. Terminology and Notation .................................... 2 + 3. MD4 Algorithm Description ................................... 2 + 4. Extensions .................................................. 6 + 5. Summary ..................................................... 7 + 6. Acknowledgements ............................................ 7 + APPENDIX - Reference Implementation ............................. 7 + Security Considerations.......................................... 18 + Author's Address................................................. 18 + +1. Abstract + + This note describes the MD4 message digest algorithm. The algorithm + takes as input an input message of arbitrary length and produces as + output a 128-bit "fingerprint" or "message digest" of the input. It + is conjectured that it is computationally infeasible to produce two + messages having the same message digest, or to produce any message + having a given prespecified target message digest. The MD4 algorithm + is thus ideal for digital signature applications, where a large file + must be "compressed" in a secure manner before being signed with the + RSA public-key cryptosystem. + + The MD4 algorithm is designed to be quite fast on 32-bit machines. + On a SUN Sparc station, MD4 runs at 1,450,000 bytes/second. On a DEC + MicroVax II, MD4 runs at approximately 70,000 bytes/second. On a + 20MHz 80286, MD4 runs at approximately 32,000 bytes/second. In + addition, the MD4 algorithm does not require any large substitution + tables; the algorithm can be coded quite compactly. + + The MD4 algorithm is being placed in the public domain for review and + possible adoption as a standard. + + + + +Rivest [Page 1] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + (Note: The document supersedes an earlier draft. The algorithm + described here is a slight modification of the one described in the + draft.) + +2. Terminology and Notation + + In this note a "word" is a 32-bit quantity and a byte is an 8-bit + quantity. A sequence of bits can be interpreted in a natural manner + as a sequence of bytes, where each consecutive group of 8 bits is + interpreted as a byte with the high-order (most significant) bit of + each byte listed first. Similarly, a sequence of bytes can be + interpreted as a sequence of 32-bit words, where each consecutive + group of 4 bytes is interpreted as a word with the low-order (least + significant) byte given first. + + Let x_i denote "x sub i". If the subscript is an expression, we + surround it in braces, as in x_{i+1}. Similarly, we use ^ for + superscripts (exponentiation), so that x^i denotes x to the i-th + power. + + Let the symbol "+" denote addition of words (i.e., modulo- 2^32 + addition). Let X <<< s denote the 32-bit value obtained by circularly + shifting (rotating) X left by s bit positions. Let not(X) denote the + bit-wise complement of X, and let X v Y denote the bit-wise OR of X + and Y. Let X xor Y denote the bit-wise XOR of X and Y, and let XY + denote the bit-wise AND of X and Y. + +3. MD4 Algorithm Description + + We begin by supposing that we have a b-bit message as input, and that + we wish to find its message digest. Here b is an arbitrary + nonnegative integer; b may be zero, it need not be a multiple of 8, + and it may be arbitrarily large. We imagine the bits of the message + written down as follows: + + m_0 m_1 ... m_{b-1} . + + The following five steps are performed to compute the message digest + of the message. + + Step 1. Append padding bits + + The message is "padded" (extended) so that its length (in bits) + is congruent to 448, modulo 512. That is, the message is + extended so that it is just 64 bits shy of being a multiple of + 512 bits long. Padding is always performed, even if the length + of the message is already congruent to 448, modulo 512 (in + which case 512 bits of padding are added). + + + +Rivest [Page 2] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + Padding is performed as follows: a single "1" bit is appended + to the message, and then enough zero bits are appended so that + the length in bits of the padded message becomes congruent to + 448, modulo 512. + + Step 2. Append length + + A 64-bit representation of b (the length of the message before + the padding bits were added) is appended to the result of the + previous step. In the unlikely event that b is greater than + 2^64, then only the low-order 64 bits of b are used. (These + bits are appended as two 32-bit words and appended low-order + word first in accordance with the previous conventions.) + + At this point the resulting message (after padding with bits + and with b) has a length that is an exact multiple of 512 bits. + Equivalently, this message has a length that is an exact + multiple of 16 (32-bit) words. Let M[0 ... N-1] denote the + words of the resulting message, where N is a multiple of 16. + + Step 3. Initialize MD buffer + + A 4-word buffer (A,B,C,D) is used to compute the message + digest. Here each of A,B,C,D are 32-bit registers. These + registers are initialized to the following values in + hexadecimal, low-order bytes first): + + word A: 01 23 45 67 + word B: 89 ab cd ef + word C: fe dc ba 98 + word D: 76 54 32 10 + + Step 4. Process message in 16-word blocks + + We first define three auxiliary functions that each take + as input three 32-bit words and produce as output one + 32-bit word. + + f(X,Y,Z) = XY v not(X)Z + g(X,Y,Z) = XY v XZ v YZ + h(X,Y,Z) = X xor Y xor Z + + In each bit position f acts as a conditional: if x then y else + z. (The function f could have been defined using + instead of + v since XY and not(X)Z will never have 1's in the same bit + position.) In each bit position g acts as a majority function: + if at least two of x, y, z are on, then g has a one in that bit + position, else g has a zero. It is interesting to note that if + + + +Rivest [Page 3] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + the bits of X, Y, and Z are independent and unbiased, the each + bit of f(X,Y,Z) will be independent and unbiased, and similarly + each bit of g(X,Y,Z) will be independent and unbiased. The + function h is the bit-wise "xor" or "parity" function; it has + properties similar to those of f and g. + + Do the following: + + For i = 0 to N/16-1 do /* process each 16-word block */ + For j = 0 to 15 do: /* copy block i into X */ + Set X[j] to M[i*16+j]. + end /* of loop on j */ + Save A as AA, B as BB, C as CC, and D as DD. + + [Round 1] + Let [A B C D i s] denote the operation + A = (A + f(B,C,D) + X[i]) <<< s . + Do the following 16 operations: + [A B C D 0 3] + [D A B C 1 7] + [C D A B 2 11] + [B C D A 3 19] + [A B C D 4 3] + [D A B C 5 7] + [C D A B 6 11] + [B C D A 7 19] + [A B C D 8 3] + [D A B C 9 7] + [C D A B 10 11] + [B C D A 11 19] + [A B C D 12 3] + [D A B C 13 7] + [C D A B 14 11] + [B C D A 15 19] + + [Round 2] + Let [A B C D i s] denote the operation + A = (A + g(B,C,D) + X[i] + 5A827999) <<< s . + (The value 5A..99 is a hexadecimal 32-bit + constant, written with the high-order digit + first. This constant represents the square + root of 2. The octal value of this constant + is 013240474631. See Knuth, The Art of + Programming, Volume 2 (Seminumerical + Algorithms), Second Edition (1981), + Addison-Wesley. Table 2, page 660.) + Do the following 16 operations: + [A B C D 0 3] + + + +Rivest [Page 4] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + [D A B C 4 5] + [C D A B 8 9] + [B C D A 12 13] + [A B C D 1 3] + [D A B C 5 5] + [C D A B 9 9] + [B C D A 13 13] + [A B C D 2 3] + [D A B C 6 5] + [C D A B 10 9] + [B C D A 14 13] + [A B C D 3 3] + [D A B C 7 5] + [C D A B 11 9] + [B C D A 15 13] + + [Round 3] + Let [A B C D i s] denote the operation + A = (A + h(B,C,D) + X[i] + 6ED9EBA1) <<< s . + (The value 6E..A1 is a hexadecimal 32-bit + constant, written with the high-order digit + first. This constant represents the square + root of 3. The octal value of this constant + is 015666365641. See Knuth, The Art of + Programming, Volume 2 (Seminumerical + Algorithms), Second Edition (1981), + Addison-Wesley. Table 2, page 660.) + Do the following 16 operations: + [A B C D 0 3] + [D A B C 8 9] + [C D A B 4 11] + [B C D A 12 15] + [A B C D 2 3] + [D A B C 10 9] + [C D A B 6 11] + [B C D A 14 15] + [A B C D 1 3] + [D A B C 9 9] + [C D A B 5 11] + [B C D A 13 15] + [A B C D 3 3] + [D A B C 11 9] + [C D A B 7 11] + [B C D A 15 15] + + Then perform the following additions: + A = A + AA + B = B + BB + + + +Rivest [Page 5] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + C = C + CC + D = D + DD + (That is, each of the four registers is incremented by + the value it had before this block was started.) + + end /* of loop on i */ + + Step 5. Output + + The message digest produced as output is A,B,C,D. That is, we + begin with the low-order byte of A, and end with the high-order + byte of D. + + This completes the description of MD4. A reference + implementation in C is given in the Appendix. + +4. Extensions + + If more than 128 bits of output are required, then the following + procedure is recommended to obtain a 256-bit output. (There is no + provision made for obtaining more than 256 bits.) + + Two copies of MD4 are run in parallel over the input. The first copy + is standard as described above. The second copy is modified as + follows. + + The initial state of the second copy is: + word A: 00 11 22 33 + word B: 44 55 66 77 + word C: 88 99 aa bb + word D: cc dd ee ff + + The magic constants in rounds 2 and 3 for the second copy of MD4 are + changed from sqrt(2) and sqrt(3) to cuberoot(2) and cuberoot(3): + + Octal Hex + Round 2 constant 012050505746 50a28be6 + Round 3 constant 013423350444 5c4dd124 + + Finally, after every 16-word block is processed (including the last + block), the values of the A registers in the two copies are + exchanged. + + The final message digest is obtaining by appending the result of the + second copy of MD4 to the end of the result of the first copy of MD4. + + + + + + +Rivest [Page 6] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + +5. Summary + + The MD4 message digest algorithm is simple to implement, and provides + a "fingerprint" or message digest of a message of arbitrary length. + + It is conjectured that the difficulty of coming up with two messages + having the same message digest is on the order of 2^64 operations, + and that the difficulty of coming up with any message having a given + message digest is on the order of 2^128 operations. The MD4 + algorithm has been carefully scrutinized for weaknesses. It is, + however, a relatively new algorithm and further security analysis is + of course justified, as is the case with any new proposal of this + sort. The level of security provided by MD4 should be sufficient for + implementing very high security hybrid digital signature schemes + based on MD4 and the RSA public-key cryptosystem. + +6. Acknowledgements + + I'd like to thank Don Coppersmith, Burt Kaliski, Ralph Merkle, and + Noam Nisan for numerous helpful comments and suggestions. + +APPENDIX - Reference Implementation + +This appendix contains the following files: + + md4.h -- header file for using MD4 implementation + md4.c -- the source code for MD4 routines + md4driver.c -- a sample "user" routine + session -- sample results of running md4driver + + /* + ** ******************************************************************** + ** md4.h -- Header file for implementation of ** + ** MD4 Message Digest Algorithm ** + ** Updated: 2/13/90 by Ronald L. Rivest ** + ** (C) 1990 RSA Data Security, Inc. ** + ** ******************************************************************** + */ + + /* MDstruct is the data structure for a message digest computation. + */ + typedef struct { + unsigned int buffer[4]; /* Holds 4-word result of MD computation */ + unsigned char count[8]; /* Number of bits processed so far */ + unsigned int done; /* Nonzero means MD computation finished */ + } MDstruct, *MDptr; + + /* MDbegin(MD) + + + +Rivest [Page 7] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + ** Input: MD -- an MDptr + ** Initialize the MDstruct prepatory to doing a message digest + ** computation. + */ + extern void MDbegin(); + + /* MDupdate(MD,X,count) + ** Input: MD -- an MDptr + ** X -- a pointer to an array of unsigned characters. + ** count -- the number of bits of X to use (an unsigned int). + ** Updates MD using the first "count" bits of X. + ** The array pointed to by X is not modified. + ** If count is not a multiple of 8, MDupdate uses high bits of + ** last byte. + ** This is the basic input routine for a user. + ** The routine terminates the MD computation when count < 512, so + ** every MD computation should end with one call to MDupdate with a + ** count less than 512. Zero is OK for a count. + */ + extern void MDupdate(); + + /* MDprint(MD) + ** Input: MD -- an MDptr + ** Prints message digest buffer MD as 32 hexadecimal digits. + ** Order is from low-order byte of buffer[0] to high-order byte + ** of buffer[3]. + ** Each byte is printed with high-order hexadecimal digit first. + */ + extern void MDprint(); + + /* + ** End of md4.h + ****************************(cut)***********************************/ + + /* + ** ******************************************************************** + ** md4.c -- Implementation of MD4 Message Digest Algorithm ** + ** Updated: 2/16/90 by Ronald L. Rivest ** + ** (C) 1990 RSA Data Security, Inc. ** + ** ******************************************************************** + */ + + /* + ** To use MD4: + ** -- Include md4.h in your program + ** -- Declare an MDstruct MD to hold the state of the digest + ** computation. + ** -- Initialize MD using MDbegin(&MD) + + + +Rivest [Page 8] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + ** -- For each full block (64 bytes) X you wish to process, call + ** MDupdate(&MD,X,512) + ** (512 is the number of bits in a full block.) + ** -- For the last block (less than 64 bytes) you wish to process, + ** MDupdate(&MD,X,n) + ** where n is the number of bits in the partial block. A partial + ** block terminates the computation, so every MD computation + ** should terminate by processing a partial block, even if it + ** has n = 0. + ** -- The message digest is available in MD.buffer[0] ... + ** MD.buffer[3]. (Least-significant byte of each word + ** should be output first.) + ** -- You can print out the digest using MDprint(&MD) + */ + + /* Implementation notes: + ** This implementation assumes that ints are 32-bit quantities. + ** If the machine stores the least-significant byte of an int in the + ** least-addressed byte (e.g., VAX and 8086), then LOWBYTEFIRST + ** should be set to TRUE. Otherwise (e.g., SUNS), LOWBYTEFIRST + ** should be set to FALSE. Note that on machines with LOWBYTEFIRST + ** FALSE the routine MDupdate modifies has a side-effect on its input + ** array (the order of bytes in each word are reversed). If this is + ** undesired a call to MDreverse(X) can reverse the bytes of X back + ** into order after each call to MDupdate. + + */ + #define TRUE 1 + #define FALSE 0 + #define LOWBYTEFIRST FALSE + + /* Compile-time includes + */ + #include <stdio.h> + #include "md4.h" + + /* Compile-time declarations of MD4 "magic constants". + */ + #define I0 0x67452301 /* Initial values for MD buffer */ + #define I1 0xefcdab89 + #define I2 0x98badcfe + #define I3 0x10325476 + #define C2 013240474631 /* round 2 constant = sqrt(2) in octal */ + #define C3 015666365641 /* round 3 constant = sqrt(3) in octal */ + /* C2 and C3 are from Knuth, The Art of Programming, Volume 2 + ** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley. + ** Table 2, page 660. + */ + + + +Rivest [Page 9] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + #define fs1 3 /* round 1 shift amounts */ + #define fs2 7 + #define fs3 11 + #define fs4 19 + #define gs1 3 /* round 2 shift amounts */ + #define gs2 5 + #define gs3 9 + #define gs4 13 + #define hs1 3 /* round 3 shift amounts */ + #define hs2 9 + #define hs3 11 + #define hs4 15 + + /* Compile-time macro declarations for MD4. + ** Note: The "rot" operator uses the variable "tmp". + ** It assumes tmp is declared as unsigned int, so that the >> + ** operator will shift in zeros rather than extending the sign bit. + */ + #define f(X,Y,Z) ((X&Y) | ((~X)&Z)) + #define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z)) + #define h(X,Y,Z) (X^Y^Z) + #define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S))) + #define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s) + #define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s) + #define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s) + + /* MDprint(MDp) + ** Print message digest buffer MDp as 32 hexadecimal digits. + ** Order is from low-order byte of buffer[0] to high-order byte of + ** buffer[3]. + ** Each byte is printed with high-order hexadecimal digit first. + ** This is a user-callable routine. + */ + void + MDprint(MDp) + MDptr MDp; + { int i,j; + for (i=0;i<4;i++) + for (j=0;j<32;j=j+8) + printf("%02x",(MDp->buffer[i]>>j) & 0xFF); + } + + /* MDbegin(MDp) + ** Initialize message digest buffer MDp. + ** This is a user-callable routine. + */ + void + MDbegin(MDp) + + + +Rivest [Page 10] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + MDptr MDp; + { int i; + MDp->buffer[0] = I0; + MDp->buffer[1] = I1; + MDp->buffer[2] = I2; + MDp->buffer[3] = I3; + for (i=0;i<8;i++) MDp->count[i] = 0; + MDp->done = 0; + } + + /* MDreverse(X) + ** Reverse the byte-ordering of every int in X. + ** Assumes X is an array of 16 ints. + ** The macro revx reverses the byte-ordering of the next word of X. + */ + #define revx { t = (*X << 16) | (*X >> 16); \ + *X++ = ((t & 0xFF00FF00) >> 8) | ((t & 0x00FF00FF) << 8); } + MDreverse(X) + unsigned int *X; + { register unsigned int t; + revx; revx; revx; revx; revx; revx; revx; revx; + revx; revx; revx; revx; revx; revx; revx; revx; + } + + /* MDblock(MDp,X) + ** Update message digest buffer MDp->buffer using 16-word data block X. + ** Assumes all 16 words of X are full of data. + ** Does not update MDp->count. + ** This routine is not user-callable. + */ + static void + MDblock(MDp,X) + MDptr MDp; + unsigned int *X; + { + register unsigned int tmp, A, B, C, D; + #if LOWBYTEFIRST == FALSE + MDreverse(X); + #endif + A = MDp->buffer[0]; + B = MDp->buffer[1]; + C = MDp->buffer[2]; + D = MDp->buffer[3]; + /* Update the message digest buffer */ + ff(A , B , C , D , 0 , fs1); /* Round 1 */ + ff(D , A , B , C , 1 , fs2); + ff(C , D , A , B , 2 , fs3); + ff(B , C , D , A , 3 , fs4); + + + +Rivest [Page 11] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + ff(A , B , C , D , 4 , fs1); + ff(D , A , B , C , 5 , fs2); + ff(C , D , A , B , 6 , fs3); + ff(B , C , D , A , 7 , fs4); + ff(A , B , C , D , 8 , fs1); + ff(D , A , B , C , 9 , fs2); + ff(C , D , A , B , 10 , fs3); + ff(B , C , D , A , 11 , fs4); + ff(A , B , C , D , 12 , fs1); + ff(D , A , B , C , 13 , fs2); + ff(C , D , A , B , 14 , fs3); + ff(B , C , D , A , 15 , fs4); + gg(A , B , C , D , 0 , gs1); /* Round 2 */ + gg(D , A , B , C , 4 , gs2); + gg(C , D , A , B , 8 , gs3); + gg(B , C , D , A , 12 , gs4); + gg(A , B , C , D , 1 , gs1); + gg(D , A , B , C , 5 , gs2); + gg(C , D , A , B , 9 , gs3); + gg(B , C , D , A , 13 , gs4); + gg(A , B , C , D , 2 , gs1); + gg(D , A , B , C , 6 , gs2); + gg(C , D , A , B , 10 , gs3); + gg(B , C , D , A , 14 , gs4); + gg(A , B , C , D , 3 , gs1); + gg(D , A , B , C , 7 , gs2); + gg(C , D , A , B , 11 , gs3); + gg(B , C , D , A , 15 , gs4); + hh(A , B , C , D , 0 , hs1); /* Round 3 */ + hh(D , A , B , C , 8 , hs2); + hh(C , D , A , B , 4 , hs3); + hh(B , C , D , A , 12 , hs4); + hh(A , B , C , D , 2 , hs1); + hh(D , A , B , C , 10 , hs2); + hh(C , D , A , B , 6 , hs3); + hh(B , C , D , A , 14 , hs4); + hh(A , B , C , D , 1 , hs1); + hh(D , A , B , C , 9 , hs2); + hh(C , D , A , B , 5 , hs3); + hh(B , C , D , A , 13 , hs4); + hh(A , B , C , D , 3 , hs1); + hh(D , A , B , C , 11 , hs2); + hh(C , D , A , B , 7 , hs3); + hh(B , C , D , A , 15 , hs4); + MDp->buffer[0] += A; + MDp->buffer[1] += B; + MDp->buffer[2] += C; + MDp->buffer[3] += D; + + + +Rivest [Page 12] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + } + + /* MDupdate(MDp,X,count) + ** Input: MDp -- an MDptr + ** X -- a pointer to an array of unsigned characters. + ** count -- the number of bits of X to use. + ** (if not a multiple of 8, uses high bits of last byte.) + ** Update MDp using the number of bits of X given by count. + ** This is the basic input routine for an MD4 user. + ** The routine completes the MD computation when count < 512, so + ** every MD computation should end with one call to MDupdate with a + ** count less than 512. A call with count 0 will be ignored if the + ** MD has already been terminated (done != 0), so an extra call with + ** count 0 can be given as a "courtesy close" to force termination + ** if desired. + */ + void + MDupdate(MDp,X,count) + MDptr MDp; + unsigned char *X; + unsigned int count; + { unsigned int i, tmp, bit, byte, mask; + unsigned char XX[64]; + unsigned char *p; + /* return with no error if this is a courtesy close with count + ** zero and MDp->done is true. + */ + if (count == 0 && MDp->done) return; + /* check to see if MD is already done and report error */ + if (MDp->done) + { printf("\nError: MDupdate MD already done."); return; } + /* Add count to MDp->count */ + tmp = count; + p = MDp->count; + while (tmp) + { tmp += *p; + *p++ = tmp; + tmp = tmp >> 8; + } + /* Process data */ + if (count == 512) + { /* Full block of data to handle */ + MDblock(MDp,(unsigned int *)X); + } + else if (count > 512) /* Check for count too large */ + { printf("\nError: MDupdate called with illegal count value %d." + ,count); + return; + + + +Rivest [Page 13] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + } + else /* partial block -- must be last block so finish up */ + { /* Find out how many bytes and residual bits there are */ + byte = count >> 3; + bit = count & 7; + /* Copy X into XX since we need to modify it */ + for (i=0;i<=byte;i++) XX[i] = X[i]; + for (i=byte+1;i<64;i++) XX[i] = 0; + /* Add padding '1' bit and low-order zeros in last byte */ + mask = 1 << (7 - bit); + XX[byte] = (XX[byte] | mask) & ~( mask - 1); + /* If room for bit count, finish up with this block */ + if (byte <= 55) + { for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; + MDblock(MDp,(unsigned int *)XX); + } + else /* need to do two blocks to finish up */ + { MDblock(MDp,(unsigned int *)XX); + for (i=0;i<56;i++) XX[i] = 0; + for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; + MDblock(MDp,(unsigned int *)XX); + } + /* Set flag saying we're done with MD computation */ + MDp->done = 1; + } + } + + /* + ** End of md4.c + ****************************(cut)***********************************/ + + /* + ** ******************************************************************** + ** md4driver.c -- sample routines to test ** + ** MD4 message digest algorithm. ** + ** Updated: 2/16/90 by Ronald L. Rivest ** + ** (C) 1990 RSA Data Security, Inc. ** + ** ******************************************************************** + */ + + #include <stdio.h> + #include "md4.h" + + /* MDtimetrial() + ** A time trial routine, to measure the speed of MD4. + ** Measures speed for 1M blocks = 64M bytes. + */ + MDtimetrial() + + + +Rivest [Page 14] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + { unsigned int X[16]; + MDstruct MD; + int i; + double t; + for (i=0;i<16;i++) X[i] = 0x01234567 + i; + printf + ("MD4 time trial. Processing 1 million 64-character blocks...\n"); + clock(); + MDbegin(&MD); + for (i=0;i<1000000;i++) MDupdate(&MD,X,512); + MDupdate(&MD,X,0); + t = (double) clock(); /* in microseconds */ + MDprint(&MD); printf(" is digest of 64M byte test input.\n"); + printf("Seconds to process test input: %g\n,t/1e6); + printf("Characters processed per second: %ld.\n,(int)(64e12/t)); + } + + /* MDstring(s) + ** Computes the message digest for string s. + ** Prints out message digest, a space, the string (in quotes) and a + ** carriage return. + */ + MDstring(s) + unsigned char *s; + { unsigned int i, len = strlen(s); + MDstruct MD; + MDbegin(&MD); + for (i=0;i+64<=len;i=i+64) MDupdate(&MD,s+i,512); + MDupdate(&MD,s+i,(len-i)*8); + MDprint(&MD); + printf(" \"%s\"\n",s); + } + + /* MDfile(filename) + ** Computes the message digest for a specified file. + ** Prints out message digest, a space, the file name, and a + ** carriage return. + */ + MDfile(filename) + char *filename; + { FILE *f = fopen(filename,"rb"); + unsigned char X[64]; + MDstruct MD; + int b; + if (f == NULL) + { printf("%s can't be opened.\n",filename); return; } + MDbegin(&MD); + while ((b=fread(X,1,64,f))!=0) MDupdate(&MD,X,b*8); + + + +Rivest [Page 15] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + MDupdate(&MD,X,0); + MDprint(&MD); + printf(" %s\n",filename); + fclose(f); + } + + /* MDfilter() + ** Writes the message digest of the data from stdin onto stdout, + ** followed by a carriage return. + */ + MDfilter() + { unsigned char X[64]; + MDstruct MD; + int b; + MDbegin(&MD); + while ((b=fread(X,1,64,stdin))!=0) MDupdate(&MD,X,b*8); + MDupdate(&MD,X,0); + MDprint(&MD); + printf("\n"); + } + + /* MDtestsuite() + ** Run a standard suite of test data. + */ + MDtestsuite() + { + printf("MD4 test suite results:\n"); + MDstring(""); + MDstring("a"); + MDstring("abc"); + MDstring("message digest"); + MDstring("abcdefghijklmnopqrstuvwxyz"); + MDstring + ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + MDfile("foo"); /* Contents of file foo are "abc" */ + } + + main(argc,argv) + int argc; + char *argv[]; + { int i; + /* For each command line argument in turn: + ** filename -- prints message digest and name of file + ** -sstring -- prints message digest and contents of string + ** -t -- prints time trial statistics for 64M bytes + ** -x -- execute a standard suite of test data + ** (no args) -- writes messages digest of stdin onto stdout + */ + + + +Rivest [Page 16] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + if (argc==1) MDfilter(); + else + for (i=1;i<argc;i++) + if (argv[i][0]=='-' && argv[i][1]=='s') MDstring(argv[i]+2); + else if (strcmp(argv[i],"-t")==0) MDtimetrial(); + else if (strcmp(argv[i],"-x")==0) MDtestsuite(); + else MDfile(argv[i]); + } + + /* + ** end of md4driver.c + ****************************(cut)***********************************/ + + + -------------------------------------------------------------------- + --- Sample session. Compiling and using MD4 on SUN Sparcstation --- + -------------------------------------------------------------------- + >ls + total 66 + -rw-rw-r-- 1 rivest 3 Feb 14 17:40 abcfile + -rwxrwxr-x 1 rivest 24576 Feb 17 12:28 md4 + -rw-rw-r-- 1 rivest 9347 Feb 17 00:37 md4.c + -rw-rw-r-- 1 rivest 25150 Feb 17 12:25 md4.doc + -rw-rw-r-- 1 rivest 1844 Feb 16 21:21 md4.h + -rw-rw-r-- 1 rivest 3497 Feb 17 12:27 md4driver.c + > + >cc -o md4 -O4 md4.c md4driver.c + md4.c: + md4driver.c: + Linking: + > + >md4 -x + MD4 test suite results: + 31d6cfe0d16ae931b73c59d7e0c089c0 "" + bde52cb31de33e46245e05fbdbd6fb24 "a" + a448017aaf21d8525fc10ae87aa6729d "abc" + d9130a8164549fe818874806e1c7014b "message digest" + d79e1c308aa5bbcdeea8ed63df412da9 "abcdefghijklmnopqrstuvwxyz" + 043f8582f241db351ce627e153e7f0e4 + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + a448017aaf21d8525fc10ae87aa6729d abcfile + > + >md4 -sabc -shi + a448017aaf21d8525fc10ae87aa6729d "abc" + cfaee2512bd25eb033236f0cd054e308 "hi" + > + >md4 * + a448017aaf21d8525fc10ae87aa6729d abcfile + + + +Rivest [Page 17] + +RFC 1186 MD4 Message Digest Algorithm October 1990 + + + d316f994da0e951cf9502928a1f73300 md4 + 379adb39eada0dfdbbdfdcd0d9def8c4 md4.c + 9a3f73327c65954198b1f45a3aa12665 md4.doc + 37fe165ac177b461ff78b86d10e4ff33 md4.h + 7dcba2e2dc4d8f1408d08beb17dabb2a md4.o + 08790161bfddc6f5788b4353875cb1c3 md4driver.c + 1f84a7f690b0545d2d0480d5d3c26eea md4driver.o + > + >cat abcfile | md4 + a448017aaf21d8525fc10ae87aa6729d + > + >md4 -t + MD4 time trial. Processing 1 million 64-character blocks... + 6325bf77e5891c7c0d8104b64cc6e9ef is digest of 64M byte test input. + Seconds to process test input: 44.0982 + Characters processed per second: 1451305. + > + > + ------------------------ end of sample session -------------------- + + Note: A version of this document including the C source code is + available for FTP from THEORY.LSC.MIT.EDU in the file "md4.doc". + +Security Considerations + + The level of security discussed in this memo by MD4 is considered to + be sufficient for implementing very high security hybrid digital + signature schemes based on MD4 and the RSA public-key cryptosystem. + +Author's Address + + Ronald L. Rivest + Massachusetts Institute of Technology + Laboratory for Computer Science + NE43-324 + 545 Technology Square + Cambridge, MA 02139-1986 + + Phone: (617) 253-5880 + + EMail: rivest@theory.lcs.mit.edu + + + + + + + + + + +Rivest [Page 18] +
\ No newline at end of file |