/********************************************************************
Created: 21/3/2004, 21:38
File name: D:\Projects\Exile\MD5\MD5.cpp
File path: D:\Projects\Exile\MD5
File base: MD5
File ext: cpp
Author: Gogolev Anton
*********************************************************************/
// MD5.cpp : Defines the entry point for the DLL
//
#include "stdafx.h"
#include "MD5.h"
#include <stdlib.h>
#include <math.h>
#include <map>
// Context map
typedef std::map<HMD5CONTEXT, MD5CONTEXT> MD5CONTEXTMAP;
MD5CONTEXTMAP mMd5Ctx;
// Summands used in rounds
MD5_WORD *g_pwSummands = 0;
// Chaining constants
static const MD5_WORD g_wChainA = 0x67452301;
static const MD5_WORD g_wChainB = 0xEFCDAB89;
static const MD5_WORD g_wChainC = 0x98BADCFE;
static const MD5_WORD g_wChainD = 0x10325476;
//////////////////////////////////////////////////////////////////////////
// MD5 Nonlinear functions
inline MD5_WORD F(MD5_WORD wX, MD5_WORD wY, MD5_WORD wZ)
{
return ((wX & wY) | ((~wX) & wZ));
}
inline MD5_WORD G(MD5_WORD wX, MD5_WORD wY, MD5_WORD wZ)
{
return ((wX & wZ) | (wY & (~wZ)));
}
inline MD5_WORD H(MD5_WORD wX, MD5_WORD wY, MD5_WORD wZ)
{
return (wX ^ wY ^ wZ);
}
inline MD5_WORD I(MD5_WORD wX, MD5_WORD wY, MD5_WORD wZ)
{
return (wY ^ (wX | (~wZ)));
}
//////////////////////////////////////////////////////////////////////////
// MD5 Transformation Functions
inline void FF(MD5_WORD &wA, MD5_WORD wB, MD5_WORD wC, MD5_WORD wD, MD5_WORD wM, int nS, MD5_WORD wT)
{
//wA += wB + _lrotl((wA + F(wB, wC, wD) + wM + wT), nS);
wA += F(wB, wC, wD) + wM + wT;
wA = _lrotl(wA, nS);
wA += wB;
}
inline void GG(MD5_WORD &wA, MD5_WORD wB, MD5_WORD wC, MD5_WORD wD, MD5_WORD wM, int nS, MD5_WORD wT)
{
//wA += wB + _lrotl((wA + G(wB, wC, wD) + wM + wT), nS);
wA += G(wB, wC, wD) + wM + wT;
wA = _lrotl(wA, nS);
wA += wB;
}
inline void HH(MD5_WORD &wA, MD5_WORD wB, MD5_WORD wC, MD5_WORD wD, MD5_WORD wM, int nS, MD5_WORD wT)
{
//wA += wB + _lrotl((wA + H(wB, wC, wD) + wM + wT), nS);
wA += H(wB, wC, wD) + wM + wT;
wA = _lrotl(wA, nS);
wA += wB;
}
inline void II(MD5_WORD &wA, MD5_WORD wB, MD5_WORD wC, MD5_WORD wD, MD5_WORD wM, int nS, MD5_WORD wT)
{
//wA += wB + _lrotl((wA + I(wB, wC, wD) + wM + wT), nS);
wA += I(wB, wC, wD) + wM + wT;
wA = _lrotl(wA, nS);
wA += wB;
}
//////////////////////////////////////////////////////////////////////////
// MD5 Main
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
} // switch
return TRUE;
}
MD5_API BOOL Md5Initialize()
{
if(g_pwSummands)
{
// Already initialized
return FALSE;
} // if
g_pwSummands = new MD5_WORD[64];
for(int n = 0; n < 64; ++n)
{
double dVal = pow(2, 32) * fabs(sin((double)n + 1));
g_pwSummands[n] = MD5_WORD(dVal);
} // for
return TRUE;
}
MD5_API BOOL Md5Uninitialize()
{
if(g_pwSummands)
{
delete [] g_pwSummands;
g_pwSummands = 0;
return TRUE;
} // if
// Not yet initialized
return FALSE;
}
MD5_API BOOL Md5AcquireContext(HMD5CONTEXT &hMd5)
{
hMd5 = (HMD5CONTEXT)&hMd5;
// Check for duplicates
if(mMd5Ctx.end() != mMd5Ctx.find(hMd5))
{
hMd5 = (HMD5CONTEXT)0;
return FALSE;
} // if
MD5CONTEXT cMd5;
cMd5.hsState.wA = g_wChainA;
cMd5.hsState.wB = g_wChainB;
cMd5.hsState.wC = g_wChainC;
cMd5.hsState.wD = g_wChainD;
cMd5.pBuffer = new BYTE[64];
cMd5.unSize = 0;
cMd5.unBuffer = 0;
mMd5Ctx[hMd5] = cMd5;
return TRUE;
}
MD5_API BOOL Md5ReleaseContext(HMD5CONTEXT &hMd5)
{
// This is an error
if(0 == hMd5)
{
return FALSE;
} // if
MD5CONTEXTMAP::iterator mMd5i = mMd5Ctx.find(hMd5);
if(mMd5Ctx.end() != mMd5i)
{
// Cleaning up
// memset((void *)(&mMd5i->second.pBuffer), 0, sizeof(BYTE) * 64);
delete [] mMd5i->second.pBuffer;
//memset((void *)(&mMd5i->second), 0, sizeof(MD5CONTEXT));
hMd5 = (HMD5CONTEXT)0;
mMd5Ctx.erase(mMd5i);
return TRUE;
} // if
return FALSE;
}
MD5_API BOOL Md5ResetContext(HMD5CONTEXT hMd5)
{
if(0 == hMd5)
{
return FALSE;
} // if
// Reset state variables and stuff...
MD5CONTEXTMAP::iterator mMd5i = mMd5Ctx.find(hMd5);
if(mMd5Ctx.end() != mMd5i)
{
mMd5i->second.hsState.wA = g_wChainA;
mMd5i->second.hsState.wB = g_wChainB;
mMd5i->second.hsState.wC = g_wChainC;
mMd5i->second.hsState.wD = g_wChainD;
mMd5i->second.unBuffer = 0;
mMd5i->second.unSize = 0;
return TRUE;
} // if
return FALSE;
}
MD5_API BOOL Md5ValidContext(HMD5CONTEXT hMd5)
{
// Zero context id indicates error
if(0 == hMd5)
{
return FALSE;
} // if
if(mMd5Ctx.end() != mMd5Ctx.find(hMd5))
{
return TRUE;
} // if
return FALSE;
}
MD5_API BOOL Md5HashBuffer(HMD5CONTEXT hMd5, BYTE *pBuffer, size_t sBuffer)
{
if(0 == hMd5)
{
return FALSE;
} // if
MD5CONTEXTMAP::iterator mMd5i = mMd5Ctx.find(hMd5);
if(mMd5Ctx.end() == mMd5i)
{
return FALSE;
} // if
// If we still have input data
while(sBuffer)
{
#ifdef _DEBUG
MD5CONTEXT cmd5 = mMd5i->second;
#endif // _DEBUG
// Fill our context buffer with as much data as possible
size_t sData = ((sBuffer >= (64 - mMd5i->second.unBuffer)) ? 64 - mMd5i->second.unBuffer : sBuffer);
memcpy(mMd5i->second.pBuffer + mMd5i->second.unBuffer, pBuffer, sData);
sBuffer -= sData; // Now have less data
pBuffer += sData; // And buffer pointer goes forward
mMd5i->second.unBuffer += sData;
mMd5i->second.unSize += sData;
#ifdef _DEBUG
cmd5 = mMd5i->second;
#endif // _DEBUG
// If we have a whole block...
if(64 == mMd5i->second.unBuffer)
{
// ...hash it
Md5HashDependentBuffer((MD5_WORD *)mMd5i->second.pBuffer, mMd5i->second.hsState);
mMd5i->second.unBuffer = 0;
} // if
} // while
return TRUE;
}
MD5_API BOOL Md5HashFinal(HMD5CONTEXT hMd5, MD5HASH &hsMd5)
{
if(0 == hMd5)
{
return FALSE;
} // if
MD5CONTEXTMAP::iterator mMd5i = mMd5Ctx.find(hMd5);
if(mMd5Ctx.end() == mMd5i)
{
return FALSE;
} // if
// If we have more than of 56 bytes of data buffered, we must pad the pemaining bytes
// with proper bits (0x80 first and 0x00 after that) and hash it, and then pad
// 56 bytes of a new buffer with zeroes and append message length (which should also
// be adjusted). It we have 56 or less bytes of buffered data, just pad it,
// append length and hash.
BYTE bPad = 0x80;
#ifdef _DEBUG
MD5CONTEXT cmd5 = mMd5i->second;
#endif // _DEBUG
if(mMd5i->second.unBuffer > 56)
{
mMd5i->second.pBuffer[mMd5i->second.unBuffer] = 0x80;
// And pad the rest with zeroes
for(unsigned int n = mMd5i->second.unBuffer + 1; n < 64; ++n)
mMd5i->second.pBuffer[n] = 0x00;
Md5HashDependentBuffer((MD5_WORD *)mMd5i->second.pBuffer, mMd5i->second.hsState);
mMd5i->second.unSize += 64 - mMd5i->second.unBuffer;
mMd5i->second.unBuffer = 0;
bPad = 0x00; // Has already been padded
} // if
#ifdef _DEBUG
cmd5 = mMd5i->second;
#endif // _DEBUG
// Either a new block or a block with less than 56 bytes of data.
// Padding with zeroes adjusting size...
memset(mMd5i->second.pBuffer + mMd5i->second.unBuffer, 0, 64 - mMd5i->second.unBuffer);
mMd5i->second.pBuffer[mMd5i->second.unBuffer] = bPad;
mMd5i->second.unSize += 64 - mMd5i->second.unBuffer;
// Appending 64-bit length
unsigned __int64 nSz = (unsigned __int64)mMd5i->second.unSize;
memmove(mMd5i->second.pBuffer + 56, &nSz, sizeof(unsigned __int64));
#ifdef _DEBUG
cmd5 = mMd5i->second;
#endif // _DEBUG
Md5HashDependentBuffer((MD5_WORD *)mMd5i->second.pBuffer, mMd5i->second.hsState);
hsMd5 = mMd5i->second.hsState;
Md5ResetContext(hMd5);
return TRUE;
}
MD5_API BOOL Md5HashDependentBuffer(MD5_WORD *pwData, MD5HASH &hMd5)
{
if(!g_pwSummands)
return FALSE;
MD5_WORD wA, wB, wC, wD;
// Here we go
wA = hMd5.wA;
wB = hMd5.wB;
wC = hMd5.wC;
wD = hMd5.wD;
// Stage 1
FF(wA, wB, wC, wD, pwData[0], 7, g_pwSummands[0]);
FF(wD, wA, wB, wC, pwData[1], 12, g_pwSummands[1]);
FF(wC, wD, wA, wB, pwData[2], 17, g_pwSummands[2]);
FF(wB, wC, wD, wA, pwData[3], 22, g_pwSummands[3]);
FF(wA, wB, wC, wD, pwData[4], 7, g_pwSummands[4]);
FF(wD, wA, wB, wC, pwData[5], 12, g_pwSummands[5]);
FF(wC, wD, wA, wB, pwData[6], 17, g_pwSummands[6]);
FF(wB, wC, wD, wA, pwData[7], 22, g_pwSummands[7]);
FF(wA, wB, wC, wD, pwData[8], 7, g_pwSummands[8]);
FF(wD, wA, wB, wC, pwData[9], 12, g_pwSummands[9]);
FF(wC, wD, wA, wB, pwData[10], 17, g_pwSummands[10]);
FF(wB, wC, wD, wA, pwData[11], 22, g_pwSummands[11]);
FF(wA, wB, wC, wD, pwData[12], 7, g_pwSummands[12]);
FF(wD, wA, wB, wC, pwData[13], 12, g_pwSummands[13]);
FF(wC, wD, wA, wB, pwData[14], 17, g_pwSummands[14]);
FF(wB, wC, wD, wA, pwData[15], 22, g_pwSummands[15]);
// Stage 2
GG(wA, wB, wC, wD, pwData[1], 5, g_pwSummands[16]);
GG(wD, wA, wB, wC, pwData[6], 9, g_pwSummands[17]);
GG(wC, wD, wA, wB, pwData[11], 14, g_pwSummands[18]);
GG(wB, wC, wD, wA, pwData[0], 20, g_pwSummands[19]);
GG(wA, wB, wC, wD, pwData[5], 5, g_pwSummands[20]);
GG(wD, wA, wB, wC, pwData[10], 9, g_pwSummands[21]);
GG(wC, wD, wA, wB, pwData[15], 14, g_pwSummands[22]);
GG(wB, wC, wD, wA, pwData[4], 20, g_pwSummands[23]);
GG(wA, wB, wC, wD, pwData[9], 5, g_pwSummands[24]);
GG(wD, wA, wB, wC, pwData[14], 9, g_pwSummands[25]);
GG(wC, wD, wA, wB, pwData[3], 14, g_pwSummands[26]);
GG(wB, wC, wD, wA, pwData[8], 20, g_pwSummands[27]);
GG(wA, wB, wC, wD, pwData[13], 5, g_pwSummands[28]);
GG(wD, wA, wB, wC, pwData[2], 9, g_pwSummands[29]);
GG(wC, wD, wA, wB, pwData[7], 14, g_pwSummands[30]);
GG(wB, wC, wD, wA, pwData[12], 20, g_pwSummands[31]);
// Stage 3
HH(wA, wB, wC, wD, pwData[5], 4, g_pwSummands[32]);
HH(wD, wA, wB, wC, pwData[8], 11, g_pwSummands[33]);
HH(wC, wD, wA, wB, pwData[11], 16, g_pwSummands[34]);
HH(wB, wC, wD, wA, pwData[14], 23, g_pwSummands[35]);
HH(wA, wB, wC, wD, pwData[1], 4, g_pwSummands[36]);
HH(wD, wA, wB, wC, pwData[4], 11, g_pwSummands[37]);
HH(wC, wD, wA, wB, pwData[7], 16, g_pwSummands[38]);
HH(wB, wC, wD, wA, pwData[10], 23, g_pwSummands[39]);
HH(wA, wB, wC, wD, pwData[13], 4, g_pwSummands[40]);
HH(wD, wA, wB, wC, pwData[0], 11, g_pwSummands[41]);
HH(wC, wD, wA, wB, pwData[3], 16, g_pwSummands[42]);
HH(wB, wC, wD, wA, pwData[6], 23, g_pwSummands[43]);
HH(wA, wB, wC, wD, pwData[8], 4, g_pwSummands[44]);
HH(wD, wA, wB, wC, pwData[12], 11, g_pwSummands[45]);
HH(wC, wD, wA, wB, pwData[15], 16, g_pwSummands[46]);
HH(wB, wC, wD, wA, pwData[2], 23, g_pwSummands[47]);
// Stage 4
II(wA, wB, wC, wD, pwData[0], 6, g_pwSummands[48]);
II(wD, wA, wB, wC, pwData[7], 10, g_pwSummands[49]);
II(wC, wD, wA, wB, pwData[14], 15, g_pwSummands[50]);
II(wB, wC, wD, wA, pwData[5], 21, g_pwSummands[51]);
II(wA, wB, wC, wD, pwData[12], 6, g_pwSummands[52]);
II(wD, wA, wB, wC, pwData[3], 10, g_pwSummands[53]);
II(wC, wD, wA, wB, pwData[10], 15, g_pwSummands[54]);
II(wB, wC, wD, wA, pwData[1], 21, g_pwSummands[55]);
II(wA, wB, wC, wD, pwData[8], 6, g_pwSummands[56]);
II(wD, wA, wB, wC, pwData[15], 10, g_pwSummands[57]);
II(wC, wD, wA, wB, pwData[6], 15, g_pwSummands[58]);
II(wB, wC, wD, wA, pwData[13], 21, g_pwSummands[59]);
II(wA, wB, wC, wD, pwData[4], 6, g_pwSummands[60]);
II(wD, wA, wB, wC, pwData[11], 10, g_pwSummands[61]);
II(wC, wD, wA, wB, pwData[2], 15, g_pwSummands[62]);
II(wB, wC, wD, wA, pwData[9], 21, g_pwSummands[63]);
// Now we add resulting values to the MD5 hash structure
hMd5.wA += wA;
hMd5.wB += wB;
hMd5.wC += wC;
hMd5.wD += wD;
return TRUE;
}
MD5_API size_t Md5GetExpandedBufferSize(size_t sSize)
{
// The (resultant buffer size + 8 bytes) must be a multiple of 64
while((sSize + 8) % 64)
++sSize;
// Eight bytes for length
sSize += 8;
return sSize;
}
MD5_API BOOL Md5ExpandData(void *pvData, size_t sSgSize, size_t sTotal)
{
// First, we set all bytes starting from (pvData + sSgSize) to (pvData + sTotal) to zero
memset((BYTE *)pvData + sSgSize, 0, sTotal - sSgSize);
// Now we set the first byte after significant data to 0x80
((BYTE *)pvData)[sSgSize] = 0x80;
// And set last 64 bits (8 bytes) to be equal to total message size (sTotal)
unsigned __int64 nSz = (unsigned __int64)sTotal;
memmove((BYTE *)pvData + sTotal - 8, &nSz, sizeof(unsigned __int64));
return TRUE;
}
MD5_API BOOL Md5HashData(MD5_WORD *pwData, UINT nBlocks, MD5HASH &hMd5)
{
if(!g_pwSummands)
return FALSE;
hMd5.wA = g_wChainA;
hMd5.wB = g_wChainB;
hMd5.wC = g_wChainC;
hMd5.wD = g_wChainD;
for( ; nBlocks; --nBlocks, pwData += 16) // Moving data pointer 512 bits (16 words) forward
{
if(!Md5HashDependentBuffer(pwData, hMd5))
return FALSE;
} // for
return TRUE;
}
MD5_API BOOL Md5EqualHashes(MD5HASH hsMd5A, MD5HASH hsMd5B)
{
return ((hsMd5A.wA == hsMd5B.wA) &&
(hsMd5A.wB == hsMd5B.wB) &&
(hsMd5A.wC == hsMd5B.wC) &&
(hsMd5A.wD == hsMd5B.wD));
}