// MDX.cpp : Defines the entry point for the DLL
//
#include "stdafx.h"
#include "MDX.h"
#include <stdlib.h>
#include <math.h>
#include <map>
// Context map
typedef std::map<HMDXCONTEXT, MDXCONTEXT> MDXCONTEXTMAP;
MDXCONTEXTMAP mMdxCtx;
// Summands used in rounds
MDX_WORD *g_pwSummands = 0;
// Chaining constants
static const MDX_WORD g_wChainA = 0x67452301;
static const MDX_WORD g_wChainB = 0xEFCDAB89;
static const MDX_WORD g_wChainC = 0x98BADCFE;
static const MDX_WORD g_wChainD = 0x10325476;
//////////////////////////////////////////////////////////////////////////
// MDX Nonlinear functions
inline MDX_WORD F(MDX_WORD wX, MDX_WORD wY, MDX_WORD wZ)
{
return ((wX & wY) | ((~wX) & wZ));
}
inline MDX_WORD G(MDX_WORD wX, MDX_WORD wY, MDX_WORD wZ)
{
return ((wX & wZ) | (wY & (~wZ)));
}
inline MDX_WORD H(MDX_WORD wX, MDX_WORD wY, MDX_WORD wZ)
{
return (wX ^ wY ^ wZ);
}
inline MDX_WORD I(MDX_WORD wX, MDX_WORD wY, MDX_WORD wZ)
{
return (wY ^ (wX | (~wZ)));
}
//////////////////////////////////////////////////////////////////////////
// MDX Transformation Functions
inline void FF(MDX_WORD &wA, MDX_WORD wB, MDX_WORD wC, MDX_WORD wD, MDX_WORD wM, int nS, MDX_WORD wT)
{
wA += F(wB, wC, wD) + wM + wT;
wA = _lrotl(wA, nS);
wA += wB;
}
inline void GG(MDX_WORD &wA, MDX_WORD wB, MDX_WORD wC, MDX_WORD wD, MDX_WORD wM, int nS, MDX_WORD wT)
{
wA += G(wB, wC, wD) + wM + wT;
wA = _lrotl(wA, nS);
wA += wB;
}
inline void HH(MDX_WORD &wA, MDX_WORD wB, MDX_WORD wC, MDX_WORD wD, MDX_WORD wM, int nS, MDX_WORD wT)
{
wA += H(wB, wC, wD) + wM + wT;
wA = _lrotl(wA, nS);
wA += wB;
}
inline void II(MDX_WORD &wA, MDX_WORD wB, MDX_WORD wC, MDX_WORD wD, MDX_WORD wM, int nS, MDX_WORD wT)
{
wA += I(wB, wC, wD) + wM + wT;
wA = _lrotl(wA, nS);
wA += wB;
}
//////////////////////////////////////////////////////////////////////////
// MDX 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;
}
MDX_API BOOL MdxInitialize()
{
if(g_pwSummands)
{
// Already initialized
return FALSE;
} // if
g_pwSummands = new MDX_WORD[64];
for(int n = 0; n < 64; ++n)
{
double dVal = pow(2.0, 32.0) * fabs(sin((double)n + 1.0));
g_pwSummands[n] = MDX_WORD(dVal);
} // for
return TRUE;
}
MDX_API BOOL MdxUninitialize()
{
if(g_pwSummands)
{
delete [] g_pwSummands;
g_pwSummands = 0;
return TRUE;
} // if
// Not yet initialized
return FALSE;
}
MDX_API BOOL MdxAcquireContext(HMDXCONTEXT &hMdx)
{
hMdx = (HMDXCONTEXT)&hMdx;
// Check for duplicates
if(mMdxCtx.end() != mMdxCtx.find(hMdx))
{
hMdx = (HMDXCONTEXT)0;
return FALSE;
} // if
MDXCONTEXT cMdx;
cMdx.hsState.wA = g_wChainA;
cMdx.hsState.wB = g_wChainB;
cMdx.hsState.wC = g_wChainC;
cMdx.hsState.wD = g_wChainD;
cMdx.pBuffer = new BYTE[64];
cMdx.unSize = 0;
cMdx.unBuffer = 0;
mMdxCtx[hMdx] = cMdx;
return TRUE;
}
MDX_API BOOL MdxReleaseContext(HMDXCONTEXT &hMdx)
{
// This is an error
if(0 == hMdx)
{
return FALSE;
} // if
MDXCONTEXTMAP::iterator mMdxi = mMdxCtx.find(hMdx);
if(mMdxCtx.end() != mMdxi)
{
// Cleaning up
delete [] mMdxi->second.pBuffer;
hMdx = (HMDXCONTEXT)0;
mMdxCtx.erase(mMdxi);
return TRUE;
} // if
return FALSE;
}
MDX_API BOOL MdxResetContext(HMDXCONTEXT hMdx)
{
if(0 == hMdx)
{
return FALSE;
} // if
// Reset state variables and stuff...
MDXCONTEXTMAP::iterator mMdxi = mMdxCtx.find(hMdx);
if(mMdxCtx.end() != mMdxi)
{
mMdxi->second.hsState.wA = g_wChainA;
mMdxi->second.hsState.wB = g_wChainB;
mMdxi->second.hsState.wC = g_wChainC;
mMdxi->second.hsState.wD = g_wChainD;
mMdxi->second.unBuffer = 0;
mMdxi->second.unSize = 0;
return TRUE;
} // if
return FALSE;
}
MDX_API BOOL MdxValidContext(HMDXCONTEXT hMdx)
{
// Zero context id indicates error
if(0 == hMdx)
{
return FALSE;
} // if
if(mMdxCtx.end() != mMdxCtx.find(hMdx))
{
return TRUE;
} // if
return FALSE;
}
MDX_API BOOL MdxHashBuffer(HMDXCONTEXT hMdx, BYTE *pBuffer, size_t sBuffer)
{
if(0 == hMdx)
{
return FALSE;
} // if
MDXCONTEXTMAP::iterator mMdxi = mMdxCtx.find(hMdx);
if(mMdxCtx.end() == mMdxi)
{
return FALSE;
} // if
// If we still have input data
while(sBuffer)
{
#ifdef _DEBUG
MDXCONTEXT cmd5 = mMdxi->second;
#endif // _DEBUG
// Fill our context buffer with as much data as possible
size_t sData = ((sBuffer >= (64 - mMdxi->second.unBuffer)) ? 64 - mMdxi->second.unBuffer : sBuffer);
memcpy(mMdxi->second.pBuffer + mMdxi->second.unBuffer, pBuffer, sData);
sBuffer -= sData; // Now have less data
pBuffer += sData; // And buffer pointer goes forward
mMdxi->second.unBuffer += sData;
mMdxi->second.unSize += sData;
#ifdef _DEBUG
cmd5 = mMdxi->second;
#endif // _DEBUG
// If we have a whole block...
if(64 == mMdxi->second.unBuffer)
{
// ...hash it
MdxHashDependentBuffer((MDX_WORD *)mMdxi->second.pBuffer, mMdxi->second.hsState);
mMdxi->second.unBuffer = 0;
} // if
} // while
return TRUE;
}
MDX_API BOOL MdxHashFinal(HMDXCONTEXT hMdx, MDXHASH &hsMdx)
{
if(0 == hMdx)
{
return FALSE;
} // if
MDXCONTEXTMAP::iterator mMdxi = mMdxCtx.find(hMdx);
if(mMdxCtx.end() == mMdxi)
{
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
MDXCONTEXT cmd5 = mMdxi->second;
#endif // _DEBUG
if(mMdxi->second.unBuffer > 56)
{
mMdxi->second.pBuffer[mMdxi->second.unBuffer] = 0x80;
// And pad the rest with zeroes
for(unsigned int n = mMdxi->second.unBuffer + 1; n < 64; ++n)
mMdxi->second.pBuffer[n] = 0x00;
MdxHashDependentBuffer((MDX_WORD *)mMdxi->second.pBuffer, mMdxi->second.hsState);
mMdxi->second.unSize += 64 - mMdxi->second.unBuffer;
mMdxi->second.unBuffer = 0;
bPad = 0x00; // Has already been padded
} // if
#ifdef _DEBUG
cmd5 = mMdxi->second;
#endif // _DEBUG
// Either a new block or a block with less than 56 bytes of data.
// Padding with zeroes adjusting size...
memset(mMdxi->second.pBuffer + mMdxi->second.unBuffer, 0, 64 - mMdxi->second.unBuffer);
mMdxi->second.pBuffer[mMdxi->second.unBuffer] = bPad;
mMdxi->second.unSize += 64 - mMdxi->second.unBuffer;
// Appending 64-bit length
unsigned __int64 nSz = (unsigned __int64)mMdxi->second.unSize;
memmove(mMdxi->second.pBuffer + 56, &nSz, sizeof(unsigned __int64));
#ifdef _DEBUG
cmd5 = mMdxi->second;
#endif // _DEBUG
MdxHashDependentBuffer((MDX_WORD *)mMdxi->second.pBuffer, mMdxi->second.hsState);
hsMdx = mMdxi->second.hsState;
MdxResetContext(hMdx);
return TRUE;
}
MDX_API BOOL MdxHashDependentBuffer(MDX_WORD *pwData, MDXHASH &hMdx)
{
if(!g_pwSummands)
return FALSE;
MDX_WORD wA, wB, wC, wD;
// Here we go
wA = hMdx.wA;
wB = hMdx.wB;
wC = hMdx.wC;
wD = hMdx.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 MDX hash structure
hMdx.wA += wA;
hMdx.wB += wB;
hMdx.wC += wC;
hMdx.wD += wD;
return TRUE;
}
MDX_API size_t MdxGetExpandedBufferSize(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;
}
MDX_API BOOL MdxExpandData(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;
}
MDX_API BOOL MdxHashData(MDX_WORD *pwData, UINT nBlocks, MDXHASH &hMdx)
{
if(!g_pwSummands)
return FALSE;
hMdx.wA = g_wChainA;
hMdx.wB = g_wChainB;
hMdx.wC = g_wChainC;
hMdx.wD = g_wChainD;
for( ; nBlocks; --nBlocks, pwData += 16) // Moving data pointer 512 bits (16 words) forward
{
if(!MdxHashDependentBuffer(pwData, hMdx))
return FALSE;
} // for
return TRUE;
}
MDX_API BOOL MdxEqualHashes(MDXHASH hsMdxA, MDXHASH hsMdxB)
{
return ((hsMdxA.wA == hsMdxB.wA) &&
(hsMdxA.wB == hsMdxB.wB) &&
(hsMdxA.wC == hsMdxB.wC) &&
(hsMdxA.wD == hsMdxB.wD));
}