/home/dko/projects/mobilec/trunk/src/security/xyssl-0.7/library/md5.c

Go to the documentation of this file.
00001 /*
00002  *  RFC 1321 compliant MD5 implementation
00003  *
00004  *  Copyright (C) 2006-2007  Christophe Devine
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License, version 2.1 as published by the Free Software Foundation.
00009  *
00010  *  This library is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  Lesser General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU Lesser General Public
00016  *  License along with this library; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00018  *  MA  02110-1301  USA
00019  */
00020 /*
00021  *  The MD5 algorithm was designed by Ron Rivest in 1991.
00022  *
00023  *  http://www.ietf.org/rfc/rfc1321.txt
00024  */
00025 
00026 #ifndef _CRT_SECURE_NO_DEPRECATE
00027 #define _CRT_SECURE_NO_DEPRECATE 1
00028 #endif
00029 
00030 #include <string.h>
00031 #include <stdio.h>
00032 
00033 #include "xyssl/md5.h"
00034 
00035 /*
00036  * 32-bit integer manipulation macros (little endian)
00037  */
00038 #ifndef GET_UINT32_LE
00039 #define GET_UINT32_LE(n,b,i)                            \
00040 {                                                       \
00041     (n) = ( (unsigned long) (b)[(i)    ]       )        \
00042         | ( (unsigned long) (b)[(i) + 1] <<  8 )        \
00043         | ( (unsigned long) (b)[(i) + 2] << 16 )        \
00044         | ( (unsigned long) (b)[(i) + 3] << 24 );       \
00045 }
00046 #endif
00047 
00048 #ifndef PUT_UINT32_LE
00049 #define PUT_UINT32_LE(n,b,i)                            \
00050 {                                                       \
00051     (b)[(i)    ] = (unsigned char) ( (n)       );       \
00052     (b)[(i) + 1] = (unsigned char) ( (n) >>  8 );       \
00053     (b)[(i) + 2] = (unsigned char) ( (n) >> 16 );       \
00054     (b)[(i) + 3] = (unsigned char) ( (n) >> 24 );       \
00055 }
00056 #endif
00057 
00058 /*
00059  * MD5 context setup
00060  */
00061 void md5_starts( md5_context *ctx )
00062 {
00063     ctx->total[0] = 0;
00064     ctx->total[1] = 0;
00065 
00066     ctx->state[0] = 0x67452301;
00067     ctx->state[1] = 0xEFCDAB89;
00068     ctx->state[2] = 0x98BADCFE;
00069     ctx->state[3] = 0x10325476;
00070 }
00071 
00072 static void md5_process( md5_context *ctx, unsigned char data[64] )
00073 {
00074     unsigned long X[16], A, B, C, D;
00075 
00076     GET_UINT32_LE( X[ 0], data,  0 );
00077     GET_UINT32_LE( X[ 1], data,  4 );
00078     GET_UINT32_LE( X[ 2], data,  8 );
00079     GET_UINT32_LE( X[ 3], data, 12 );
00080     GET_UINT32_LE( X[ 4], data, 16 );
00081     GET_UINT32_LE( X[ 5], data, 20 );
00082     GET_UINT32_LE( X[ 6], data, 24 );
00083     GET_UINT32_LE( X[ 7], data, 28 );
00084     GET_UINT32_LE( X[ 8], data, 32 );
00085     GET_UINT32_LE( X[ 9], data, 36 );
00086     GET_UINT32_LE( X[10], data, 40 );
00087     GET_UINT32_LE( X[11], data, 44 );
00088     GET_UINT32_LE( X[12], data, 48 );
00089     GET_UINT32_LE( X[13], data, 52 );
00090     GET_UINT32_LE( X[14], data, 56 );
00091     GET_UINT32_LE( X[15], data, 60 );
00092 
00093 #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
00094 
00095 #define P(a,b,c,d,k,s,t)                                \
00096 {                                                       \
00097     a += F(b,c,d) + X[k] + t; a = S(a,s) + b;           \
00098 }
00099 
00100     A = ctx->state[0];
00101     B = ctx->state[1];
00102     C = ctx->state[2];
00103     D = ctx->state[3];
00104 
00105 #define F(x,y,z) (z ^ (x & (y ^ z)))
00106 
00107     P( A, B, C, D,  0,  7, 0xD76AA478 );
00108     P( D, A, B, C,  1, 12, 0xE8C7B756 );
00109     P( C, D, A, B,  2, 17, 0x242070DB );
00110     P( B, C, D, A,  3, 22, 0xC1BDCEEE );
00111     P( A, B, C, D,  4,  7, 0xF57C0FAF );
00112     P( D, A, B, C,  5, 12, 0x4787C62A );
00113     P( C, D, A, B,  6, 17, 0xA8304613 );
00114     P( B, C, D, A,  7, 22, 0xFD469501 );
00115     P( A, B, C, D,  8,  7, 0x698098D8 );
00116     P( D, A, B, C,  9, 12, 0x8B44F7AF );
00117     P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
00118     P( B, C, D, A, 11, 22, 0x895CD7BE );
00119     P( A, B, C, D, 12,  7, 0x6B901122 );
00120     P( D, A, B, C, 13, 12, 0xFD987193 );
00121     P( C, D, A, B, 14, 17, 0xA679438E );
00122     P( B, C, D, A, 15, 22, 0x49B40821 );
00123 
00124 #undef F
00125 
00126 #define F(x,y,z) (y ^ (z & (x ^ y)))
00127 
00128     P( A, B, C, D,  1,  5, 0xF61E2562 );
00129     P( D, A, B, C,  6,  9, 0xC040B340 );
00130     P( C, D, A, B, 11, 14, 0x265E5A51 );
00131     P( B, C, D, A,  0, 20, 0xE9B6C7AA );
00132     P( A, B, C, D,  5,  5, 0xD62F105D );
00133     P( D, A, B, C, 10,  9, 0x02441453 );
00134     P( C, D, A, B, 15, 14, 0xD8A1E681 );
00135     P( B, C, D, A,  4, 20, 0xE7D3FBC8 );
00136     P( A, B, C, D,  9,  5, 0x21E1CDE6 );
00137     P( D, A, B, C, 14,  9, 0xC33707D6 );
00138     P( C, D, A, B,  3, 14, 0xF4D50D87 );
00139     P( B, C, D, A,  8, 20, 0x455A14ED );
00140     P( A, B, C, D, 13,  5, 0xA9E3E905 );
00141     P( D, A, B, C,  2,  9, 0xFCEFA3F8 );
00142     P( C, D, A, B,  7, 14, 0x676F02D9 );
00143     P( B, C, D, A, 12, 20, 0x8D2A4C8A );
00144 
00145 #undef F
00146     
00147 #define F(x,y,z) (x ^ y ^ z)
00148 
00149     P( A, B, C, D,  5,  4, 0xFFFA3942 );
00150     P( D, A, B, C,  8, 11, 0x8771F681 );
00151     P( C, D, A, B, 11, 16, 0x6D9D6122 );
00152     P( B, C, D, A, 14, 23, 0xFDE5380C );
00153     P( A, B, C, D,  1,  4, 0xA4BEEA44 );
00154     P( D, A, B, C,  4, 11, 0x4BDECFA9 );
00155     P( C, D, A, B,  7, 16, 0xF6BB4B60 );
00156     P( B, C, D, A, 10, 23, 0xBEBFBC70 );
00157     P( A, B, C, D, 13,  4, 0x289B7EC6 );
00158     P( D, A, B, C,  0, 11, 0xEAA127FA );
00159     P( C, D, A, B,  3, 16, 0xD4EF3085 );
00160     P( B, C, D, A,  6, 23, 0x04881D05 );
00161     P( A, B, C, D,  9,  4, 0xD9D4D039 );
00162     P( D, A, B, C, 12, 11, 0xE6DB99E5 );
00163     P( C, D, A, B, 15, 16, 0x1FA27CF8 );
00164     P( B, C, D, A,  2, 23, 0xC4AC5665 );
00165 
00166 #undef F
00167 
00168 #define F(x,y,z) (y ^ (x | ~z))
00169 
00170     P( A, B, C, D,  0,  6, 0xF4292244 );
00171     P( D, A, B, C,  7, 10, 0x432AFF97 );
00172     P( C, D, A, B, 14, 15, 0xAB9423A7 );
00173     P( B, C, D, A,  5, 21, 0xFC93A039 );
00174     P( A, B, C, D, 12,  6, 0x655B59C3 );
00175     P( D, A, B, C,  3, 10, 0x8F0CCC92 );
00176     P( C, D, A, B, 10, 15, 0xFFEFF47D );
00177     P( B, C, D, A,  1, 21, 0x85845DD1 );
00178     P( A, B, C, D,  8,  6, 0x6FA87E4F );
00179     P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
00180     P( C, D, A, B,  6, 15, 0xA3014314 );
00181     P( B, C, D, A, 13, 21, 0x4E0811A1 );
00182     P( A, B, C, D,  4,  6, 0xF7537E82 );
00183     P( D, A, B, C, 11, 10, 0xBD3AF235 );
00184     P( C, D, A, B,  2, 15, 0x2AD7D2BB );
00185     P( B, C, D, A,  9, 21, 0xEB86D391 );
00186 
00187 #undef F
00188 
00189     ctx->state[0] += A;
00190     ctx->state[1] += B;
00191     ctx->state[2] += C;
00192     ctx->state[3] += D;
00193 }
00194 
00195 /*
00196  * MD5 process buffer
00197  */
00198 void md5_update( md5_context *ctx, unsigned char *input, int ilen )
00199 {
00200     int fill;
00201     unsigned long left;
00202 
00203     if( ilen <= 0 )
00204         return;
00205 
00206     left = ctx->total[0] & 0x3F;
00207     fill = 64 - left;
00208 
00209     ctx->total[0] += ilen;
00210     ctx->total[0] &= 0xFFFFFFFF;
00211 
00212     if( ctx->total[0] < (unsigned long) ilen )
00213         ctx->total[1]++;
00214 
00215     if( left && ilen >= fill )
00216     {
00217         memcpy( (void *) (ctx->buffer + left),
00218                 (void *) input, fill );
00219         md5_process( ctx, ctx->buffer );
00220         input += fill;
00221         ilen  -= fill;
00222         left = 0;
00223     }
00224 
00225     while( ilen >= 64 )
00226     {
00227         md5_process( ctx, input );
00228         input += 64;
00229         ilen  -= 64;
00230     }
00231 
00232     if( ilen > 0 )
00233     {
00234         memcpy( (void *) (ctx->buffer + left),
00235                 (void *) input, ilen );
00236     }
00237 }
00238 
00239 static const unsigned char md5_padding[64] =
00240 {
00241  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00242     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00243     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00244     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00245 };
00246 
00247 /*
00248  * MD5 final digest
00249  */
00250 void md5_finish( md5_context *ctx, unsigned char *output )
00251 {
00252     unsigned long last, padn;
00253     unsigned long high, low;
00254     unsigned char msglen[8];
00255 
00256     high = ( ctx->total[0] >> 29 )
00257          | ( ctx->total[1] <<  3 );
00258     low  = ( ctx->total[0] <<  3 );
00259 
00260     PUT_UINT32_LE( low,  msglen, 0 );
00261     PUT_UINT32_LE( high, msglen, 4 );
00262 
00263     last = ctx->total[0] & 0x3F;
00264     padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
00265 
00266     md5_update( ctx, (unsigned char *) md5_padding, padn );
00267     md5_update( ctx, msglen, 8 );
00268 
00269     PUT_UINT32_LE( ctx->state[0], output,  0 );
00270     PUT_UINT32_LE( ctx->state[1], output,  4 );
00271     PUT_UINT32_LE( ctx->state[2], output,  8 );
00272     PUT_UINT32_LE( ctx->state[3], output, 12 );
00273 }
00274 
00275 /*
00276  * Output = MD5( input buffer )
00277  */
00278 void md5( unsigned char *input, int ilen,
00279           unsigned char *output )
00280 {
00281     md5_context ctx;
00282 
00283     md5_starts( &ctx );
00284     md5_update( &ctx, input, ilen );
00285     md5_finish( &ctx, output );
00286 
00287     memset( &ctx, 0, sizeof( md5_context ) );
00288 }
00289 
00290 /*
00291  * Output = MD5( file contents )
00292  */
00293 int md5_file( char *path, unsigned char *output )
00294 {
00295     FILE *f;
00296     size_t n;
00297     md5_context ctx;
00298     unsigned char buf[1024];
00299 
00300     if( ( f = fopen( path, "rb" ) ) == NULL )
00301         return( 1 );
00302 
00303     md5_starts( &ctx );
00304 
00305     while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
00306         md5_update( &ctx, buf, (int) n );
00307 
00308     md5_finish( &ctx, output );
00309 
00310     memset( &ctx, 0, sizeof( md5_context ) );
00311 
00312     if( ferror( f ) != 0 )
00313     {
00314         fclose( f );
00315         return( 2 );
00316     }
00317 
00318     fclose( f );
00319     return( 0 );
00320 }
00321 
00322 /*
00323  * MD5 HMAC context setup
00324  */
00325 void md5_hmac_starts( md5_context *ctx,
00326                       unsigned char *key, int keylen )
00327 {
00328     int i;
00329 
00330     memset( ctx->ipad, 0x36, 64 );
00331     memset( ctx->opad, 0x5C, 64 );
00332 
00333     for( i = 0; i < keylen; i++ )
00334     {
00335         if( i >= 64 ) break;
00336 
00337         ctx->ipad[i] ^= key[i];
00338         ctx->opad[i] ^= key[i];
00339     }
00340 
00341     md5_starts( ctx );
00342     md5_update( ctx, ctx->ipad, 64 );
00343 }
00344 
00345 /*
00346  * MD5 HMAC process buffer
00347  */
00348 void md5_hmac_update( md5_context *ctx,
00349                       unsigned char *input, int ilen )
00350 {
00351     md5_update( ctx, input, ilen );
00352 }
00353 
00354 /*
00355  * MD5 HMAC final digest
00356  */
00357 void md5_hmac_finish( md5_context *ctx, unsigned char *output )
00358 {
00359     unsigned char tmpbuf[16];
00360 
00361     md5_finish( ctx, tmpbuf );
00362     md5_starts( ctx );
00363     md5_update( ctx, ctx->opad, 64 );
00364     md5_update( ctx, tmpbuf, 16 );
00365     md5_finish( ctx, output );
00366 
00367     memset( tmpbuf, 0, sizeof( tmpbuf ) );
00368 }
00369 
00370 /*
00371  * Output = HMAC-MD5( hmac key, input buffer )
00372  */
00373 void md5_hmac( unsigned char *key, int keylen,
00374                unsigned char *input, int ilen,
00375                unsigned char *output )
00376 {
00377     md5_context ctx;
00378 
00379     md5_hmac_starts( &ctx, key, keylen );
00380     md5_hmac_update( &ctx, input, ilen );
00381     md5_hmac_finish( &ctx, output );
00382 
00383     memset( &ctx, 0, sizeof( md5_context ) );
00384 }
00385 
00386 static const char _md5_src[] = "_md5_src";
00387 
00388 #if defined(SELF_TEST)
00389 /*
00390  * RFC 1321 test vectors
00391  */
00392 static const char md5_test_str[7][81] =
00393 {
00394     { "" }, 
00395     { "a" },
00396     { "abc" },
00397     { "message digest" },
00398     { "abcdefghijklmnopqrstuvwxyz" },
00399     { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
00400     { "12345678901234567890123456789012345678901234567890123456789012" \
00401       "345678901234567890" }
00402 };
00403 
00404 static const unsigned char md5_test_sum[7][16] =
00405 {
00406     { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
00407       0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E },
00408     { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8,
00409       0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 },
00410     { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0,
00411       0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 },
00412     { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D,
00413       0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 },
00414     { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00,
00415       0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B },
00416     { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5,
00417       0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F },
00418     { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55,
00419       0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A }
00420 };
00421 
00422 /*
00423  * Checkup routine
00424  */
00425 int md5_self_test( int verbose )
00426 {
00427     int i;
00428     unsigned char md5sum[16];
00429 
00430     for( i = 0; i < 7; i++ )
00431     {
00432         if( verbose != 0 )
00433             printf( "  MD5 test #%d: ", i + 1 );
00434 
00435         md5( (unsigned char *) md5_test_str[i],
00436              strlen( md5_test_str[i] ), md5sum );
00437 
00438         if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 )
00439         {
00440             if( verbose != 0 )
00441                 printf( "failed\n" );
00442 
00443             return( 1 );
00444         }
00445 
00446         if( verbose != 0 )
00447             printf( "passed\n" );
00448     }
00449 
00450     if( verbose != 0 )
00451         printf( "\n" );
00452 
00453     return( 0 );
00454 }
00455 #else
00456 int md5_self_test( int verbose )
00457 {
00458     return( 0 );
00459 }
00460 #endif

Generated on Fri May 16 14:49:55 2008 for Mobile-C by  doxygen 1.5.4