updated code from RFC
authorJohn Kohl <jtkohl@mit.edu>
Tue, 26 Feb 1991 13:31:30 +0000 (13:31 +0000)
committerJohn Kohl <jtkohl@mit.edu>
Tue, 26 Feb 1991 13:31:30 +0000 (13:31 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@1782 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/crypto/md4/md4.c

index 038f2d52f31ef99a3c445d229d87bb6789a7121a..feed466c4f572269cdd19fe8455a8bd63a6f5bb3 100644 (file)
 /*
- *     $Source$
- *     $Author$
- *     $Id$
+ **********************************************************************
+ ** md4.c                                                            **
+ ** RSA Data Security, Inc. MD4 Message Digest Algorithm             **
+ ** Created: 2/17/90 RLR                                             **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version                  **
+ **********************************************************************
  */
 
 /*
- * md4.c from RFC1186
- *
- * $Log$
- * Revision 5.2  1991/01/17 11:39:34  jtkohl
- * fix problem with referencing past end of array on byte-aligned
- * input
- *
- * Revision 5.1  90/11/08  11:32:24  jtkohl
- * change to copy onto stack to avoid modifying input in MDupdate
- * add Kerberos byte-order detection
- * some compilers will require the "L" qualifier on long constants.
- * 
- * Revision 5.0  90/11/07  14:12:04  jtkohl
- * Initial code from RFC
- * 
+ **********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ **                                                                  **
+ ** License to copy and use this software is granted provided that   **
+ ** it is identified as the "RSA Data Security, Inc. MD4 Message     **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function.                                       **
+ **                                                                  **
+ ** License is also granted to make and use derivative works         **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD4 Message Digest Algorithm" in all         **
+ ** material mentioning or referencing the derived work.             **
+ **                                                                  **
+ ** RSA Data Security, Inc. makes no representations concerning      **
+ ** either the merchantability of this software or the suitability   **
+ ** of this software for any particular purpose.  It is provided "as **
+ ** is" without express or implied warranty of any kind.             **
+ **                                                                  **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software.                                   **
+ **********************************************************************
  */
 
-/*
-** ********************************************************************
-** md4.c -- Implementation of MD4 Message Digest Algorithm           **
-** Updated: 2/16/90 by Ronald L. Rivest                              **
-** (C) 1990 RSA Data Security, Inc.                                  **
-** ********************************************************************
-*/
+#include "md4.h"
 
-/*
-** To use MD4:
-**   -- Include md4.h in your program
-**   -- Declare an MDstruct MD to hold the state of the digest
-**          computation.
-**   -- Initialize MD using MDbegin(&MD)
-**   -- For each full block (64 bytes) X you wish to process, call
-**          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)
-*/
+/* forward declaration */
+static void Transform ();
 
-/* 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.
-*/
-#define TRUE  1
-#define FALSE 0
-#ifdef LSBFIRST
-#define LOWBYTEFIRST TRUE
-#endif
-#ifdef MSBFIRST
-#define LOWBYTEFIRST FALSE
-#endif
-#ifndef LOWBYTEFIRST
- error: you must define MSBFIRST or LSBFIRST;
-#endif
+static unsigned char PADDING[64] = {
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
 
-/* Compile-time includes
-*/
-#include <stdio.h>
-#include <krb5/krb5.h>
-#include <krb5/rsa-md4.h>
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#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))
 
-/* Compile-time declarations of MD4 "magic constants".
-*/
-#define I0  0x67452301L       /* Initial values for MD buffer */
-#define I1  0xefcdab89L
-#define I2  0x98badcfeL
-#define I3  0x10325476L
-#define C2  013240474631L     /* round 2 constant = sqrt(2) in octal */
-#define C3  015666365641L     /* 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.
-*/
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
 
-#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
+/* FF, GG and HH are MD4 transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) \
+  {(a) += F ((b), (c), (d)) + (x); \
+   (a) = ROTATE_LEFT ((a), (s));}
+#define GG(a, b, c, d, x, s) \
+  {(a) += G ((b), (c), (d)) + (x) + (UINT4)013240474631; \
+   (a) = ROTATE_LEFT ((a), (s));}
+#define HH(a, b, c, d, x, s) \
+  {(a) += H ((b), (c), (d)) + (x) + (UINT4)015666365641; \
+   (a) = ROTATE_LEFT ((a), (s));}
 
-/* 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)
+void MD4Init (mdContext)
+MD4_CTX *mdContext;
+{
+  mdContext->i[0] = mdContext->i[1] = (UINT4)0;
 
-/* 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);
+  /* Load magic initialization constants.
+   */
+  mdContext->buf[0] = (UINT4)0x67452301;
+  mdContext->buf[1] = (UINT4)0xefcdab89;
+  mdContext->buf[2] = (UINT4)0x98badcfe;
+  mdContext->buf[3] = (UINT4)0x10325476;
 }
 
-/* MDbegin(MDp)
-** Initialize message digest buffer MDp.
-** This is a user-callable routine.
-*/
-void
-MDbegin(MDp)
-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;
-}
+void MD4Update (mdContext, inBuf, inLen)
+MD4_CTX *mdContext;
+unsigned char *inBuf;
+unsigned int inLen;
+{
+  UINT4 in[16];
+  int mdi;
+  unsigned int i, ii;
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* update number of bits */
+  if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+    mdContext->i[1]++;
+  mdContext->i[0] += ((UINT4)inLen << 3);
+  mdContext->i[1] += ((UINT4)inLen >> 29);
 
-/* 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 & 0xFF00FF00L) >> 8) | ((t & 0x00FF00FFL) << 8); }
-void
-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;
+  while (inLen--) {
+    /* add new character to buffer, increment mdi */
+    mdContext->in[mdi++] = *inBuf++;
+
+    /* transform if necessary */
+    if (mdi == 0x40) {
+      for (i = 0, ii = 0; i < 16; i++, ii += 4)
+        in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+                (((UINT4)mdContext->in[ii+2]) << 16) |
+                (((UINT4)mdContext->in[ii+1]) << 8) |
+                ((UINT4)mdContext->in[ii]);
+      Transform (mdContext->buf, in);
+      mdi = 0;
+    }
+  }
 }
 
-/* MDblock(MDp,X)
-** Update message digest buffer MDp->buffer using 16-word data block X.
-** Assumes all 16 words of X are full of data.
-** Does not update MDp->count.
-** This routine is not user-callable.
-*/
-static void
-MDblock(MDp,X)
-MDptr MDp;
-unsigned int *X;
+void MD4Final (mdContext)
+MD4_CTX *mdContext;
 {
-  register unsigned int tmp, A, B, C, D;
-#if LOWBYTEFIRST == FALSE
-  unsigned int Xtmp[16];
-  memcpy(Xtmp, X, sizeof(Xtmp));
-  X = Xtmp;
-  MDreverse(X);
-#endif
+  UINT4 in[16];
+  int mdi;
+  unsigned int i, ii;
+  unsigned int padLen;
+
+  /* save number of bits */
+  in[14] = mdContext->i[0];
+  in[15] = mdContext->i[1];
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* pad out to 56 mod 64 */
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+  MD4Update (mdContext, PADDING, padLen);
+
+  /* append length in bits and transform */
+  for (i = 0, ii = 0; i < 14; i++, ii += 4)
+    in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+            (((UINT4)mdContext->in[ii+2]) << 16) |
+            (((UINT4)mdContext->in[ii+1]) << 8) |
+            ((UINT4)mdContext->in[ii]);
+  Transform (mdContext->buf, in);
 
-  A = MDp->buffer[0];
-  B = MDp->buffer[1];
-  C = MDp->buffer[2];
-  D = MDp->buffer[3];
-  /* Update the message digest buffer */
-  ff(A , B , C , D ,  0 , fs1); /* Round 1 */
-  ff(D , A , B , C ,  1 , fs2);
-  ff(C , D , A , B ,  2 , fs3);
-  ff(B , C , D , A ,  3 , fs4);
-  ff(A , B , C , D ,  4 , fs1);
-  ff(D , A , B , C ,  5 , fs2);
-  ff(C , D , A , B ,  6 , fs3);
-  ff(B , C , D , A ,  7 , fs4);
-  ff(A , B , C , D ,  8 , fs1);
-  ff(D , A , B , C ,  9 , fs2);
-  ff(C , D , A , B , 10 , fs3);
-  ff(B , C , D , A , 11 , fs4);
-  ff(A , B , C , D , 12 , fs1);
-  ff(D , A , B , C , 13 , fs2);
-  ff(C , D , A , B , 14 , fs3);
-  ff(B , C , D , A , 15 , fs4);
-  gg(A , B , C , D ,  0 , gs1); /* Round 2 */
-  gg(D , A , B , C ,  4 , gs2);
-  gg(C , D , A , B ,  8 , gs3);
-  gg(B , C , D , A , 12 , gs4);
-  gg(A , B , C , D ,  1 , gs1);
-  gg(D , A , B , C ,  5 , gs2);
-  gg(C , D , A , B ,  9 , gs3);
-  gg(B , C , D , A , 13 , gs4);
-  gg(A , B , C , D ,  2 , gs1);
-  gg(D , A , B , C ,  6 , gs2);
-  gg(C , D , A , B , 10 , gs3);
-  gg(B , C , D , A , 14 , gs4);
-  gg(A , B , C , D ,  3 , gs1);
-  gg(D , A , B , C ,  7 , gs2);
-  gg(C , D , A , B , 11 , gs3);
-  gg(B , C , D , A , 15 , gs4);
-  hh(A , B , C , D ,  0 , hs1); /* Round 3 */
-  hh(D , A , B , C ,  8 , hs2);
-  hh(C , D , A , B ,  4 , hs3);
-  hh(B , C , D , A , 12 , hs4);
-  hh(A , B , C , D ,  2 , hs1);
-  hh(D , A , B , C , 10 , hs2);
-  hh(C , D , A , B ,  6 , hs3);
-  hh(B , C , D , A , 14 , hs4);
-  hh(A , B , C , D ,  1 , hs1);
-  hh(D , A , B , C ,  9 , hs2);
-  hh(C , D , A , B ,  5 , hs3);
-  hh(B , C , D , A , 13 , hs4);
-  hh(A , B , C , D ,  3 , hs1);
-  hh(D , A , B , C , 11 , hs2);
-  hh(C , D , A , B ,  7 , hs3);
-  hh(B , C , D , A , 15 , hs4);
-  MDp->buffer[0] += A;
-  MDp->buffer[1] += B;
-  MDp->buffer[2] += C;
-  MDp->buffer[3] += D;
+
+  /* store buffer in digest */
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+    mdContext->digest[ii+1] =
+      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+    mdContext->digest[ii+2] =
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+    mdContext->digest[ii+3] =
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+  }
 }
 
-/* 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++ = (unsigned char) 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;
-    }
-  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];
-      if (bit)
-         XX[byte] = X[byte];
-      else
-         XX[byte] = 0;
-      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;
-    }
+/* Basic MD4 step. Transform buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+  UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+  /* Round 1 */
+  FF (a, b, c, d, in[ 0],  3);
+  FF (d, a, b, c, in[ 1],  7);
+  FF (c, d, a, b, in[ 2], 11);
+  FF (b, c, d, a, in[ 3], 19);
+  FF (a, b, c, d, in[ 4],  3);
+  FF (d, a, b, c, in[ 5],  7);
+  FF (c, d, a, b, in[ 6], 11);
+  FF (b, c, d, a, in[ 7], 19);
+  FF (a, b, c, d, in[ 8],  3);
+  FF (d, a, b, c, in[ 9],  7);
+  FF (c, d, a, b, in[10], 11);
+  FF (b, c, d, a, in[11], 19);
+  FF (a, b, c, d, in[12],  3);
+  FF (d, a, b, c, in[13],  7);
+  FF (c, d, a, b, in[14], 11);
+  FF (b, c, d, a, in[15], 19);
+
+  /* Round 2 */
+  GG (a, b, c, d, in[ 0],  3);
+  GG (d, a, b, c, in[ 4],  5);
+  GG (c, d, a, b, in[ 8],  9);
+  GG (b, c, d, a, in[12], 13);
+  GG (a, b, c, d, in[ 1],  3);
+  GG (d, a, b, c, in[ 5],  5);
+  GG (c, d, a, b, in[ 9],  9);
+  GG (b, c, d, a, in[13], 13);
+  GG (a, b, c, d, in[ 2],  3);
+  GG (d, a, b, c, in[ 6],  5);
+  GG (c, d, a, b, in[10],  9);
+  GG (b, c, d, a, in[14], 13);
+  GG (a, b, c, d, in[ 3],  3);
+  GG (d, a, b, c, in[ 7],  5);
+  GG (c, d, a, b, in[11],  9);
+  GG (b, c, d, a, in[15], 13);
+
+  /* Round 3 */
+  HH (a, b, c, d, in[ 0],  3);
+  HH (d, a, b, c, in[ 8],  9);
+  HH (c, d, a, b, in[ 4], 11);
+  HH (b, c, d, a, in[12], 15);
+  HH (a, b, c, d, in[ 2],  3);
+  HH (d, a, b, c, in[10],  9);
+  HH (c, d, a, b, in[ 6], 11);
+  HH (b, c, d, a, in[14], 15);
+  HH (a, b, c, d, in[ 1],  3);
+  HH (d, a, b, c, in[ 9],  9);
+  HH (c, d, a, b, in[ 5], 11);
+  HH (b, c, d, a, in[13], 15);
+  HH (a, b, c, d, in[ 3],  3);
+  HH (d, a, b, c, in[11],  9);
+  HH (c, d, a, b, in[ 7], 11);
+  HH (b, c, d, a, in[15], 15);
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
 }
 
 /*
-** End of md4.c
-*/
+ **********************************************************************
+ ** End of md4.c                                                     **
+ ******************************* (cut) ********************************
+ */