// MD5.h http://www.faqs.org/rfcs/rfc1321.html #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #ifndef MD5h #define MD5h /* CMD5 Forms the Message Digest 5 (MD5) hash for given data. CString S=CMD5("The Text").GetMD5s(); For some random string: CString S=CMD5(itoa((long)GetTickCount())).GetMD5s(); CFileMD5 Finds the Message Digest of a whole File. The Automatic Tester at the end of MD5.h uses standard Test Vectors. */ class CMD5 { BYTE Digest[16]; char sMD5[33]; public: CMD5() {*sMD5=0;} CMD5(const char* String) {Set(String);} virtual ~CMD5() {} struct MD5Context{ DWORD state[4]; // state (ABCD) DWORD count[2]; // number of bits, modulo 2^64 (lsb first) unsigned char buffer[64];// input buffer }; void Set(const char* String) { MD5Context Context; Init(&Context); Update(&Context, (BYTE*)String, strlen(String)); Final(&Context); CreateString(); } bool IsValid() const {return *sMD5!=0;} const char* GetMD5s() const {return sMD5;} const BYTE* GetMD5n() const {return Digest;} protected: void Init(MD5Context *Context) { // MD5 initialization. Begins an MD5 operation, writing a new Context. *sMD5=0; memset(Digest, 0, sizeof(Digest)); Context->count[0]=Context->count[1]=0; // Load magic initialization constants. Context->state[0]=0x67452301; Context->state[1]=0xEFCDAB89; Context->state[2]=0x98BADCFE; Context->state[3]=0x10325476; } // MD5 block update operation. // Continues an MD5 message-digest operation, processing another message block, and updating the Context. void Update(MD5Context *Context, unsigned char *input, DWORD inputLen) { unsigned int i, index, partLen; index=(unsigned int)((Context->count[0] >> 3) & 0x3F); // Compute number of bytes mod 64 // Update number of bits: if((Context->count[0] += (inputLen << 3)) < (inputLen << 3)) Context->count[1]++; Context->count[1] += (inputLen >> 29); partLen=64-index; if(inputLen>=partLen) { // Transform as many times as possible: memcpy((unsigned char*)&Context->buffer[index], (unsigned char*)input, partLen); Transform(Context->state, Context->buffer); for(i=partLen; (i+63)state, &input[i]); index=0; }else i=0; // Buffer remaining input: if(inputLen>i) memcpy((unsigned char *)&Context->buffer[index], (unsigned char *)&input[i], inputLen-i); } void CreateString() { char* ptr=sMD5; BYTE* src=Digest; for(int i=0; i<16; i++) { BYTE b=*src++; BYTE B=b>>4; b&=0x0F; B=(B>9 ? B-10+'A' : B+'0'); b=(b>9 ? b-10+'A' : b+'0'); *ptr++=B; *ptr++=b; } *ptr=0; } // MD5 finalization. // Ends an MD5 message-digest operation, writing the the message digest and zeroing the Context. void Final(MD5Context *Context) { unsigned char bits[8]; unsigned int index, padLen; static unsigned char Padding[64]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; Encode(bits, Context->count, 8); //Save number of bits index=(unsigned int)((Context->count[0] >> 3) & 0x3F); //Pad out to 56 mod 64. padLen=(index<56) ? (56-index) : (120-index); Update(Context, Padding, padLen); Update(Context, bits, 8); //Append length (before padding) Encode(Digest, Context->state, 16); // Store state in digest memset((unsigned char *)Context, 0, sizeof(*Context)); // Zero sensitive information. } private: void Transform(DWORD state[4], unsigned char block[64]) { DWORD a=state[0], b=state[1], c=state[2], d=state[3], x[16]; Decode(x, block, 64); const DWORD S11= 7; const DWORD S12=12; const DWORD S13=17; const DWORD S14=22; const DWORD S21= 5; const DWORD S22= 9; const DWORD S23=14; const DWORD S24=20; const DWORD S31= 4; const DWORD S32=11; const DWORD S33=16; const DWORD S34=23; const DWORD S41= 6; const DWORD S42=10; const DWORD S43=15; const DWORD S44=21; // Round 1 FF(a,b,c,d,x[ 0],S11,0xD76AA478); // 1 FF(d,a,b,c,x[ 1],S12,0xE8C7B756); // 2 FF(c,d,a,b,x[ 2],S13,0x242070DB); // 3 FF(b,c,d,a,x[ 3],S14,0xC1BDCEEE); // 4 FF(a,b,c,d,x[ 4],S11,0xF57C0FAF); // 5 FF(d,a,b,c,x[ 5],S12,0x4787C62A); // 6 FF(c,d,a,b,x[ 6],S13,0xA8304613); // 7 FF(b,c,d,a,x[ 7],S14,0xFD469501); // 8 FF(a,b,c,d,x[ 8],S11,0x698098D8); // 9 FF(d,a,b,c,x[ 9],S12,0x8B44F7AF); // 10 FF(c,d,a,b,x[10],S13,0xFFFF5BB1); // 11 FF(b,c,d,a,x[11],S14,0x895CD7BE); // 12 FF(a,b,c,d,x[12],S11,0x6B901122); // 13 FF(d,a,b,c,x[13],S12,0xFD987193); // 14 FF(c,d,a,b,x[14],S13,0xA679438E); // 15 FF(b,c,d,a,x[15],S14,0x49B40821); // 16 // Round 2 GG(a,b,c,d,x[ 1],S21,0xF61E2562); // 17 GG(d,a,b,c,x[ 6],S22,0xC040B340); // 18 GG(c,d,a,b,x[11],S23,0x265E5A51); // 19 GG(b,c,d,a,x[ 0],S24,0xE9B6C7AA); // 20 GG(a,b,c,d,x[ 5],S21,0xD62F105D); // 21 GG(d,a,b,c,x[10],S22,0x02441453); // 22 GG(c,d,a,b,x[15],S23,0xD8A1E681); // 23 GG(b,c,d,a,x[ 4],S24,0xE7D3FBC8); // 24 GG(a,b,c,d,x[ 9],S21,0x21E1CDE6); // 25 GG(d,a,b,c,x[14],S22,0xC33707D6); // 26 GG(c,d,a,b,x[ 3],S23,0xF4D50D87); // 27 GG(b,c,d,a,x[ 8],S24,0x455A14ED); // 28 GG(a,b,c,d,x[13],S21,0xA9E3E905); // 29 GG(d,a,b,c,x[ 2],S22,0xFCEFA3F8); // 30 GG(c,d,a,b,x[ 7],S23,0x676F02D9); // 31 GG(b,c,d,a,x[12],S24,0x8D2A4C8A); // 32 // Round 3 HH(a,b,c,d,x[ 5],S31,0xFFFA3942); // 33 HH(d,a,b,c,x[ 8],S32,0x8771F681); // 34 HH(c,d,a,b,x[11],S33,0x6D9D6122); // 35 HH(b,c,d,a,x[14],S34,0xFDE5380C); // 36 HH(a,b,c,d,x[ 1],S31,0xA4BEEA44); // 37 HH(d,a,b,c,x[ 4],S32,0x4BDECFA9); // 38 HH(c,d,a,b,x[ 7],S33,0xF6BB4B60); // 39 HH(b,c,d,a,x[10],S34,0xBEBFBC70); // 40 HH(a,b,c,d,x[13],S31,0x289B7EC6); // 41 HH(d,a,b,c,x[ 0],S32,0xEAA127FA); // 42 HH(c,d,a,b,x[ 3],S33,0xD4EF3085); // 43 HH(b,c,d,a,x[ 6],S34,0x04881D05); // 44 HH(a,b,c,d,x[ 9],S31,0xD9D4D039); // 45 HH(d,a,b,c,x[12],S32,0xE6DB99E5); // 46 HH(c,d,a,b,x[15],S33,0x1FA27CF8); // 47 HH(b,c,d,a,x[ 2],S34,0xC4AC5665); // 48 // Round 4 II(a,b,c,d,x[ 0],S41,0xF4292244); // 49 II(d,a,b,c,x[ 7],S42,0x432AFF97); // 50 II(c,d,a,b,x[14],S43,0xAB9423A7); // 51 II(b,c,d,a,x[ 5],S44,0xFC93A039); // 52 II(a,b,c,d,x[12],S41,0x655B59C3); // 53 II(d,a,b,c,x[ 3],S42,0x8F0CCC92); // 54 II(c,d,a,b,x[10],S43,0xFFEFF47D); // 55 II(b,c,d,a,x[ 1],S44,0x85845DD1); // 56 II(a,b,c,d,x[ 8],S41,0x6FA87E4F); // 57 II(d,a,b,c,x[15],S42,0xFE2CE6E0); // 58 II(c,d,a,b,x[ 6],S43,0xA3014314); // 59 II(b,c,d,a,x[13],S44,0x4E0811A1); // 60 II(a,b,c,d,x[ 4],S41,0xF7537E82); // 61 II(d,a,b,c,x[11],S42,0xBD3AF235); // 62 II(c,d,a,b,x[ 2],S43,0x2AD7D2BB); // 63 II(b,c,d,a,x[ 9],S44,0xEB86D391); // 64 state[0]+=a; state[1]+=b; state[2]+=c; state[3]+=d; memset ((unsigned char*)x, 0, sizeof (x)); // Zero sensitive information. } // Encodes input (DWORD) into output (unsigned char). Assumes len is a multiple of 4. void Encode(unsigned char *output, DWORD *input, unsigned int len) { unsigned i,j; for (i=j=0; j> 8) & 0xFF); output[j+2]=(unsigned char)((input[i]>>16) & 0xFF); output[j+3]=(unsigned char)((input[i]>>24) & 0xFF); } } // Decodes input (unsigned char) into output (DWORD). Assumes len is a multiple of 4. void Decode(DWORD *output, unsigned char *input, unsigned int len) { unsigned int i, j; for(i=j=0; j>(32-n));} // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. // Rotation is separate from addition to prevent re-computation. void FF(DWORD& a, DWORD b, DWORD c, DWORD d, DWORD x, DWORD s, DWORD ac) {a+=F(b,c,d)+x+ac; RotateLeft(a,s); a+=b;} void GG(DWORD& a, DWORD b, DWORD c, DWORD d, DWORD x, DWORD s, DWORD ac) {a+=G(b,c,d)+x+ac; RotateLeft(a,s); a+=b;} void HH(DWORD& a, DWORD b, DWORD c, DWORD d, DWORD x, DWORD s, DWORD ac) {a+=H(b,c,d)+x+ac; RotateLeft(a,s); a+=b;} void II(DWORD& a, DWORD b, DWORD c, DWORD d, DWORD x, DWORD s, DWORD ac) {a+=I(b,c,d)+x+ac; RotateLeft(a,s); a+=b;} }; struct CFileMD5 : public CMD5 { CFileMD5() {} CFileMD5(const HANDLE File) {Load(File);} CFileMD5(const char* Path) {Load(Path);} virtual ~CFileMD5() {} bool Load(const char* Path) { HANDLE File=CreateFile(Path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(File==INVALID_HANDLE_VALUE) return false; bool OK=Load(File); CloseHandle(File); return OK; } bool Load(const HANDLE File) { if(File==INVALID_HANDLE_VALUE) return false; #if _MSC_VER > 1200 LARGE_INTEGER Size,Pos={0}; SetFilePointerEx(File,Pos,&Pos,FILE_CURRENT); // find out how far from the End of the File the File Pointer is. GetFileSizeEx(File,&Size); #else DWORD PosHi=0; DWORD PosLo=SetFilePointer(File,0,(PLONG)&PosHi,FILE_CURRENT); // find out how far from the End of the File the File Pointer is. DWORD SizeHi; DWORD SizeLo=GetFileSize(File,&SizeHi); #endif DWORD ByteCount; unsigned char Buffer[64]; MD5Context Context; Init(&Context); #if _MSC_VER > 1200 if((Size.HighPart> Pos.HighPart) || ((Size.HighPart==Pos.HighPart) && (Size.LowPart>Pos.LowPart))) { #else if((SizeHi> PosHi) ||((SizeHi==PosHi) && (SizeLo>PosLo))) { #endif do { ReadFile(File, Buffer, 64, &ByteCount, NULL); Update(&Context, Buffer, ByteCount); } while(ByteCount==64); } Final(&Context); CreateString(); return true; } }; #ifdef Assert // Run tests if Tester.h is included in stdafx.h namespace { // namespace prevents multiple definitions if instantiating in the header like this: struct MD5Tester : Tester { MD5Tester() { Assert(strcmp(CMD5("").GetMD5s(), "D41D8CD98F00B204E9800998ECF8427E")==0); Assert(strcmp(CMD5("a").GetMD5s(), "0CC175B9C0F1B6A831C399E269772661")==0); Assert(strcmp(CMD5("abc").GetMD5s(), "900150983CD24FB0D6963F7D28E17F72")==0); Assert(strcmp(CMD5("message digest").GetMD5s(), "F96B697D7CB7938D525A2F31AAF161D0")==0); Assert(strcmp(CMD5("abcdefghijklmnopqrstuvwxyz").GetMD5s(), "C3FCD3D76192E4007DFB496CCA67E13B")==0); Assert(strcmp(CMD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789").GetMD5s(), "D174AB98D277D9F5A5611C2C9F419D9F")==0); Assert(strcmp(CMD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890").GetMD5s(), "57EDF4A22BE3C955AC49DA2E2107B67A")==0); } } _MD5Tester; } #endif // def Assert #endif //ndef MD5h