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

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

Generated on Tue Jul 1 15:29:59 2008 for Mobile-C by  doxygen 1.5.4