MD5Checksum.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. #include "stdafx.h"
  2. #include "MD5Checksum.h"
  3. #include "MD5ChecksumDefines.h"
  4. extern HANDLE g_EventCheckMd5;
  5. #ifdef _DEBUG
  6. #undef THIS_FILE
  7. static char THIS_FILE[]=__FILE__;
  8. #define new DEBUG_NEW
  9. #endif
  10. /*****************************************************************************************
  11. *****************************************************************************************/
  12. BYTE CMD5Checksum::GetMD5(LPCTSTR sFilePath, CString &sMd5)
  13. {
  14. try
  15. {
  16. CFile file;
  17. if(file.Open(sFilePath,CFile::modeRead)==0)
  18. return 1;
  19. CMD5Checksum MD5Checksum; //checksum object
  20. int nLength = 0; //number of bytes read from the file
  21. const int nBufferSize = 500*1024; //checksum the file in blocks of 1024 bytes
  22. BYTE Buffer[nBufferSize]; //buffer for data read from the file
  23. BYTE btRet = 0;
  24. //checksum the file in blocks of 1024 bytes
  25. while ((nLength = file.Read( Buffer, nBufferSize )) > 0 )
  26. {
  27. if(WaitForSingleObject(g_EventCheckMd5,0) == WAIT_OBJECT_0)
  28. {
  29. btRet = 2;
  30. break;
  31. }
  32. MD5Checksum.Update( Buffer, nLength );
  33. }
  34. file.Close();
  35. //finalise the checksum and return it
  36. sMd5 = MD5Checksum.Final();
  37. return btRet;
  38. }
  39. //report any file exceptions in debug mode only
  40. catch (CFileException* e )
  41. {
  42. TRACE0("CMD5Checksum::GetMD5: CFileException caught");
  43. throw e;
  44. }
  45. return 1;
  46. }
  47. /*****************************************************************************************
  48. FUNCTION: CMD5Checksum::RotateLeft
  49. DETAILS: private
  50. DESCRIPTION: Rotates the bits in a 32 bit DWORD left by a specified amount
  51. RETURNS: The rotated DWORD
  52. ARGUMENTS: DWORD x : the value to be rotated
  53. int n : the number of bits to rotate by
  54. *****************************************************************************************/
  55. DWORD CMD5Checksum::RotateLeft(DWORD x, int n)
  56. {
  57. //check that DWORD is 4 bytes long - true in Visual C++ 6 and 32 bit Windows
  58. ASSERT( sizeof(x) == 4 );
  59. //rotate and return x
  60. return (x << n) | (x >> (32-n));
  61. }
  62. /*****************************************************************************************
  63. FUNCTION: CMD5Checksum::FF
  64. DETAILS: protected
  65. DESCRIPTION: Implementation of basic MD5 transformation algorithm
  66. RETURNS: none
  67. ARGUMENTS: DWORD &A, B, C, D : Current (partial) checksum
  68. DWORD X : Input data
  69. DWORD S : MD5_SXX Transformation constant
  70. DWORD T : MD5_TXX Transformation constant
  71. NOTES: None
  72. *****************************************************************************************/
  73. void CMD5Checksum::FF( DWORD& A, DWORD B, DWORD C, DWORD D, DWORD X, DWORD S, DWORD T)
  74. {
  75. DWORD F = (B & C) | (~B & D);
  76. A += F + X + T;
  77. A = RotateLeft(A, S);
  78. A += B;
  79. }
  80. /*****************************************************************************************
  81. FUNCTION: CMD5Checksum::GG
  82. DETAILS: protected
  83. DESCRIPTION: Implementation of basic MD5 transformation algorithm
  84. RETURNS: none
  85. ARGUMENTS: DWORD &A, B, C, D : Current (partial) checksum
  86. DWORD X : Input data
  87. DWORD S : MD5_SXX Transformation constant
  88. DWORD T : MD5_TXX Transformation constant
  89. NOTES: None
  90. *****************************************************************************************/
  91. void CMD5Checksum::GG( DWORD& A, DWORD B, DWORD C, DWORD D, DWORD X, DWORD S, DWORD T)
  92. {
  93. DWORD G = (B & D) | (C & ~D);
  94. A += G + X + T;
  95. A = RotateLeft(A, S);
  96. A += B;
  97. }
  98. /*****************************************************************************************
  99. FUNCTION: CMD5Checksum::HH
  100. DETAILS: protected
  101. DESCRIPTION: Implementation of basic MD5 transformation algorithm
  102. RETURNS: none
  103. ARGUMENTS: DWORD &A, B, C, D : Current (partial) checksum
  104. DWORD X : Input data
  105. DWORD S : MD5_SXX Transformation constant
  106. DWORD T : MD5_TXX Transformation constant
  107. NOTES: None
  108. *****************************************************************************************/
  109. void CMD5Checksum::HH( DWORD& A, DWORD B, DWORD C, DWORD D, DWORD X, DWORD S, DWORD T)
  110. {
  111. DWORD H = (B ^ C ^ D);
  112. A += H + X + T;
  113. A = RotateLeft(A, S);
  114. A += B;
  115. }
  116. /*****************************************************************************************
  117. FUNCTION: CMD5Checksum::II
  118. DETAILS: protected
  119. DESCRIPTION: Implementation of basic MD5 transformation algorithm
  120. RETURNS: none
  121. ARGUMENTS: DWORD &A, B, C, D : Current (partial) checksum
  122. DWORD X : Input data
  123. DWORD S : MD5_SXX Transformation constant
  124. DWORD T : MD5_TXX Transformation constant
  125. NOTES: None
  126. *****************************************************************************************/
  127. void CMD5Checksum::II( DWORD& A, DWORD B, DWORD C, DWORD D, DWORD X, DWORD S, DWORD T)
  128. {
  129. DWORD I = (C ^ (B | ~D));
  130. A += I + X + T;
  131. A = RotateLeft(A, S);
  132. A += B;
  133. }
  134. /*****************************************************************************************
  135. FUNCTION: CMD5Checksum::ByteToDWord
  136. DETAILS: private
  137. DESCRIPTION: Transfers the data in an 8 bit array to a 32 bit array
  138. RETURNS: void
  139. ARGUMENTS: DWORD* Output : the 32 bit (unsigned long) destination array
  140. BYTE* Input : the 8 bit (unsigned char) source array
  141. UINT nLength : the number of 8 bit data items in the source array
  142. NOTES: Four BYTES from the input array are transferred to each DWORD entry
  143. of the output array. The first BYTE is transferred to the bits (0-7)
  144. of the output DWORD, the second BYTE to bits 8-15 etc.
  145. The algorithm assumes that the input array is a multiple of 4 bytes long
  146. so that there is a perfect fit into the array of 32 bit words.
  147. *****************************************************************************************/
  148. void CMD5Checksum::ByteToDWord(DWORD* Output, BYTE* Input, UINT nLength)
  149. {
  150. //entry invariants
  151. ASSERT( nLength % 4 == 0 );
  152. ASSERT( AfxIsValidAddress(Output, nLength/4, TRUE) );
  153. ASSERT( AfxIsValidAddress(Input, nLength, FALSE) );
  154. //initialisations
  155. UINT i=0; //index to Output array
  156. UINT j=0; //index to Input array
  157. //transfer the data by shifting and copying
  158. for ( ; j < nLength; i++, j += 4)
  159. {
  160. Output[i] = (ULONG)Input[j] |
  161. (ULONG)Input[j+1] << 8 |
  162. (ULONG)Input[j+2] << 16 |
  163. (ULONG)Input[j+3] << 24;
  164. }
  165. }
  166. /*****************************************************************************************
  167. FUNCTION: CMD5Checksum::Transform
  168. DETAILS: protected
  169. DESCRIPTION: MD5 basic transformation algorithm; transforms 'm_lMD5'
  170. RETURNS: void
  171. ARGUMENTS: BYTE Block[64]
  172. NOTES: An MD5 checksum is calculated by four rounds of 'Transformation'.
  173. The MD5 checksum currently held in m_lMD5 is merged by the
  174. transformation process with data passed in 'Block'.
  175. *****************************************************************************************/
  176. void CMD5Checksum::Transform(BYTE Block[64])
  177. {
  178. //initialise local data with current checksum
  179. ULONG a = m_lMD5[0];
  180. ULONG b = m_lMD5[1];
  181. ULONG c = m_lMD5[2];
  182. ULONG d = m_lMD5[3];
  183. //copy BYTES from input 'Block' to an array of ULONGS 'X'
  184. ULONG X[16];
  185. ByteToDWord( X, Block, 64 );
  186. //Perform Round 1 of the transformation
  187. FF (a, b, c, d, X[ 0], MD5_S11, MD5_T01);
  188. FF (d, a, b, c, X[ 1], MD5_S12, MD5_T02);
  189. FF (c, d, a, b, X[ 2], MD5_S13, MD5_T03);
  190. FF (b, c, d, a, X[ 3], MD5_S14, MD5_T04);
  191. FF (a, b, c, d, X[ 4], MD5_S11, MD5_T05);
  192. FF (d, a, b, c, X[ 5], MD5_S12, MD5_T06);
  193. FF (c, d, a, b, X[ 6], MD5_S13, MD5_T07);
  194. FF (b, c, d, a, X[ 7], MD5_S14, MD5_T08);
  195. FF (a, b, c, d, X[ 8], MD5_S11, MD5_T09);
  196. FF (d, a, b, c, X[ 9], MD5_S12, MD5_T10);
  197. FF (c, d, a, b, X[10], MD5_S13, MD5_T11);
  198. FF (b, c, d, a, X[11], MD5_S14, MD5_T12);
  199. FF (a, b, c, d, X[12], MD5_S11, MD5_T13);
  200. FF (d, a, b, c, X[13], MD5_S12, MD5_T14);
  201. FF (c, d, a, b, X[14], MD5_S13, MD5_T15);
  202. FF (b, c, d, a, X[15], MD5_S14, MD5_T16);
  203. //Perform Round 2 of the transformation
  204. GG (a, b, c, d, X[ 1], MD5_S21, MD5_T17);
  205. GG (d, a, b, c, X[ 6], MD5_S22, MD5_T18);
  206. GG (c, d, a, b, X[11], MD5_S23, MD5_T19);
  207. GG (b, c, d, a, X[ 0], MD5_S24, MD5_T20);
  208. GG (a, b, c, d, X[ 5], MD5_S21, MD5_T21);
  209. GG (d, a, b, c, X[10], MD5_S22, MD5_T22);
  210. GG (c, d, a, b, X[15], MD5_S23, MD5_T23);
  211. GG (b, c, d, a, X[ 4], MD5_S24, MD5_T24);
  212. GG (a, b, c, d, X[ 9], MD5_S21, MD5_T25);
  213. GG (d, a, b, c, X[14], MD5_S22, MD5_T26);
  214. GG (c, d, a, b, X[ 3], MD5_S23, MD5_T27);
  215. GG (b, c, d, a, X[ 8], MD5_S24, MD5_T28);
  216. GG (a, b, c, d, X[13], MD5_S21, MD5_T29);
  217. GG (d, a, b, c, X[ 2], MD5_S22, MD5_T30);
  218. GG (c, d, a, b, X[ 7], MD5_S23, MD5_T31);
  219. GG (b, c, d, a, X[12], MD5_S24, MD5_T32);
  220. //Perform Round 3 of the transformation
  221. HH (a, b, c, d, X[ 5], MD5_S31, MD5_T33);
  222. HH (d, a, b, c, X[ 8], MD5_S32, MD5_T34);
  223. HH (c, d, a, b, X[11], MD5_S33, MD5_T35);
  224. HH (b, c, d, a, X[14], MD5_S34, MD5_T36);
  225. HH (a, b, c, d, X[ 1], MD5_S31, MD5_T37);
  226. HH (d, a, b, c, X[ 4], MD5_S32, MD5_T38);
  227. HH (c, d, a, b, X[ 7], MD5_S33, MD5_T39);
  228. HH (b, c, d, a, X[10], MD5_S34, MD5_T40);
  229. HH (a, b, c, d, X[13], MD5_S31, MD5_T41);
  230. HH (d, a, b, c, X[ 0], MD5_S32, MD5_T42);
  231. HH (c, d, a, b, X[ 3], MD5_S33, MD5_T43);
  232. HH (b, c, d, a, X[ 6], MD5_S34, MD5_T44);
  233. HH (a, b, c, d, X[ 9], MD5_S31, MD5_T45);
  234. HH (d, a, b, c, X[12], MD5_S32, MD5_T46);
  235. HH (c, d, a, b, X[15], MD5_S33, MD5_T47);
  236. HH (b, c, d, a, X[ 2], MD5_S34, MD5_T48);
  237. //Perform Round 4 of the transformation
  238. II (a, b, c, d, X[ 0], MD5_S41, MD5_T49);
  239. II (d, a, b, c, X[ 7], MD5_S42, MD5_T50);
  240. II (c, d, a, b, X[14], MD5_S43, MD5_T51);
  241. II (b, c, d, a, X[ 5], MD5_S44, MD5_T52);
  242. II (a, b, c, d, X[12], MD5_S41, MD5_T53);
  243. II (d, a, b, c, X[ 3], MD5_S42, MD5_T54);
  244. II (c, d, a, b, X[10], MD5_S43, MD5_T55);
  245. II (b, c, d, a, X[ 1], MD5_S44, MD5_T56);
  246. II (a, b, c, d, X[ 8], MD5_S41, MD5_T57);
  247. II (d, a, b, c, X[15], MD5_S42, MD5_T58);
  248. II (c, d, a, b, X[ 6], MD5_S43, MD5_T59);
  249. II (b, c, d, a, X[13], MD5_S44, MD5_T60);
  250. II (a, b, c, d, X[ 4], MD5_S41, MD5_T61);
  251. II (d, a, b, c, X[11], MD5_S42, MD5_T62);
  252. II (c, d, a, b, X[ 2], MD5_S43, MD5_T63);
  253. II (b, c, d, a, X[ 9], MD5_S44, MD5_T64);
  254. //add the transformed values to the current checksum
  255. m_lMD5[0] += a;
  256. m_lMD5[1] += b;
  257. m_lMD5[2] += c;
  258. m_lMD5[3] += d;
  259. }
  260. /*****************************************************************************************
  261. CONSTRUCTOR: CMD5Checksum
  262. DESCRIPTION: Initialises member data
  263. ARGUMENTS: None
  264. NOTES: None
  265. *****************************************************************************************/
  266. CMD5Checksum::CMD5Checksum()
  267. {
  268. // zero members
  269. memset( m_lpszBuffer, 0, 64 );
  270. m_nCount[0] = m_nCount[1] = 0;
  271. // Load magic state initialization constants
  272. m_lMD5[0] = MD5_INIT_STATE_0;
  273. m_lMD5[1] = MD5_INIT_STATE_1;
  274. m_lMD5[2] = MD5_INIT_STATE_2;
  275. m_lMD5[3] = MD5_INIT_STATE_3;
  276. }
  277. /*****************************************************************************************
  278. FUNCTION: CMD5Checksum::DWordToByte
  279. DETAILS: private
  280. DESCRIPTION: Transfers the data in an 32 bit array to a 8 bit array
  281. RETURNS: void
  282. ARGUMENTS: BYTE* Output : the 8 bit destination array
  283. DWORD* Input : the 32 bit source array
  284. UINT nLength : the number of 8 bit data items in the source array
  285. NOTES: One DWORD from the input array is transferred into four BYTES
  286. in the output array. The first (0-7) bits of the first DWORD are
  287. transferred to the first output BYTE, bits bits 8-15 are transferred from
  288. the second BYTE etc.
  289. The algorithm assumes that the output array is a multiple of 4 bytes long
  290. so that there is a perfect fit of 8 bit BYTES into the 32 bit DWORDs.
  291. *****************************************************************************************/
  292. void CMD5Checksum::DWordToByte(BYTE* Output, DWORD* Input, UINT nLength )
  293. {
  294. //entry invariants
  295. ASSERT( nLength % 4 == 0 );
  296. ASSERT( AfxIsValidAddress(Output, nLength, TRUE) );
  297. ASSERT( AfxIsValidAddress(Input, nLength/4, FALSE) );
  298. //transfer the data by shifting and copying
  299. UINT i = 0;
  300. UINT j = 0;
  301. for ( ; j < nLength; i++, j += 4)
  302. {
  303. Output[j] = (UCHAR)(Input[i] & 0xff );
  304. Output[j+1] = (UCHAR)((Input[i] >> 8) & 0xff);
  305. Output[j+2] = (UCHAR)((Input[i] >> 16) & 0xff);
  306. Output[j+3] = (UCHAR)((Input[i] >> 24) & 0xff);
  307. }
  308. }
  309. /*****************************************************************************************
  310. FUNCTION: CMD5Checksum::Final
  311. DETAILS: protected
  312. DESCRIPTION: Implementation of main MD5 checksum algorithm; ends the checksum calculation.
  313. RETURNS: CString : the final hexadecimal MD5 checksum result
  314. ARGUMENTS: None
  315. NOTES: Performs the final MD5 checksum calculation ('Update' does most of the work,
  316. this function just finishes the calculation.)
  317. *****************************************************************************************/
  318. CString CMD5Checksum::Final()
  319. {
  320. //Save number of bits
  321. BYTE Bits[8];
  322. DWordToByte( Bits, m_nCount, 8 );
  323. //Pad out to 56 mod 64.
  324. UINT nIndex = (UINT)((m_nCount[0] >> 3) & 0x3f);
  325. UINT nPadLen = (nIndex < 56) ? (56 - nIndex) : (120 - nIndex);
  326. Update( PADDING, nPadLen );
  327. //Append length (before padding)
  328. Update( Bits, 8 );
  329. //Store final state in 'lpszMD5'
  330. const int nMD5Size = 16;
  331. unsigned char lpszMD5[ nMD5Size ];
  332. DWordToByte( lpszMD5, m_lMD5, nMD5Size );
  333. //Convert the hexadecimal checksum to a CString
  334. CString strMD5;
  335. for ( int i=0; i < nMD5Size; i++)
  336. {
  337. CString Str;
  338. if (lpszMD5[i] == 0)
  339. {
  340. Str = CString("00");
  341. }
  342. else if (lpszMD5[i] <= 15)
  343. {
  344. Str.Format(_T("0%X"),lpszMD5[i]);
  345. }
  346. else
  347. {
  348. Str.Format(_T("%X"),lpszMD5[i]);
  349. }
  350. ASSERT( Str.GetLength() == 2 );
  351. strMD5 += Str;
  352. }
  353. ASSERT( strMD5.GetLength() == 32 );
  354. /*
  355. char szMd5[MAX_DESC] = {0};
  356. sprintf_s(szMd5, sizeof(szMd5), "%s", strMD5.GetBuffer());
  357. strMD5.ReleaseBuffer();
  358. return szMd5;
  359. */
  360. return strMD5;
  361. }
  362. /*****************************************************************************************
  363. FUNCTION: CMD5Checksum::Update
  364. DETAILS: protected
  365. DESCRIPTION: Implementation of main MD5 checksum algorithm
  366. RETURNS: void
  367. ARGUMENTS: BYTE* Input : input block
  368. UINT nInputLen : length of input block
  369. NOTES: Computes the partial MD5 checksum for 'nInputLen' bytes of data in 'Input'
  370. *****************************************************************************************/
  371. void CMD5Checksum::Update( BYTE* Input, ULONG nInputLen )
  372. {
  373. //Compute number of bytes mod 64
  374. UINT nIndex = (UINT)((m_nCount[0] >> 3) & 0x3F);
  375. //Update number of bits
  376. if ( ( m_nCount[0] += nInputLen << 3 ) < ( nInputLen << 3) )
  377. {
  378. m_nCount[1]++;
  379. }
  380. m_nCount[1] += (nInputLen >> 29);
  381. //Transform as many times as possible.
  382. UINT i=0;
  383. UINT nPartLen = 64 - nIndex;
  384. if (nInputLen >= nPartLen)
  385. {
  386. memcpy( &m_lpszBuffer[nIndex], Input, nPartLen );
  387. Transform( m_lpszBuffer );
  388. for (i = nPartLen; i + 63 < nInputLen; i += 64)
  389. {
  390. Transform( &Input[i] );
  391. }
  392. nIndex = 0;
  393. }
  394. else
  395. {
  396. i = 0;
  397. }
  398. // Buffer remaining input
  399. memcpy( &m_lpszBuffer[nIndex], &Input[i], nInputLen-i);
  400. }
  401. CString CMD5Checksum::GetMD5OfString(CString strString)
  402. {
  403. try
  404. {
  405. CMD5Checksum MD5Checksum; //checksum object
  406. int nLength = strString.GetLength(); //number of bytes read from the file
  407. //const int nBufferSize = 1024; //checksum the file in blocks of 1024 bytes
  408. BYTE *Buffer; //buffer for data read from the file
  409. Buffer=(BYTE*)(strString.GetBuffer(nLength));
  410. //checksum the file in blocks of 1024 bytes
  411. //while ((nLength = File.Read( Buffer, nBufferSize )) > 0 )
  412. //{
  413. MD5Checksum.Update( Buffer, nLength );
  414. //}
  415. //finalise the checksum and return it
  416. return MD5Checksum.Final();
  417. }
  418. //report any file exceptions in debug mode only
  419. catch (CFileException* e )
  420. {
  421. TRACE0("CMD5Checksum::GetMD5: CFileException caught");
  422. throw e;
  423. }
  424. }