Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

md5.cpp

Go to the documentation of this file.
00001 //============================================== 00002 // copyright : (C) 2003-2005 by Will Stokes 00003 //============================================== 00004 // This program is free software; you can redistribute it 00005 // and/or modify it under the terms of the GNU General 00006 // Public License as published by the Free Software 00007 // Foundation; either version 2 of the License, or 00008 // (at your option) any later version. 00009 //============================================== 00010 00011 00012 // MD5.CC - source code for the C++/object oriented translation and 00013 // modification of MD5. 00014 00015 // Translation and modification (c) 1995 by Mordechai T. Abzug 00016 00017 // This translation/ modification is provided "as is," without express or 00018 // implied warranty of any kind. 00019 00020 // The translator/ modifier does not claim (1) that MD5 will do what you think 00021 // it does; (2) that this translation/ modification is accurate; or (3) that 00022 // this software is "merchantible." (Language for this disclaimer partially 00023 // copied from the disclaimer below). 00024 00025 /* based on: 00026 00027 MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm 00028 MDDRIVER.C - test driver for MD2, MD4 and MD5 00029 00030 00031 Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 00032 rights reserved. 00033 00034 License to copy and use this software is granted provided that it 00035 is identified as the "RSA Data Security, Inc. MD5 Message-Digest 00036 Algorithm" in all material mentioning or referencing this software 00037 or this function. 00038 00039 License is also granted to make and use derivative works provided 00040 that such works are identified as "derived from the RSA Data 00041 Security, Inc. MD5 Message-Digest Algorithm" in all material 00042 mentioning or referencing the derived work. 00043 00044 RSA Data Security, Inc. makes no representations concerning either 00045 the merchantability of this software or the suitability of this 00046 software for any particular purpose. It is provided "as is" 00047 without express or implied warranty of any kind. 00048 00049 These notices must be retained in any copies of any part of this 00050 documentation and/or software. 00051 00052 */ 00053 00054 #include <assert.h> 00055 #include <string> 00056 #include <iostream> 00057 #include <stdio.h> 00058 00059 #include "md5.h" 00060 00061 // MD5 simple initialization method 00062 MD5::MD5() 00063 { 00064 init(); 00065 } 00066 00067 // MD5 block update operation. Continues an MD5 message-digest 00068 // operation, processing another message block, and updating the 00069 // context. 00070 00071 void MD5::update (uint1 *input, uint4 input_length) { 00072 00073 uint4 input_index, buffer_index; 00074 uint4 buffer_space; // how much space is left in buffer 00075 00076 if (finalized){ // so we can't update! 00077 std::cerr << "MD5::update: Can't update a finalized digest!" << std::endl; 00078 return; 00079 } 00080 00081 // Compute number of bytes mod 64 00082 buffer_index = (unsigned int)((count[0] >> 3) & 0x3F); 00083 00084 // Update number of bits 00085 if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) ) 00086 count[1]++; 00087 00088 count[1] += ((uint4)input_length >> 29); 00089 00090 00091 buffer_space = 64 - buffer_index; // how much space is left in buffer 00092 00093 // Transform as many times as possible. 00094 if (input_length >= buffer_space) { // ie. we have enough to fill the buffer 00095 // fill the rest of the buffer and transform 00096 memcpy (buffer + buffer_index, input, buffer_space); 00097 transform (buffer); 00098 00099 // now, transform each 64-byte piece of the input, bypassing the buffer 00100 for (input_index = buffer_space; input_index + 63 < input_length; 00101 input_index += 64) 00102 transform (input+input_index); 00103 00104 buffer_index = 0; // so we can buffer remaining 00105 } 00106 else 00107 input_index=0; // so we can buffer the whole input 00108 00109 00110 // and here we do the buffering: 00111 memcpy(buffer+buffer_index, input+input_index, input_length-input_index); 00112 } 00113 00114 00115 00116 // MD5 update for files. 00117 // Like above, except that it works on files (and uses above as a primitive.) 00118 00119 void MD5::update(FILE *file){ 00120 00121 unsigned char buffer[1024]; 00122 int len; 00123 00124 while (true) 00125 { 00126 len=fread(buffer, 1, 1024, file); 00127 if(!len) 00128 { break; } 00129 00130 update(buffer, len); 00131 } 00132 00133 fclose (file); 00134 00135 } 00136 00137 00138 00139 00140 00141 00142 // MD5 update for istreams. 00143 // Like update for files; see above. 00144 00145 void MD5::update(std::istream& stream){ 00146 00147 unsigned char buffer[1024]; 00148 int len; 00149 00150 while (stream.good()){ 00151 stream.read((char*)buffer, 1024); // note that return value of read is unusable. 00152 len=stream.gcount(); 00153 update(buffer, len); 00154 } 00155 00156 } 00157 00158 00159 00160 00161 00162 00163 // MD5 update for ifstreams. 00164 // Like update for files; see above. 00165 00166 void MD5::update(std::ifstream& stream){ 00167 00168 unsigned char buffer[1024]; 00169 int len; 00170 00171 while (stream.good()){ 00172 stream.read((char*)buffer, 1024); // note that return value of read is unusable. 00173 len=stream.gcount(); 00174 update(buffer, len); 00175 } 00176 00177 } 00178 00179 00180 00181 00182 00183 00184 // MD5 finalization. Ends an MD5 message-digest operation, writing the 00185 // the message digest and zeroizing the context. 00186 00187 00188 void MD5::finalize (){ 00189 00190 unsigned char bits[8]; 00191 unsigned int index, padLen; 00192 static uint1 PADDING[64]={ 00193 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00194 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00195 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 00196 }; 00197 00198 if (finalized){ 00199 std::cerr << "MD5::finalize: Already finalized this digest!" << std::endl; 00200 return; 00201 } 00202 00203 // Save number of bits 00204 encode (bits, count, 8); 00205 00206 // Pad out to 56 mod 64. 00207 index = (uint4) ((count[0] >> 3) & 0x3f); 00208 padLen = (index < 56) ? (56 - index) : (120 - index); 00209 update (PADDING, padLen); 00210 00211 // Append length (before padding) 00212 update (bits, 8); 00213 00214 // Store state in digest 00215 encode (digest, state, 16); 00216 00217 // Zeroize sensitive information 00218 memset (buffer, 0, sizeof(*buffer)); 00219 00220 finalized=1; 00221 00222 } 00223 00224 00225 00226 00227 MD5::MD5(FILE *file){ 00228 00229 init(); // must be called be all constructors 00230 update(file); 00231 finalize (); 00232 } 00233 00234 00235 00236 00237 MD5::MD5(std::istream& stream){ 00238 00239 init(); // must called by all constructors 00240 update (stream); 00241 finalize(); 00242 } 00243 00244 00245 00246 MD5::MD5(std::ifstream& stream){ 00247 00248 init(); // must called by all constructors 00249 update (stream); 00250 finalize(); 00251 } 00252 00253 00254 00255 unsigned char *MD5::raw_digest(){ 00256 00257 uint1 *s = new uint1[16]; 00258 00259 if (!finalized){ 00260 std::cerr << "MD5::raw_digest: Can't get digest if you haven't "<< 00261 "finalized the digest!" << std::endl; 00262 return ( (unsigned char*) ""); 00263 } 00264 00265 memcpy(s, digest, 16); 00266 return s; 00267 } 00268 00269 00270 00271 QString MD5::hex_digest(){ 00272 00273 int i; 00274 char *s= new char[33]; 00275 00276 if (!finalized){ 00277 std::cerr << "MD5::hex_digest: Can't get digest if you haven't "<< 00278 "finalized the digest!" << std::endl; 00279 return ""; 00280 } 00281 00282 for (i=0; i<16; i++) 00283 sprintf(s+i*2, "%02x", digest[i]); 00284 00285 s[32]='\0'; 00286 00287 QString result(s); 00288 delete s; 00289 return result; 00290 } 00291 00292 00293 // PRIVATE METHODS: 00294 00295 00296 00297 void MD5::init(){ 00298 finalized=0; // we just started! 00299 00300 // Nothing counted, so count=0 00301 count[0] = 0; 00302 count[1] = 0; 00303 00304 // Load magic initialization constants. 00305 state[0] = 0x67452301; 00306 state[1] = 0xefcdab89; 00307 state[2] = 0x98badcfe; 00308 state[3] = 0x10325476; 00309 } 00310 00311 00312 00313 // Constants for MD5Transform routine. 00314 // Although we could use C++ style constants, defines are actually better, 00315 // since they let us easily evade scope clashes. 00316 00317 #define S11 7 00318 #define S12 12 00319 #define S13 17 00320 #define S14 22 00321 #define S21 5 00322 #define S22 9 00323 #define S23 14 00324 #define S24 20 00325 #define S31 4 00326 #define S32 11 00327 #define S33 16 00328 #define S34 23 00329 #define S41 6 00330 #define S42 10 00331 #define S43 15 00332 #define S44 21 00333 00334 00335 00336 00337 // MD5 basic transformation. Transforms state based on block. 00338 void MD5::transform (uint1 block[64]){ 00339 00340 uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; 00341 00342 decode (x, block, 64); 00343 00344 assert(!finalized); // not just a user error, since the method is private 00345 00346 /* Round 1 */ 00347 FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ 00348 FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ 00349 FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ 00350 FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ 00351 FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ 00352 FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ 00353 FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ 00354 FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ 00355 FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ 00356 FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ 00357 FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 00358 FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 00359 FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 00360 FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 00361 FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 00362 FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 00363 00364 /* Round 2 */ 00365 GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ 00366 GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ 00367 GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ 00368 GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ 00369 GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ 00370 GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ 00371 GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ 00372 GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ 00373 GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ 00374 GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ 00375 GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ 00376 GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ 00377 GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 00378 GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ 00379 GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ 00380 GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 00381 00382 /* Round 3 */ 00383 HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ 00384 HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ 00385 HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ 00386 HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ 00387 HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ 00388 HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ 00389 HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ 00390 HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ 00391 HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ 00392 HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ 00393 HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ 00394 HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ 00395 HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ 00396 HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ 00397 HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ 00398 HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ 00399 00400 /* Round 4 */ 00401 II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ 00402 II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ 00403 II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ 00404 II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ 00405 II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ 00406 II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ 00407 II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ 00408 II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ 00409 II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ 00410 II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ 00411 II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ 00412 II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ 00413 II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ 00414 II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ 00415 II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ 00416 II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ 00417 00418 state[0] += a; 00419 state[1] += b; 00420 state[2] += c; 00421 state[3] += d; 00422 00423 // Zeroize sensitive information. 00424 memset ( (uint1 *) x, 0, sizeof(x)); 00425 00426 } 00427 00428 00429 00430 // Encodes input (UINT4) into output (unsigned char). Assumes len is 00431 // a multiple of 4. 00432 void MD5::encode (uint1 *output, uint4 *input, uint4 len) { 00433 00434 unsigned int i, j; 00435 00436 for (i = 0, j = 0; j < len; i++, j += 4) { 00437 output[j] = (uint1) (input[i] & 0xff); 00438 output[j+1] = (uint1) ((input[i] >> 8) & 0xff); 00439 output[j+2] = (uint1) ((input[i] >> 16) & 0xff); 00440 output[j+3] = (uint1) ((input[i] >> 24) & 0xff); 00441 } 00442 } 00443 00444 00445 00446 00447 // Decodes input (unsigned char) into output (UINT4). Assumes len is 00448 // a multiple of 4. 00449 void MD5::decode (uint4 *output, uint1 *input, uint4 len){ 00450 00451 unsigned int i, j; 00452 00453 for (i = 0, j = 0; j < len; i++, j += 4) 00454 output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) | 00455 (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24); 00456 } 00457 00458 00459 00460 00461 00462 // Note: Replace "for loop" with standard memcpy if possible. 00463 void MD5::memcpy (uint1 *output, uint1 *input, uint4 len){ 00464 00465 unsigned int i; 00466 00467 for (i = 0; i < len; i++) 00468 output[i] = input[i]; 00469 } 00470 00471 00472 00473 // Note: Replace "for loop" with standard memset if possible. 00474 void MD5::memset (uint1 *output, uint1 value, uint4 len){ 00475 00476 unsigned int i; 00477 00478 for (i = 0; i < len; i++) 00479 output[i] = value; 00480 } 00481 00482 00483 00484 // ROTATE_LEFT rotates x left n bits. 00485 00486 inline unsigned int MD5::rotate_left (uint4 x, uint4 n){ 00487 return (x << n) | (x >> (32-n)) ; 00488 } 00489 00490 00491 00492 00493 // F, G, H and I are basic MD5 functions. 00494 00495 inline unsigned int MD5::F (uint4 x, uint4 y, uint4 z){ 00496 return (x & y) | (~x & z); 00497 } 00498 00499 inline unsigned int MD5::G (uint4 x, uint4 y, uint4 z){ 00500 return (x & z) | (y & ~z); 00501 } 00502 00503 inline unsigned int MD5::H (uint4 x, uint4 y, uint4 z){ 00504 return x ^ y ^ z; 00505 } 00506 00507 inline unsigned int MD5::I (uint4 x, uint4 y, uint4 z){ 00508 return y ^ (x | ~z); 00509 } 00510 00511 00512 00513 // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. 00514 // Rotation is separate from addition to prevent recomputation. 00515 00516 00517 inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 00518 uint4 s, uint4 ac){ 00519 a += F(b, c, d) + x + ac; 00520 a = rotate_left (a, s) +b; 00521 } 00522 00523 inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 00524 uint4 s, uint4 ac){ 00525 a += G(b, c, d) + x + ac; 00526 a = rotate_left (a, s) +b; 00527 } 00528 00529 inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 00530 uint4 s, uint4 ac){ 00531 a += H(b, c, d) + x + ac; 00532 a = rotate_left (a, s) +b; 00533 } 00534 00535 inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 00536 uint4 s, uint4 ac){ 00537 a += I(b, c, d) + x + ac; 00538 a = rotate_left (a, s) +b; 00539 } 00540 //-------------------------------------------------- 00541 //returns md5 for a given file 00542 QString getMD5(std::ifstream& stream) 00543 { 00544 MD5 obj( stream ); 00545 return obj.hex_digest(); 00546 } 00547 //-------------------------------------------------- 00548 //compares md5's for two files, returns true if they match 00549 bool filesMatch(std::ifstream& stream, QString oldMD5) 00550 { 00551 MD5 obj( stream ); 00552 return (obj.hex_digest() == oldMD5); 00553 } 00554 //--------------------------------------------------

Generated on Sun Mar 4 19:42:56 2007 for AlbumShaper by doxygen 1.3.7