summaryrefslogtreecommitdiff
path: root/md5.cpp
blob: e41fc593568c4b4f6184f94e492e7b2160206d84 (plain)
    1 /*
    2  * RFC 1321 compliant MD5 implementation,
    3  * by Christophe Devine <devine@cr0.net>;
    4  * this program is licensed under the GPL.
    5  */
    6 
    7 #include <string.h>
    8 #include "md5.h"
    9 
   10 #define GET_UINT32(n,b,i)                                       \
   11 {                                                               \
   12     (n) = (uint32) ((uint8 *) b)[(i)]                           \
   13       | (((uint32) ((uint8 *) b)[(i)+1]) <<  8)                 \
   14       | (((uint32) ((uint8 *) b)[(i)+2]) << 16)                 \
   15       | (((uint32) ((uint8 *) b)[(i)+3]) << 24);                \
   16 }
   17 
   18 #define PUT_UINT32(n,b,i)                                       \
   19 {                                                               \
   20     (((uint8 *) b)[(i)]  ) = (uint8) (((n)      ) & 0xFF);      \
   21     (((uint8 *) b)[(i)+1]) = (uint8) (((n) >>  8) & 0xFF);      \
   22     (((uint8 *) b)[(i)+2]) = (uint8) (((n) >> 16) & 0xFF);      \
   23     (((uint8 *) b)[(i)+3]) = (uint8) (((n) >> 24) & 0xFF);      \
   24 }
   25 
   26 void md5_starts( struct md5_context *ctx )
   27 {
   28     ctx->total[0] = 0;
   29     ctx->total[1] = 0;
   30     ctx->state[0] = 0x67452301;
   31     ctx->state[1] = 0xEFCDAB89;
   32     ctx->state[2] = 0x98BADCFE;
   33     ctx->state[3] = 0x10325476;
   34 }
   35 
   36 void md5_process( struct md5_context *ctx, uint8 data[64] )
   37 {
   38     uint32 A, B, C, D, X[16];
   39 
   40     GET_UINT32( X[0],  data,  0 );
   41     GET_UINT32( X[1],  data,  4 );
   42     GET_UINT32( X[2],  data,  8 );
   43     GET_UINT32( X[3],  data, 12 );
   44     GET_UINT32( X[4],  data, 16 );
   45     GET_UINT32( X[5],  data, 20 );
   46     GET_UINT32( X[6],  data, 24 );
   47     GET_UINT32( X[7],  data, 28 );
   48     GET_UINT32( X[8],  data, 32 );
   49     GET_UINT32( X[9],  data, 36 );
   50     GET_UINT32( X[10], data, 40 );
   51     GET_UINT32( X[11], data, 44 );
   52     GET_UINT32( X[12], data, 48 );
   53     GET_UINT32( X[13], data, 52 );
   54     GET_UINT32( X[14], data, 56 );
   55     GET_UINT32( X[15], data, 60 );
   56 
   57 #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
   58 
   59 #define P(a,b,c,d,k,s,t)                                \
   60 {                                                       \
   61     a += F(b,c,d) + X[k] + t; a = S(a,s) + b;           \
   62 }
   63 
   64     A = ctx->state[0];
   65     B = ctx->state[1];
   66     C = ctx->state[2];
   67     D = ctx->state[3];
   68 
   69 #define F(x,y,z) (z ^ (x & (y ^ z)))
   70 
   71     P( A, B, C, D,  0,  7, 0xD76AA478 );
   72     P( D, A, B, C,  1, 12, 0xE8C7B756 );
   73     P( C, D, A, B,  2, 17, 0x242070DB );
   74     P( B, C, D, A,  3, 22, 0xC1BDCEEE );
   75     P( A, B, C, D,  4,  7, 0xF57C0FAF );
   76     P( D, A, B, C,  5, 12, 0x4787C62A );
   77     P( C, D, A, B,  6, 17, 0xA8304613 );
   78     P( B, C, D, A,  7, 22, 0xFD469501 );
   79     P( A, B, C, D,  8,  7, 0x698098D8 );
   80     P( D, A, B, C,  9, 12, 0x8B44F7AF );
   81     P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
   82     P( B, C, D, A, 11, 22, 0x895CD7BE );
   83     P( A, B, C, D, 12,  7, 0x6B901122 );
   84     P( D, A, B, C, 13, 12, 0xFD987193 );
   85     P( C, D, A, B, 14, 17, 0xA679438E );
   86     P( B, C, D, A, 15, 22, 0x49B40821 );
   87 
   88 #undef F
   89 
   90 #define F(x,y,z) (y ^ (z & (x ^ y)))
   91 
   92     P( A, B, C, D,  1,  5, 0xF61E2562 );
   93     P( D, A, B, C,  6,  9, 0xC040B340 );
   94     P( C, D, A, B, 11, 14, 0x265E5A51 );
   95     P( B, C, D, A,  0, 20, 0xE9B6C7AA );
   96     P( A, B, C, D,  5,  5, 0xD62F105D );
   97     P( D, A, B, C, 10,  9, 0x02441453 );
   98     P( C, D, A, B, 15, 14, 0xD8A1E681 );
   99     P( B, C, D, A,  4, 20, 0xE7D3FBC8 );
  100     P( A, B, C, D,  9,  5, 0x21E1CDE6 );
  101     P( D, A, B, C, 14,  9, 0xC33707D6 );
  102     P( C, D, A, B,  3, 14, 0xF4D50D87 );
  103     P( B, C, D, A,  8, 20, 0x455A14ED );
  104     P( A, B, C, D, 13,  5, 0xA9E3E905 );
  105     P( D, A, B, C,  2,  9, 0xFCEFA3F8 );
  106     P( C, D, A, B,  7, 14, 0x676F02D9 );
  107     P( B, C, D, A, 12, 20, 0x8D2A4C8A );
  108 
  109 #undef F
  110     
  111 #define F(x,y,z) (x ^ y ^ z)
  112 
  113     P( A, B, C, D,  5,  4, 0xFFFA3942 );
  114     P( D, A, B, C,  8, 11, 0x8771F681 );
  115     P( C, D, A, B, 11, 16, 0x6D9D6122 );
  116     P( B, C, D, A, 14, 23, 0xFDE5380C );
  117     P( A, B, C, D,  1,  4, 0xA4BEEA44 );
  118     P( D, A, B, C,  4, 11, 0x4BDECFA9 );
  119     P( C, D, A, B,  7, 16, 0xF6BB4B60 );
  120     P( B, C, D, A, 10, 23, 0xBEBFBC70 );
  121     P( A, B, C, D, 13,  4, 0x289B7EC6 );
  122     P( D, A, B, C,  0, 11, 0xEAA127FA );
  123     P( C, D, A, B,  3, 16, 0xD4EF3085 );
  124     P( B, C, D, A,  6, 23, 0x04881D05 );
  125     P( A, B, C, D,  9,  4, 0xD9D4D039 );
  126     P( D, A, B, C, 12, 11, 0xE6DB99E5 );
  127     P( C, D, A, B, 15, 16, 0x1FA27CF8 );
  128     P( B, C, D, A,  2, 23, 0xC4AC5665 );
  129 
  130 #undef F
  131 
  132 #define F(x,y,z) (y ^ (x | ~z))
  133 
  134     P( A, B, C, D,  0,  6, 0xF4292244 );
  135     P( D, A, B, C,  7, 10, 0x432AFF97 );
  136     P( C, D, A, B, 14, 15, 0xAB9423A7 );
  137     P( B, C, D, A,  5, 21, 0xFC93A039 );
  138     P( A, B, C, D, 12,  6, 0x655B59C3 );
  139     P( D, A, B, C,  3, 10, 0x8F0CCC92 );
  140     P( C, D, A, B, 10, 15, 0xFFEFF47D );
  141     P( B, C, D, A,  1, 21, 0x85845DD1 );
  142     P( A, B, C, D,  8,  6, 0x6FA87E4F );
  143     P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
  144     P( C, D, A, B,  6, 15, 0xA3014314 );
  145     P( B, C, D, A, 13, 21, 0x4E0811A1 );
  146     P( A, B, C, D,  4,  6, 0xF7537E82 );
  147     P( D, A, B, C, 11, 10, 0xBD3AF235 );
  148     P( C, D, A, B,  2, 15, 0x2AD7D2BB );
  149     P( B, C, D, A,  9, 21, 0xEB86D391 );
  150 
  151 #undef F
  152 
  153     ctx->state[0] += A;
  154     ctx->state[1] += B;
  155     ctx->state[2] += C;
  156     ctx->state[3] += D;
  157 }
  158 
  159 void md5_update( struct md5_context *ctx, uint8 *input, uint32 length )
  160 {
  161     uint32 left, fill;
  162 
  163     if( ! length ) return;
  164 
  165     left = ( ctx->total[0] >> 3 ) & 0x3F;
  166     fill = 64 - left;
  167 
  168     ctx->total[0] += length <<  3;
  169     ctx->total[1] += length >> 29;
  170 
  171     ctx->total[0] &= 0xFFFFFFFF;
  172     ctx->total[1] += ctx->total[0] < ( length << 3 );
  173 
  174     if( left && length >= fill )
  175     {
  176         memcpy( (void *) (ctx->buffer + left), (void *) input, fill );
  177         md5_process( ctx, ctx->buffer );
  178         length -= fill;
  179         input  += fill;
  180         left = 0;
  181     }
  182 
  183     while( length >= 64 )
  184     {
  185         md5_process( ctx, input );
  186         length -= 64;
  187         input  += 64;
  188     }
  189 
  190     if( length )
  191     {
  192         memcpy( (void *) (ctx->buffer + left), (void *) input, length );
  193     }
  194 }
  195 
  196 static uint8 md5_padding[64] =
  197 {
  198  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  199     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  200     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  201     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  202 };
  203 
  204 void md5_finish( struct md5_context *ctx, uint8 digest[16] )
  205 {
  206     uint32 last, padn;
  207     uint8 msglen[8];
  208 
  209     PUT_UINT32( ctx->total[0], msglen, 0 );
  210     PUT_UINT32( ctx->total[1], msglen, 4 );
  211 
  212     last = ( ctx->total[0] >> 3 ) & 0x3F;
  213     padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
  214 
  215     md5_update( ctx, md5_padding, padn );
  216     md5_update( ctx, msglen, 8 );
  217 
  218     PUT_UINT32( ctx->state[0], digest,  0 );
  219     PUT_UINT32( ctx->state[1], digest,  4 );
  220     PUT_UINT32( ctx->state[2], digest,  8 );
  221     PUT_UINT32( ctx->state[3], digest, 12 );
  222 }
  223 
  224 #ifdef TEST
  225 
  226 #include <stdio.h>
  227 
  228 /*
  229  * those are the standard RFC 1321 test vectors
  230  */
  231 
  232 static char *msg[] =
  233 {
  234     "",
  235     "a",
  236     "abc",
  237     "message digest",
  238     "abcdefghijklmnopqrstuvwxyz",
  239     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
  240     "12345678901234567890123456789012345678901234567890123456789012" \
  241         "345678901234567890"
  242 };
  243 
  244 static char *val[] =
  245 {
  246     "d41d8cd98f00b204e9800998ecf8427e",
  247     "0cc175b9c0f1b6a831c399e269772661",
  248     "900150983cd24fb0d6963f7d28e17f72",
  249     "f96b697d7cb7938d525a2f31aaf161d0",
  250     "c3fcd3d76192e4007dfb496cca67e13b",
  251     "d174ab98d277d9f5a5611c2c9f419d9f",
  252     "57edf4a22be3c955ac49da2e2107b67a"
  253 };
  254 
  255 int main( int argc, char *argv[] )
  256 {
  257     FILE *f;
  258     int i, j;
  259     char output[33];
  260     struct md5_context ctx;
  261     unsigned char md5sum[16], buffer[1000];
  262 
  263     if( argc < 2 )
  264     {
  265         for( i = 0; i < 7; i++ )
  266         {
  267             md5_starts( &ctx );
  268             md5_update( &ctx, (uint8 *) msg[i], strlen( msg[i] ) );
  269             md5_finish( &ctx, md5sum );
  270 
  271             for( j = 0; j < 16; j++ )
  272             {
  273                 sprintf( output + j * 2, "%02x", md5sum[j] );
  274             }
  275 
  276             printf( "test %d ", i + 1 );
  277 
  278             if( ! memcmp( output, val[i], 32 ) )
  279             {
  280                 printf( "passed\n" );
  281             }
  282             else
  283             {
  284                 printf( "failed\n" );
  285                 return( 1 );
  286             }
  287         }
  288     }
  289     else
  290     {
  291         if( ! ( f = fopen( argv[1], "rb" ) ) )
  292         {
  293             perror( "fopen" );
  294             return( 1 );
  295         }
  296 
  297         md5_starts( &ctx );
  298 
  299         while( ( i = fread( buffer, 1, sizeof( buffer ), f ) ) > 0 )
  300         {
  301             md5_update( &ctx, buffer, i );
  302         }
  303 
  304         md5_finish( &ctx, md5sum );
  305 
  306         for( j = 0; j < 16; j++ )
  307         {
  308             printf( "%02x", md5sum[j] );
  309         }
  310 
  311         printf( "  %s\n", argv[1] );
  312     }
  313 
  314     return( 0 );
  315 }
  316 
  317 #endif

Generated by cgit