md4transform.cpp

Go to the documentation of this file.
00001 /**
00002  * Copyright (C) 1990-1992, RSA Data Security, Inc. All rights reserved.
00003  *
00004  * License to copy and use this software is granted provided that it
00005  * is identified as the "RSA Data Security, Inc. MD4 Message-Digest
00006  * Algorithm" in all material mentioning or referencing this software
00007  * or this function.
00008  *
00009  * License is also granted to make and use derivative works provided
00010  * that such works are identified as "derived from the RSA Data
00011  * Security, Inc. MD4 Message-Digest Algorithm" in all material
00012  * mentioning or referencing the derived work.
00013  *
00014  * RSA Data Security, Inc. makes no representations concerning either
00015  * the merchantability of this software or the suitability of this
00016  * software for any particular purpose. It is provided "as is"
00017  * without express or implied warranty of any kind.
00018  *
00019  * These notices must be retained in any copies of any part of this
00020  * documentation and/or software.
00021  */
00022 
00023 /** \file md4transform.cpp Implementation of MD4 Checksumming Algorithm */
00024 
00025 #include <hn/hnprec.h>
00026 #include <hn/md4transform.h>
00027 
00028 static void Decode(uint32_t * output, const uint8_t * input, size_t len) {
00029         unsigned int i,j;
00030 
00031         for (i=j=0; j<len; ++i,j+=4)
00032                 output[i]=
00033                         ( (uint32_t)input[j  ]     )|
00034                         (((uint32_t)input[j+1])<< 8)|
00035                         (((uint32_t)input[j+2])<<16)|
00036                         (((uint32_t)input[j+3])<<24);
00037 }
00038 
00039 static void Encode(uint8_t * output, const uint32_t * input, size_t len) {
00040         unsigned int i,j;
00041 
00042         for (i=j=0; j<len; ++i,j+=4) {
00043                 output[j  ]= input[i]     &0xff;
00044                 output[j+1]=(input[i]>> 8)&0xff;
00045                 output[j+2]=(input[i]>>16)&0xff;
00046                 output[j+3]= input[i]>>24      ;
00047         }
00048 }
00049 
00050 /* Constants for MD4Transform routine. */
00051 #define S11 3
00052 #define S12 7
00053 #define S13 11
00054 #define S14 19
00055 #define S21 3
00056 #define S22 5
00057 #define S23 9
00058 #define S24 13
00059 #define S31 3
00060 #define S32 9
00061 #define S33 11
00062 #define S34 15
00063 
00064 static const uint8_t padding[64] = { 0x80 };
00065 
00066 /* F, G and H are basic MD4 functions. */
00067 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
00068 #define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
00069 #define H(x, y, z) ((x) ^ (y) ^ (z))
00070 
00071 /* ROL rotates x left n bits. */
00072 #define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n))))
00073 #define XX(f,a,b,c,d,x,n,s) do { a+=f(b,c,d)+x+s; a=ROL(a,n); } while (0)
00074 
00075 /*
00076  * FF, GG and HH are transformations for rounds 1, 2 and 3
00077  * Rotation is separate from addition to prevent recomputation
00078  */
00079 #define FF(a,b,c,d,x,n) XX(F,a,b,c,d,x,n,0)
00080 #define GG(a,b,c,d,x,n) XX(G,a,b,c,d,x,n,(uint32_t)0x5a827999LU)
00081 #define HH(a,b,c,d,x,n) XX(H,a,b,c,d,x,n,(uint32_t)0x6ed9eba1LU)
00082 
00083 static void MD4Transform(uint32_t state[4],const uint8_t block[64]) {
00084         uint32_t a=state[0];
00085         uint32_t b=state[1];
00086         uint32_t c=state[2];
00087         uint32_t d=state[3];
00088         uint32_t x[16];
00089 
00090         Decode(x,block,64);
00091 
00092         FF(      a,b,c,d,x[ 0],S11);
00093         FF(    d,a,b,c,  x[ 1],S12);
00094         FF(  c,d,a,b,    x[ 2],S13);
00095         FF(b,c,d,a,      x[ 3],S14);
00096         FF(      a,b,c,d,x[ 4],S11);
00097         FF(    d,a,b,c,  x[ 5],S12);
00098         FF(  c,d,a,b,    x[ 6],S13);
00099         FF(b,c,d,a,      x[ 7],S14);
00100         FF(      a,b,c,d,x[ 8],S11);
00101         FF(    d,a,b,c,  x[ 9],S12);
00102         FF(  c,d,a,b,    x[10],S13);
00103         FF(b,c,d,a,      x[11],S14);
00104         FF(      a,b,c,d,x[12],S11);
00105         FF(    d,a,b,c,  x[13],S12);
00106         FF(  c,d,a,b,    x[14],S13);
00107         FF(b,c,d,a,      x[15],S14);
00108 
00109         GG(      a,b,c,d,x[ 0],S21);
00110         GG(    d,a,b,c,  x[ 4],S22);
00111         GG(  c,d,a,b,    x[ 8],S23);
00112         GG(b,c,d,a,      x[12],S24);
00113         GG(      a,b,c,d,x[ 1],S21);
00114         GG(    d,a,b,c,  x[ 5],S22);
00115         GG(  c,d,a,b,    x[ 9],S23);
00116         GG(b,c,d,a,      x[13],S24);
00117         GG(      a,b,c,d,x[ 2],S21);
00118         GG(    d,a,b,c,  x[ 6],S22);
00119         GG(  c,d,a,b,    x[10],S23);
00120         GG(b,c,d,a,      x[14],S24);
00121         GG(      a,b,c,d,x[ 3],S21);
00122         GG(    d,a,b,c,  x[ 7],S22);
00123         GG(  c,d,a,b,    x[11],S23);
00124         GG(b,c,d,a,      x[15],S24);
00125 
00126         HH(      a,b,c,d,x[ 0],S31);
00127         HH(    d,a,b,c,  x[ 8],S32);
00128         HH(  c,d,a,b,    x[ 4],S33);
00129         HH(b,c,d,a,      x[12],S34);
00130         HH(      a,b,c,d,x[ 2],S31);
00131         HH(    d,a,b,c,  x[10],S32);
00132         HH(  c,d,a,b,    x[ 6],S33);
00133         HH(b,c,d,a,      x[14],S34);
00134         HH(      a,b,c,d,x[ 1],S31);
00135         HH(    d,a,b,c,  x[ 9],S32);
00136         HH(  c,d,a,b,    x[ 5],S33);
00137         HH(b,c,d,a,      x[13],S34);
00138         HH(      a,b,c,d,x[ 3],S31);
00139         HH(    d,a,b,c,  x[11],S32);
00140         HH(  c,d,a,b,    x[ 7],S33);
00141         HH(b,c,d,a,      x[15],S34);
00142 
00143         state[0] += a;
00144         state[1] += b;
00145         state[2] += c;
00146         state[3] += d;
00147 
00148         memset(x,0,sizeof(x));
00149 }
00150 
00151 /* MD4 initialization. Begins an MD4 operation, writing a new context. */
00152 Md4Transform::Md4Transform() : wasFlushed(false) {
00153         count[0]=count[1]=0;
00154 
00155         /* Load magic initialization constants.
00156          */
00157         state[0]=0x67452301LU;
00158         state[1]=0xefcdab89LU;
00159         state[2]=0x98badcfeLU;
00160         state[3]=0x10325476LU;
00161 }
00162 
00163 /*
00164  * MD4 block update operation. Continues an MD4 message-digest operation,
00165  * processing another message block, and updating the context.
00166  */
00167 void Md4Transform::sumUp(const uint8_t *data, uint32_t size) {
00168         CHECK(!wasFlushed);
00169 
00170         unsigned int i, index, partLen;
00171 
00172         /* Compute number of bytes mod 64 */
00173         index = (unsigned int) ((count[0] >> 3) & 0x3F);
00174         /* Update number of bits */
00175         if ((count[0]+=((uint32_t)size << 3)) < ((uint32_t)size << 3))
00176                 count[1]++;
00177         count[1] += ((uint32_t) size >> 29);
00178 
00179         partLen = 64 - index;
00180         /* Transform as many times as possible.
00181          */
00182         if (size >= partLen) {
00183                 memcpy(&buffer[index],data,partLen);
00184                 MD4Transform(state, buffer);
00185 
00186                 for (i = partLen; i + 63 < size; i += 64)
00187                         MD4Transform(state, &data[i]);
00188 
00189                 index = 0;
00190         } else
00191                 i = 0;
00192 
00193         /* Buffer remaining data */
00194         memcpy(&buffer[index],&data[i],size-i);
00195 }
00196 
00197 /*
00198  * MD4 finalization. Ends an MD4 message-digest operation, writing the
00199  * the message digest and zeroizing the context.
00200  */
00201 Hash<MD4Hash> Md4Transform::getHash() {
00202         CHECK(!wasFlushed);
00203 
00204         unsigned char digest[16];
00205         uint8_t bits[8];
00206         unsigned int index, padLen;
00207 
00208         /* Save number of bits */
00209         Encode(bits, count, 8);
00210 
00211         /* Pad out to 56 mod 64. */
00212         index = (unsigned int) ((count[0] >> 3) & 0x3f);
00213         padLen = (index < 56) ? (56 - index) : (120 - index);
00214         Md4Transform::sumUp(padding, padLen);
00215 
00216         /* Append length (before padding) */
00217         Md4Transform::sumUp(bits, 8);
00218         /* Store state in digest */
00219         Encode(digest, state, 16);
00220 
00221         /* Clear sensitive information */
00222         memset(buffer,0,sizeof(buffer));
00223         memset(state ,0,sizeof(state ));
00224         count[0]=count[1]=0;
00225 
00226         wasFlushed=true;
00227 
00228         return Hash<MD4Hash>(digest);
00229 }
00230 
00231 Md4Transform::~Md4Transform() {
00232         CHECK(wasFlushed);
00233 }
00234 
00235 void Md4Transform::sumUp(const char *data, uint32_t size) {
00236         sumUp(reinterpret_cast<const unsigned char*>(data), size);
00237 }