1 // MD5Checksum.cpp: implementation of the MD5Checksum class.
2 //
3 //////////////////////////////////////////////////////////////////////
4
5
6 /****************************************************************************************
7 This software is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
8 Incorporation of this statement is a condition of use; please see the RSA
9 Data Security Inc copyright notice below:-
10
11 Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
12 rights reserved.
13
14 RSA Data Security, Inc. makes no representations concerning either
15 the merchantability of this software or the suitability of this
16 software for any particular purpose. It is provided "as is"
17 without express or implied warranty of any kind.
18
19 These notices must be retained in any copies of any part of this
20 documentation and/or software.
21
22 Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
23 rights reserved.
24 License to copy and use this software is granted provided that it
25 is identified as the "RSA Data Security, Inc. MD5 Message-Digest
26 Algorithm" in all material mentioning or referencing this software
27 or this function.
28 License is also granted to make and use derivative works provided
29 that such works are identified as "derived from the RSA Data
30 Security, Inc. MD5 Message-Digest Algorithm" in all material
31 mentioning or referencing the derived work.
32 RSA Data Security, Inc. makes no representations concerning either
33 the merchantability of this software or the suitability of this
34 software for any particular purpose. It is provided "as is"
35 without express or implied warranty of any kind.
36
37 These notices must be retained in any copies of any part of this
38 documentation and/or software.
39 *****************************************************************************************/
40
41 /****************************************************************************************
42 This implementation of the RSA MD5 Algorithm was written by Langfine Ltd
43 (www.langfine.com).
44
45 Langfine Ltd makes no representations concerning either
46 the merchantability of this software or the suitability of this
47 software for any particular purpose. It is provided "as is"
48 without express or implied warranty of any kind.
49
50 In addition to the above, Langfine make no warrant or assurances regarding the
51 accuracy of this implementation of the MD5 checksum algorithm nor any assurances regarding
52 its suitability for any purposes.
53
54 This implementation may be used freely provided that Langfine is credited
55 in a copyright or similar notices (eg, RSA MD5 Algorithm implemented by Langfine
56 Ltd.) and provided that the RSA Data Security notices are complied with.
57 */
58 #include "MD5Checksum.h"
59 #include "MD5ChecksumDefines.h"
60
61
62
63 /*****************************************************************************************
64 FUNCTION: CMD5Checksum::GetMD5
65 DETAILS: static, public
66 DESCRIPTION: Gets the MD5 checksum for a specified file
67 RETURNS: CString : the hexadecimal MD5 checksum for the specified file
68 ARGUMENTS: CString& strFilePath : the full pathname of the specified file
69 NOTES: Provides an interface to the CMD5Checksum class. 'strFilePath' name should
70 hold the full pathname of the file, eg C:\My Documents\Arcticle.txt.
71 NB. If any problems occur with opening or reading this file, a CFileException
72 will be thrown; callers of this function should be ready to catch this
73 exception.
74 *****************************************************************************************/
GetMD5(const tstring & strFilePath,long long nLength)75 tstring CMD5Checksum::GetMD5(const tstring &strFilePath, long long nLength)
76 {
77 //open the file as a binary file in readonly mode, denying write access
78 FILE *file = NULL;
79 file = fopen(strFilePath.c_str(), _T("rb"));
80 if (!file)
81 {
82 return _T("");
83 }
84 //the file has been successfully opened, so now get and return its checksum
85 tstring strRet;
86 strRet = GetMD5(file, nLength);
87 fclose(file);
88 return strRet;
89 }
90
_GetMD5(const tstring & strFilePath,long long nLength)91 unsigned char *CMD5Checksum::_GetMD5(const tstring &strFilePath, long long nLength)
92 {
93 //open the file as a binary file in readonly mode, denying write access
94 FILE *file = NULL;
95 file = fopen(strFilePath.c_str(), _T("rb"));
96 if (!file)
97 {
98 return NULL;
99 }
100
101 //the file has been successfully opened, so now get and return its checksum
102 unsigned char *pRet;
103 pRet = _GetMD5(file, nLength);
104 fclose(file);
105 return pRet;
106 }
107
108 /*****************************************************************************************
109 FUNCTION: CMD5Checksum::GetMD5
110 DETAILS: static, public
111 DESCRIPTION: Gets the MD5 checksum for a specified file
112 RETURNS: CString : the hexadecimal MD5 checksum for the specified file
113 ARGUMENTS: CFile& File : the specified file
114 NOTES: Provides an interface to the CMD5Checksum class. 'File' should be open in
115 binary readonly mode before calling this function.
116 NB. Callers of this function should be ready to catch any CFileException
117 thrown by the CFile functions
118 *****************************************************************************************/
GetMD5(FILE * File,long long nLength)119 tstring CMD5Checksum::GetMD5(FILE *File, long long nLength)
120 {
121 try
122 {
123 CMD5Checksum MD5Checksum; //checksum object
124 int nCount = 0; //number of bytes read from the file
125 const int nBufferSize = 1024; //checksum the file in blocks of 1024 bytes
126 BYTE Buffer[nBufferSize]; //buffer for data read from the file
127
128 long long uiFileSize = nLength;
129 //fseeko(File,0,SEEK_END);
130 //uiFileSize = ftello(File);
131 fseeko(File, 0, SEEK_SET);
132 //checksum the file in blocks of 1024 bytes
133 while (uiFileSize > 0)
134 {
135 nCount = (uiFileSize >= nBufferSize) ? nBufferSize : uiFileSize;
136 nCount = fread(Buffer, 1, nCount, File);
137 uiFileSize -= nCount;
138 MD5Checksum.Update(Buffer, nCount);
139 }
140 //finalise the checksum and return it
141 return MD5Checksum.Final();
142 }
143
144 //report any file exceptions in debug mode only
145 catch (...)
146 {
147 return _T("");
148 }
149 }
150
_GetMD5(FILE * File,long long nLength)151 unsigned char *CMD5Checksum::_GetMD5(FILE *File, long long nLength)
152 {
153 try
154 {
155 CMD5Checksum MD5Checksum; //checksum object
156 int nCount = 0; //number of bytes read from the file
157 const int nBufferSize = 1024; //checksum the file in blocks of 1024 bytes
158 BYTE Buffer[nBufferSize]; //buffer for data read from the file
159
160 long long uiFileSize = nLength;
161 // fseeko(File,0,SEEK_END);
162 // uiFileSize = ftello(File);
163 fseeko(File, 0, SEEK_SET);
164 //checksum the file in blocks of 1024 bytes
165 while (uiFileSize > 0)
166 {
167 nCount = (uiFileSize >= nBufferSize) ? nBufferSize : uiFileSize;
168 nCount = fread(Buffer, 1, nCount, File);
169 uiFileSize -= nCount;
170 MD5Checksum.Update(Buffer, nCount);
171 }
172
173 //finalise the checksum and return it
174 return MD5Checksum.FinalChar();
175 }
176
177 //report any file exceptions in debug mode only
178 catch (...)
179 {
180 return NULL;
181 }
182 }
183
184 /*****************************************************************************************
185 FUNCTION: CMD5Checksum::GetMD5
186 DETAILS: static, public
187 DESCRIPTION: Gets the MD5 checksum for data in a BYTE array
188 RETURNS: CString : the hexadecimal MD5 checksum for the specified data
189 ARGUMENTS: BYTE* pBuf : pointer to the BYTE array
190 UINT nLength : number of BYTEs of data to be checksumed
191 NOTES: Provides an interface to the CMD5Checksum class. Any data that can
192 be cast to a BYTE array of known length can be checksummed by this
193 function. Typically, CString and char arrays will be checksumed,
194 although this function can be used to check the integrity of any BYTE array.
195 A buffer of zero length can be checksummed; all buffers of zero length
196 will return the same checksum.
197 *****************************************************************************************/
GetMD5(BYTE * pBuf,UINT nLength)198 tstring CMD5Checksum::GetMD5(BYTE *pBuf, UINT nLength)
199 {
200
201 //calculate and return the checksum
202 CMD5Checksum MD5Checksum;
203 MD5Checksum.Update(pBuf, nLength);
204 return MD5Checksum.Final();
205 }
206
_GetMD5(BYTE * pBuf,UINT nLength)207 unsigned char *CMD5Checksum::_GetMD5(BYTE *pBuf, UINT nLength)
208 {
209 //calculate and return the checksum
210 CMD5Checksum MD5Checksum;
211 MD5Checksum.Update(pBuf, nLength);
212 return MD5Checksum.FinalChar();
213 }
214
215 /*****************************************************************************************
216 FUNCTION: CMD5Checksum::RotateLeft
217 DETAILS: private
218 DESCRIPTION: Rotates the bits in a 32 bit DWORD left by a specified amount
219 RETURNS: The rotated DWORD
220 ARGUMENTS: DWORD x : the value to be rotated
221 int n : the number of bits to rotate by
222 *****************************************************************************************/
RotateLeft(DWORD x,int n)223 DWORD CMD5Checksum::RotateLeft(DWORD x, int n)
224 {
225 //check that DWORD is 4 bytes long - true in Visual C++ 6 and 32 bit Windows
226 assert(sizeof(x) == 4);
227
228 //rotate and return x
229 return (x << n) | (x >> (32 - n));
230 }
231
232
233 /*****************************************************************************************
234 FUNCTION: CMD5Checksum::FF
235 DETAILS: protected
236 DESCRIPTION: Implementation of basic MD5 transformation algorithm
237 RETURNS: none
238 ARGUMENTS: DWORD &A, B, C, D : Current (partial) checksum
239 DWORD X : Input data
240 DWORD S : MD5_SXX Transformation constant
241 DWORD T : MD5_TXX Transformation constant
242 NOTES: None
243 *****************************************************************************************/
FF(DWORD & A,DWORD B,DWORD C,DWORD D,DWORD X,DWORD S,DWORD T)244 void CMD5Checksum::FF(DWORD &A, DWORD B, DWORD C, DWORD D, DWORD X, DWORD S, DWORD T)
245 {
246 DWORD F = (B & C) | (~B & D);
247 A += F + X + T;
248 A = RotateLeft(A, S);
249 A += B;
250 }
251
252
253 /*****************************************************************************************
254 FUNCTION: CMD5Checksum::GG
255 DETAILS: protected
256 DESCRIPTION: Implementation of basic MD5 transformation algorithm
257 RETURNS: none
258 ARGUMENTS: DWORD &A, B, C, D : Current (partial) checksum
259 DWORD X : Input data
260 DWORD S : MD5_SXX Transformation constant
261 DWORD T : MD5_TXX Transformation constant
262 NOTES: None
263 *****************************************************************************************/
GG(DWORD & A,DWORD B,DWORD C,DWORD D,DWORD X,DWORD S,DWORD T)264 void CMD5Checksum::GG(DWORD &A, DWORD B, DWORD C, DWORD D, DWORD X, DWORD S, DWORD T)
265 {
266 DWORD G = (B & D) | (C & ~D);
267 A += G + X + T;
268 A = RotateLeft(A, S);
269 A += B;
270 }
271
272
273 /*****************************************************************************************
274 FUNCTION: CMD5Checksum::HH
275 DETAILS: protected
276 DESCRIPTION: Implementation of basic MD5 transformation algorithm
277 RETURNS: none
278 ARGUMENTS: DWORD &A, B, C, D : Current (partial) checksum
279 DWORD X : Input data
280 DWORD S : MD5_SXX Transformation constant
281 DWORD T : MD5_TXX Transformation constant
282 NOTES: None
283 *****************************************************************************************/
HH(DWORD & A,DWORD B,DWORD C,DWORD D,DWORD X,DWORD S,DWORD T)284 void CMD5Checksum::HH(DWORD &A, DWORD B, DWORD C, DWORD D, DWORD X, DWORD S, DWORD T)
285 {
286 DWORD H = (B ^ C ^ D);
287 A += H + X + T;
288 A = RotateLeft(A, S);
289 A += B;
290 }
291
292
293 /*****************************************************************************************
294 FUNCTION: CMD5Checksum::II
295 DETAILS: protected
296 DESCRIPTION: Implementation of basic MD5 transformation algorithm
297 RETURNS: none
298 ARGUMENTS: DWORD &A, B, C, D : Current (partial) checksum
299 DWORD X : Input data
300 DWORD S : MD5_SXX Transformation constant
301 DWORD T : MD5_TXX Transformation constant
302 NOTES: None
303 *****************************************************************************************/
II(DWORD & A,DWORD B,DWORD C,DWORD D,DWORD X,DWORD S,DWORD T)304 void CMD5Checksum::II(DWORD &A, DWORD B, DWORD C, DWORD D, DWORD X, DWORD S, DWORD T)
305 {
306 DWORD I = (C ^ (B | ~D));
307 A += I + X + T;
308 A = RotateLeft(A, S);
309 A += B;
310 }
311
312
313 /*****************************************************************************************
314 FUNCTION: CMD5Checksum::ByteToDWord
315 DETAILS: private
316 DESCRIPTION: Transfers the data in an 8 bit array to a 32 bit array
317 RETURNS: void
318 ARGUMENTS: DWORD* Output : the 32 bit (unsigned long) destination array
319 BYTE* Input : the 8 bit (unsigned char) source array
320 UINT nLength : the number of 8 bit data items in the source array
321 NOTES: Four BYTES from the input array are transferred to each DWORD entry
322 of the output array. The first BYTE is transferred to the bits (0-7)
323 of the output DWORD, the second BYTE to bits 8-15 etc.
324 The algorithm assumes that the input array is a multiple of 4 bytes long
325 so that there is a perfect fit into the array of 32 bit words.
326 *****************************************************************************************/
ByteToDWord(DWORD * Output,BYTE * Input,UINT nLength)327 void CMD5Checksum::ByteToDWord(DWORD *Output, BYTE *Input, UINT nLength)
328 {
329
330 //initialisations
331 UINT i = 0; //index to Output array
332 UINT j = 0; //index to Input array
333
334 //transfer the data by shifting and copying
335 for (; j < nLength; i++, j += 4)
336 {
337 Output[i] = (UINT)Input[j] |
338 (UINT)Input[j + 1] << 8 |
339 (UINT)Input[j + 2] << 16 |
340 (UINT)Input[j + 3] << 24;
341 }
342 }
343
344 /*****************************************************************************************
345 FUNCTION: CMD5Checksum::Transform
346 DETAILS: protected
347 DESCRIPTION: MD5 basic transformation algorithm; transforms 'm_lMD5'
348 RETURNS: void
349 ARGUMENTS: BYTE Block[64]
350 NOTES: An MD5 checksum is calculated by four rounds of 'Transformation'.
351 The MD5 checksum currently held in m_lMD5 is merged by the
352 transformation process with data passed in 'Block'.
353 *****************************************************************************************/
Transform(BYTE Block[64])354 void CMD5Checksum::Transform(BYTE Block[64])
355 {
356 //initialise local data with current checksum
357 UINT a = m_lMD5[0];
358 UINT b = m_lMD5[1];
359 UINT c = m_lMD5[2];
360 UINT d = m_lMD5[3];
361
362 //copy BYTES from input 'Block' to an array of UINTS 'X'
363 UINT X[16];
364 ByteToDWord(X, Block, 64);
365
366 //Perform Round 1 of the transformation
367 FF(a, b, c, d, X[ 0], MD5_S11, MD5_T01);
368 FF(d, a, b, c, X[ 1], MD5_S12, MD5_T02);
369 FF(c, d, a, b, X[ 2], MD5_S13, MD5_T03);
370 FF(b, c, d, a, X[ 3], MD5_S14, MD5_T04);
371 FF(a, b, c, d, X[ 4], MD5_S11, MD5_T05);
372 FF(d, a, b, c, X[ 5], MD5_S12, MD5_T06);
373 FF(c, d, a, b, X[ 6], MD5_S13, MD5_T07);
374 FF(b, c, d, a, X[ 7], MD5_S14, MD5_T08);
375 FF(a, b, c, d, X[ 8], MD5_S11, MD5_T09);
376 FF(d, a, b, c, X[ 9], MD5_S12, MD5_T10);
377 FF(c, d, a, b, X[10], MD5_S13, MD5_T11);
378 FF(b, c, d, a, X[11], MD5_S14, MD5_T12);
379 FF(a, b, c, d, X[12], MD5_S11, MD5_T13);
380 FF(d, a, b, c, X[13], MD5_S12, MD5_T14);
381 FF(c, d, a, b, X[14], MD5_S13, MD5_T15);
382 FF(b, c, d, a, X[15], MD5_S14, MD5_T16);
383
384 //Perform Round 2 of the transformation
385 GG(a, b, c, d, X[ 1], MD5_S21, MD5_T17);
386 GG(d, a, b, c, X[ 6], MD5_S22, MD5_T18);
387 GG(c, d, a, b, X[11], MD5_S23, MD5_T19);
388 GG(b, c, d, a, X[ 0], MD5_S24, MD5_T20);
389 GG(a, b, c, d, X[ 5], MD5_S21, MD5_T21);
390 GG(d, a, b, c, X[10], MD5_S22, MD5_T22);
391 GG(c, d, a, b, X[15], MD5_S23, MD5_T23);
392 GG(b, c, d, a, X[ 4], MD5_S24, MD5_T24);
393 GG(a, b, c, d, X[ 9], MD5_S21, MD5_T25);
394 GG(d, a, b, c, X[14], MD5_S22, MD5_T26);
395 GG(c, d, a, b, X[ 3], MD5_S23, MD5_T27);
396 GG(b, c, d, a, X[ 8], MD5_S24, MD5_T28);
397 GG(a, b, c, d, X[13], MD5_S21, MD5_T29);
398 GG(d, a, b, c, X[ 2], MD5_S22, MD5_T30);
399 GG(c, d, a, b, X[ 7], MD5_S23, MD5_T31);
400 GG(b, c, d, a, X[12], MD5_S24, MD5_T32);
401
402 //Perform Round 3 of the transformation
403 HH(a, b, c, d, X[ 5], MD5_S31, MD5_T33);
404 HH(d, a, b, c, X[ 8], MD5_S32, MD5_T34);
405 HH(c, d, a, b, X[11], MD5_S33, MD5_T35);
406 HH(b, c, d, a, X[14], MD5_S34, MD5_T36);
407 HH(a, b, c, d, X[ 1], MD5_S31, MD5_T37);
408 HH(d, a, b, c, X[ 4], MD5_S32, MD5_T38);
409 HH(c, d, a, b, X[ 7], MD5_S33, MD5_T39);
410 HH(b, c, d, a, X[10], MD5_S34, MD5_T40);
411 HH(a, b, c, d, X[13], MD5_S31, MD5_T41);
412 HH(d, a, b, c, X[ 0], MD5_S32, MD5_T42);
413 HH(c, d, a, b, X[ 3], MD5_S33, MD5_T43);
414 HH(b, c, d, a, X[ 6], MD5_S34, MD5_T44);
415 HH(a, b, c, d, X[ 9], MD5_S31, MD5_T45);
416 HH(d, a, b, c, X[12], MD5_S32, MD5_T46);
417 HH(c, d, a, b, X[15], MD5_S33, MD5_T47);
418 HH(b, c, d, a, X[ 2], MD5_S34, MD5_T48);
419
420 //Perform Round 4 of the transformation
421 II(a, b, c, d, X[ 0], MD5_S41, MD5_T49);
422 II(d, a, b, c, X[ 7], MD5_S42, MD5_T50);
423 II(c, d, a, b, X[14], MD5_S43, MD5_T51);
424 II(b, c, d, a, X[ 5], MD5_S44, MD5_T52);
425 II(a, b, c, d, X[12], MD5_S41, MD5_T53);
426 II(d, a, b, c, X[ 3], MD5_S42, MD5_T54);
427 II(c, d, a, b, X[10], MD5_S43, MD5_T55);
428 II(b, c, d, a, X[ 1], MD5_S44, MD5_T56);
429 II(a, b, c, d, X[ 8], MD5_S41, MD5_T57);
430 II(d, a, b, c, X[15], MD5_S42, MD5_T58);
431 II(c, d, a, b, X[ 6], MD5_S43, MD5_T59);
432 II(b, c, d, a, X[13], MD5_S44, MD5_T60);
433 II(a, b, c, d, X[ 4], MD5_S41, MD5_T61);
434 II(d, a, b, c, X[11], MD5_S42, MD5_T62);
435 II(c, d, a, b, X[ 2], MD5_S43, MD5_T63);
436 II(b, c, d, a, X[ 9], MD5_S44, MD5_T64);
437
438 //add the transformed values to the current checksum
439 m_lMD5[0] += a;
440 m_lMD5[1] += b;
441 m_lMD5[2] += c;
442 m_lMD5[3] += d;
443 }
444
445
446 /*****************************************************************************************
447 CONSTRUCTOR: CMD5Checksum
448 DESCRIPTION: Initialises member data
449 ARGUMENTS: None
450 NOTES: None
451 *****************************************************************************************/
CMD5Checksum()452 CMD5Checksum::CMD5Checksum()
453 {
454 // zero members
455 memset(m_lpszBuffer, 0, 64);
456 m_nCount[0] = m_nCount[1] = 0;
457 m_pBuffer = NULL;
458 // Load magic state initialization constants
459 m_lMD5[0] = MD5_INIT_STATE_0;
460 m_lMD5[1] = MD5_INIT_STATE_1;
461 m_lMD5[2] = MD5_INIT_STATE_2;
462 m_lMD5[3] = MD5_INIT_STATE_3;
463 m_pBuffer = NULL;
464 }
465
466 /*****************************************************************************************
467 FUNCTION: CMD5Checksum::DWordToByte
468 DETAILS: private
469 DESCRIPTION: Transfers the data in an 32 bit array to a 8 bit array
470 RETURNS: void
471 ARGUMENTS: BYTE* Output : the 8 bit destination array
472 DWORD* Input : the 32 bit source array
473 UINT nLength : the number of 8 bit data items in the source array
474 NOTES: One DWORD from the input array is transferred into four BYTES
475 in the output array. The first (0-7) bits of the first DWORD are
476 transferred to the first output BYTE, bits bits 8-15 are transferred from
477 the second BYTE etc.
478
479 The algorithm assumes that the output array is a multiple of 4 bytes long
480 so that there is a perfect fit of 8 bit BYTES into the 32 bit DWORDs.
481 *****************************************************************************************/
DWordToByte(BYTE * Output,DWORD * Input,UINT nLength)482 void CMD5Checksum::DWordToByte(BYTE *Output, DWORD *Input, UINT nLength)
483 {
484 //transfer the data by shifting and copying
485 UINT i = 0;
486 UINT j = 0;
487 for (; j < nLength; i++, j += 4)
488 {
489 Output[j] = (UCHAR)(Input[i] & 0xff);
490 Output[j + 1] = (UCHAR)((Input[i] >> 8) & 0xff);
491 Output[j + 2] = (UCHAR)((Input[i] >> 16) & 0xff);
492 Output[j + 3] = (UCHAR)((Input[i] >> 24) & 0xff);
493 }
494 }
495
496
497 /*****************************************************************************************
498 FUNCTION: CMD5Checksum::Final
499 DETAILS: protected
500 DESCRIPTION: Implementation of main MD5 checksum algorithm; ends the checksum calculation.
501 RETURNS: CString : the final hexadecimal MD5 checksum result
502 ARGUMENTS: None
503 NOTES: Performs the final MD5 checksum calculation ('Update' does most of the work,
504 this function just finishes the calculation.)
505 *****************************************************************************************/
Final()506 tstring CMD5Checksum::Final()
507 {
508 //Save number of bits
509 BYTE Bits[8];
510 DWordToByte(Bits, m_nCount, 8);
511
512 //Pad out to 56 mod 64.
513 UINT nIndex = (UINT)((m_nCount[0] >> 3) & 0x3f);
514 UINT nPadLen = (nIndex < 56) ? (56 - nIndex) : (120 - nIndex);
515 Update(PADDING, nPadLen);
516
517 //Append length (before padding)
518 Update(Bits, 8);
519
520 //Store final state in 'lpszMD5'
521 const int nMD5Size = 16;
522 unsigned char lpszMD5[ nMD5Size ];
523 DWordToByte(lpszMD5, m_lMD5, nMD5Size);
524
525 //Convert the hexadecimal checksum to a CString
526 tstring strMD5;
527 tchar str[10];
528 strMD5 = _T("");
529 for (int i = 0; i < nMD5Size; i++)
530 {
531 if (lpszMD5[i] == 0)
532 {
533 _tcscpy(str, _T("00"));
534 }
535 else if (lpszMD5[i] <= 15)
536 {
537 _stprintf(str, _T("0%x"), lpszMD5[i]);
538 }
539 else
540 {
541 _stprintf(str, _T("%x"), lpszMD5[i]);
542 }
543
544 assert(_tcslen(str) == 2);
545 strMD5 += str;
546 }
547 assert(strMD5.size() == 32);
548 return strMD5;
549 }
550
551 /*****************************************************************************************
552 FUNCTION: CMD5Checksum::Final
553 DETAILS: protected
554 DESCRIPTION: Implementation of main MD5 checksum algorithm; ends the checksum calculation.
555 RETURNS: CString : the final hexadecimal MD5 checksum result
556 ARGUMENTS: None
557 NOTES: Performs the final MD5 checksum calculation ('Update' does most of the work,
558 this function just finishes the calculation.)
559 *****************************************************************************************/
FinalChar()560 unsigned char *CMD5Checksum::FinalChar()
561 {
562 //Save number of bits
563 BYTE Bits[8];
564 DWordToByte(Bits, m_nCount, 8);
565
566 //Pad out to 56 mod 64.
567 UINT nIndex = (UINT)((m_nCount[0] >> 3) & 0x3f);
568 UINT nPadLen = (nIndex < 56) ? (56 - nIndex) : (120 - nIndex);
569 Update(PADDING, nPadLen);
570
571 //Append length (before padding)
572 Update(Bits, 8);
573
574 //Store final state in 'lpszMD5'
575 const int nMD5Size = 16;
576 if (m_pBuffer)
577 {
578 delete []m_pBuffer;
579 m_pBuffer = NULL;
580 }
581 m_pBuffer = new BYTE[nMD5Size];
582 DWordToByte(m_pBuffer, m_lMD5, nMD5Size);
583 return m_pBuffer;
584 // unsigned char lpszMD5[ nMD5Size ];
585 // DWordToByte( lpszMD5, m_lMD5, nMD5Size );
586
587 // return lpszMD5;
588 }
589
590 /*****************************************************************************************
591 FUNCTION: CMD5Checksum::Update
592 DETAILS: protected
593 DESCRIPTION: Implementation of main MD5 checksum algorithm
594 RETURNS: void
595 ARGUMENTS: BYTE* Input : input block
596 UINT nInputLen : length of input block
597 NOTES: Computes the partial MD5 checksum for 'nInputLen' bytes of data in 'Input'
598 *****************************************************************************************/
Update(BYTE * Input,UINT nInputLen)599 void CMD5Checksum::Update(BYTE *Input, UINT nInputLen)
600 {
601 //Compute number of bytes mod 64
602 UINT nIndex = (UINT)((m_nCount[0] >> 3) & 0x3F);
603
604 //Update number of bits
605 if ((m_nCount[0] += nInputLen << 3) < (nInputLen << 3))
606 {
607 m_nCount[1]++;
608 }
609 m_nCount[1] += (nInputLen >> 29);
610
611 //Transform as many times as possible.
612 UINT i = 0;
613 UINT nPartLen = 64 - nIndex;
614 if (nInputLen >= nPartLen)
615 {
616 memcpy(&m_lpszBuffer[nIndex], Input, nPartLen);
617 Transform(m_lpszBuffer);
618 for (i = nPartLen; i + 63 < nInputLen; i += 64)
619 {
620 Transform(&Input[i]);
621 }
622 nIndex = 0;
623 }
624 else
625 {
626 i = 0;
627 }
628
629 // Buffer remaining input
630 memcpy(&m_lpszBuffer[nIndex], &Input[i], nInputLen - i);
631 }
632
633
634