1 #include <memory.h> 2 #include "Types.h" 3 4 // "Derived from the RSA Data Security, Inc. MD5 Message Digest Algorithm" 5 6 /** 7 * \brief MD5 context structure 8 */ 9 typedef struct 10 { 11 unsigned long total[2]; /*!< number of bytes processed */ 12 unsigned long state[4]; /*!< intermediate digest state */ 13 unsigned char buffer[64]; /*!< data block being processed */ 14 15 unsigned char ipad[64]; /*!< HMAC: inner padding */ 16 unsigned char opad[64]; /*!< HMAC: outer padding */ 17 } 18 md5_context; 19 20 /** 21 * \brief MD5 context setup 22 * 23 * \param ctx context to be initialized 24 */ 25 void md5_starts( md5_context *ctx ); 26 27 /** 28 * \brief MD5 process buffer 29 * 30 * \param ctx MD5 context 31 * \param input buffer holding the data 32 * \param ilen length of the input data 33 */ 34 void md5_update( md5_context *ctx, unsigned char *input, int ilen ); 35 36 /** 37 * \brief MD5 final digest 38 * 39 * \param ctx MD5 context 40 * \param output MD5 checksum result 41 */ 42 void md5_finish( md5_context *ctx, unsigned char output[16] ); 43 44 /** 45 * \brief Output = MD5( input buffer ) 46 * 47 * \param input buffer holding the data 48 * \param ilen length of the input data 49 * \param output MD5 checksum result 50 */ 51 void md5( unsigned char *input, int ilen, unsigned char output[16] ); 52 53 /** 54 * \brief Output = MD5( file contents ) 55 * 56 * \param path input file name 57 * \param output MD5 checksum result 58 * 59 * \return 0 if successful, 1 if fopen failed, 60 * or 2 if fread failed 61 */ 62 int md5_file( char *path, unsigned char output[16] ); 63 64 /** 65 * \brief MD5 HMAC context setup 66 * 67 * \param ctx HMAC context to be initialized 68 * \param key HMAC secret key 69 * \param keylen length of the HMAC key 70 */ 71 void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen ); 72 73 /** 74 * \brief MD5 HMAC process buffer 75 * 76 * \param ctx HMAC context 77 * \param input buffer holding the data 78 * \param ilen length of the input data 79 */ 80 void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen ); 81 82 /** 83 * \brief MD5 HMAC final digest 84 * 85 * \param ctx HMAC context 86 * \param output MD5 HMAC checksum result 87 */ 88 void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ); 89 90 /** 91 * \brief Output = HMAC-MD5( hmac key, input buffer ) 92 * 93 * \param key HMAC secret key 94 * \param keylen length of the HMAC key 95 * \param input buffer holding the data 96 * \param ilen length of the input data 97 * \param output HMAC-MD5 result 98 */ 99 void md5_hmac( unsigned char *key, int keylen, 100 unsigned char *input, int ilen, 101 unsigned char output[16] ); 102 103 /** 104 * \brief Checkup routine 105 * 106 * \return 0 if successful, or 1 if the test failed 107 */ 108 int md5_self_test( int verbose ); 109 110 /* 111 * 32-bit integer manipulation macros (little endian) 112 */ 113 #ifndef GET_ULONG_LE 114 #define GET_ULONG_LE(n,b,i) \ 115 { \ 116 (n) = ( (unsigned long) (b)[(i) ] ) \ 117 | ( (unsigned long) (b)[(i) + 1] << 8 ) \ 118 | ( (unsigned long) (b)[(i) + 2] << 16 ) \ 119 | ( (unsigned long) (b)[(i) + 3] << 24 ); \ 120 } 121 #endif 122 123 #ifndef PUT_ULONG_LE 124 #define PUT_ULONG_LE(n,b,i) \ 125 { \ 126 (b)[(i) ] = (unsigned char) ( (n) ); \ 127 (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ 128 (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ 129 (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ 130 } 131 #endif 132 133 /* 134 * MD5 context setup 135 */ 136 void md5_starts( md5_context *ctx ) 137 { 138 ctx->total[0] = 0; 139 ctx->total[1] = 0; 140 141 ctx->state[0] = 0x67452301; 142 ctx->state[1] = 0xEFCDAB89; 143 ctx->state[2] = 0x98BADCFE; 144 ctx->state[3] = 0x10325476; 145 } 146 147 static void md5_process( md5_context *ctx, unsigned char data[64] ) 148 { 149 unsigned long X[16], A, B, C, D; 150 151 GET_ULONG_LE( X[ 0], data, 0 ); 152 GET_ULONG_LE( X[ 1], data, 4 ); 153 GET_ULONG_LE( X[ 2], data, 8 ); 154 GET_ULONG_LE( X[ 3], data, 12 ); 155 GET_ULONG_LE( X[ 4], data, 16 ); 156 GET_ULONG_LE( X[ 5], data, 20 ); 157 GET_ULONG_LE( X[ 6], data, 24 ); 158 GET_ULONG_LE( X[ 7], data, 28 ); 159 GET_ULONG_LE( X[ 8], data, 32 ); 160 GET_ULONG_LE( X[ 9], data, 36 ); 161 GET_ULONG_LE( X[10], data, 40 ); 162 GET_ULONG_LE( X[11], data, 44 ); 163 GET_ULONG_LE( X[12], data, 48 ); 164 GET_ULONG_LE( X[13], data, 52 ); 165 GET_ULONG_LE( X[14], data, 56 ); 166 GET_ULONG_LE( X[15], data, 60 ); 167 168 #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) 169 170 #define P(a,b,c,d,k,s,t) \ 171 { \ 172 a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ 173 } 174 175 A = ctx->state[0]; 176 B = ctx->state[1]; 177 C = ctx->state[2]; 178 D = ctx->state[3]; 179 180 #define F(x,y,z) (z ^ (x & (y ^ z))) 181 182 P( A, B, C, D, 0, 7, 0xD76AA478 ); 183 P( D, A, B, C, 1, 12, 0xE8C7B756 ); 184 P( C, D, A, B, 2, 17, 0x242070DB ); 185 P( B, C, D, A, 3, 22, 0xC1BDCEEE ); 186 P( A, B, C, D, 4, 7, 0xF57C0FAF ); 187 P( D, A, B, C, 5, 12, 0x4787C62A ); 188 P( C, D, A, B, 6, 17, 0xA8304613 ); 189 P( B, C, D, A, 7, 22, 0xFD469501 ); 190 P( A, B, C, D, 8, 7, 0x698098D8 ); 191 P( D, A, B, C, 9, 12, 0x8B44F7AF ); 192 P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); 193 P( B, C, D, A, 11, 22, 0x895CD7BE ); 194 P( A, B, C, D, 12, 7, 0x6B901122 ); 195 P( D, A, B, C, 13, 12, 0xFD987193 ); 196 P( C, D, A, B, 14, 17, 0xA679438E ); 197 P( B, C, D, A, 15, 22, 0x49B40821 ); 198 199 #undef F 200 201 #define F(x,y,z) (y ^ (z & (x ^ y))) 202 203 P( A, B, C, D, 1, 5, 0xF61E2562 ); 204 P( D, A, B, C, 6, 9, 0xC040B340 ); 205 P( C, D, A, B, 11, 14, 0x265E5A51 ); 206 P( B, C, D, A, 0, 20, 0xE9B6C7AA ); 207 P( A, B, C, D, 5, 5, 0xD62F105D ); 208 P( D, A, B, C, 10, 9, 0x02441453 ); 209 P( C, D, A, B, 15, 14, 0xD8A1E681 ); 210 P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); 211 P( A, B, C, D, 9, 5, 0x21E1CDE6 ); 212 P( D, A, B, C, 14, 9, 0xC33707D6 ); 213 P( C, D, A, B, 3, 14, 0xF4D50D87 ); 214 P( B, C, D, A, 8, 20, 0x455A14ED ); 215 P( A, B, C, D, 13, 5, 0xA9E3E905 ); 216 P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); 217 P( C, D, A, B, 7, 14, 0x676F02D9 ); 218 P( B, C, D, A, 12, 20, 0x8D2A4C8A ); 219 220 #undef F 221 222 #define F(x,y,z) (x ^ y ^ z) 223 224 P( A, B, C, D, 5, 4, 0xFFFA3942 ); 225 P( D, A, B, C, 8, 11, 0x8771F681 ); 226 P( C, D, A, B, 11, 16, 0x6D9D6122 ); 227 P( B, C, D, A, 14, 23, 0xFDE5380C ); 228 P( A, B, C, D, 1, 4, 0xA4BEEA44 ); 229 P( D, A, B, C, 4, 11, 0x4BDECFA9 ); 230 P( C, D, A, B, 7, 16, 0xF6BB4B60 ); 231 P( B, C, D, A, 10, 23, 0xBEBFBC70 ); 232 P( A, B, C, D, 13, 4, 0x289B7EC6 ); 233 P( D, A, B, C, 0, 11, 0xEAA127FA ); 234 P( C, D, A, B, 3, 16, 0xD4EF3085 ); 235 P( B, C, D, A, 6, 23, 0x04881D05 ); 236 P( A, B, C, D, 9, 4, 0xD9D4D039 ); 237 P( D, A, B, C, 12, 11, 0xE6DB99E5 ); 238 P( C, D, A, B, 15, 16, 0x1FA27CF8 ); 239 P( B, C, D, A, 2, 23, 0xC4AC5665 ); 240 241 #undef F 242 243 #define F(x,y,z) (y ^ (x | ~z)) 244 245 P( A, B, C, D, 0, 6, 0xF4292244 ); 246 P( D, A, B, C, 7, 10, 0x432AFF97 ); 247 P( C, D, A, B, 14, 15, 0xAB9423A7 ); 248 P( B, C, D, A, 5, 21, 0xFC93A039 ); 249 P( A, B, C, D, 12, 6, 0x655B59C3 ); 250 P( D, A, B, C, 3, 10, 0x8F0CCC92 ); 251 P( C, D, A, B, 10, 15, 0xFFEFF47D ); 252 P( B, C, D, A, 1, 21, 0x85845DD1 ); 253 P( A, B, C, D, 8, 6, 0x6FA87E4F ); 254 P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); 255 P( C, D, A, B, 6, 15, 0xA3014314 ); 256 P( B, C, D, A, 13, 21, 0x4E0811A1 ); 257 P( A, B, C, D, 4, 6, 0xF7537E82 ); 258 P( D, A, B, C, 11, 10, 0xBD3AF235 ); 259 P( C, D, A, B, 2, 15, 0x2AD7D2BB ); 260 P( B, C, D, A, 9, 21, 0xEB86D391 ); 261 262 #undef F 263 264 ctx->state[0] += A; 265 ctx->state[1] += B; 266 ctx->state[2] += C; 267 ctx->state[3] += D; 268 } 269 270 /* 271 * MD5 process buffer 272 */ 273 void md5_update( md5_context *ctx, unsigned char *input, int ilen ) 274 { 275 int fill; 276 unsigned long left; 277 278 if( ilen <= 0 ) 279 return; 280 281 left = ctx->total[0] & 0x3F; 282 fill = 64 - left; 283 284 ctx->total[0] += ilen; 285 ctx->total[0] &= 0xFFFFFFFF; 286 287 if( ctx->total[0] < (unsigned long) ilen ) 288 ctx->total[1]++; 289 290 if( left && ilen >= fill ) 291 { 292 memcpy( (void *) (ctx->buffer + left), 293 (void *) input, fill ); 294 md5_process( ctx, ctx->buffer ); 295 input += fill; 296 ilen -= fill; 297 left = 0; 298 } 299 300 while( ilen >= 64 ) 301 { 302 md5_process( ctx, input ); 303 input += 64; 304 ilen -= 64; 305 } 306 307 if( ilen > 0 ) 308 { 309 memcpy( (void *) (ctx->buffer + left), 310 (void *) input, ilen ); 311 } 312 } 313 314 static const unsigned char md5_padding[64] = 315 { 316 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 320 }; 321 322 /* 323 * MD5 final digest 324 */ 325 void md5_finish( md5_context *ctx, unsigned char output[16] ) 326 { 327 unsigned long last, padn; 328 unsigned long high, low; 329 unsigned char msglen[8]; 330 331 high = ( ctx->total[0] >> 29 ) 332 | ( ctx->total[1] << 3 ); 333 low = ( ctx->total[0] << 3 ); 334 335 PUT_ULONG_LE( low, msglen, 0 ); 336 PUT_ULONG_LE( high, msglen, 4 ); 337 338 last = ctx->total[0] & 0x3F; 339 padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); 340 341 md5_update( ctx, (unsigned char *) md5_padding, padn ); 342 md5_update( ctx, msglen, 8 ); 343 344 PUT_ULONG_LE( ctx->state[0], output, 0 ); 345 PUT_ULONG_LE( ctx->state[1], output, 4 ); 346 PUT_ULONG_LE( ctx->state[2], output, 8 ); 347 PUT_ULONG_LE( ctx->state[3], output, 12 ); 348 } 349 350 /* 351 * output = MD5( input buffer ) 352 */ 353 void md5( unsigned char *input, int ilen, unsigned char output[16] ) 354 { 355 md5_context ctx; 356 357 md5_starts( &ctx ); 358 md5_update( &ctx, input, ilen ); 359 md5_finish( &ctx, output ); 360 361 memset( &ctx, 0, sizeof( md5_context ) ); 362 } 363 364 unsigned int md5hash ( const void * input, int len, unsigned int /*seed*/ ) 365 { 366 unsigned int hash[4]; 367 368 md5((unsigned char *)input,len,(unsigned char *)hash); 369 370 //return hash[0] ^ hash[1] ^ hash[2] ^ hash[3]; 371 372 return hash[0]; 373 } 374 375 void md5_32 ( const void * key, int len, uint32_t /*seed*/, void * out ) 376 { 377 unsigned int hash[4]; 378 379 md5((unsigned char*)key,len,(unsigned char*)hash); 380 381 *(uint32_t*)out = hash[0]; 382 }