Files
core/ASCOfficePDFReader/Decrypt.cpp

818 lines
27 KiB
C++

#include "stdafx.h"
#include <string.h>
#include "MemoryUtils.h"
#include "Decrypt.h"
static void RC4InitKey (unsigned char *sKey, int nKeyLen, unsigned char *sState);
static unsigned char RC4DecryptByte(unsigned char *sState, unsigned char *pX, unsigned char *pY, unsigned char nChar);
static void AESKeyExpansion(DecryptAESState *pState, unsigned char *sObjectKey, int nObjectKeyLen);
static void AESDecryptBlock(DecryptAESState *pState, unsigned char *sIn, BOOL bLast);
static void MD5(unsigned char *sMessage, int nMessageLen, unsigned char *sDigest);
static unsigned char passwordPad[32] =
{
0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,
0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a
};
//-------------------------------------------------------------------------------------------------------------------------------
// Decrypt
//-------------------------------------------------------------------------------------------------------------------------------
BOOL Decrypt::MakeFileKey(int nEncVersion, int nEncRevision, int nKeyLength, StringExt *seOwnerKey, StringExt *seUserKey, int nPermissions, StringExt *seFileID, StringExt *seOwnerPassword, StringExt *seUserPassword, unsigned char *sFileKey, BOOL bEncryptMetadata, BOOL *pbOwnerPasswordValid)
{
// Ïîïûòàåìñÿ, èñïîëüçóÿ ïàðîëü âëàäåëüöà, ñãåíåðèðîâàòü ïîëüçîâàòåëüñêèé ïàðîëü
*pbOwnerPasswordValid = FALSE;
if ( seOwnerPassword )
{
int nLen = seOwnerPassword->GetLength();
unsigned char arrOwnerPass[32];
if ( nLen < 32 )
{
memcpy( arrOwnerPass, seOwnerPassword->GetBuffer(), nLen );
memcpy( arrOwnerPass + nLen, passwordPad, 32 - nLen );
}
else
{
memcpy( arrOwnerPass, seOwnerPassword->GetBuffer(), 32);
}
MD5( arrOwnerPass, 32, arrOwnerPass );
if ( nEncRevision == 3 )
{
for ( int nIndex = 0; nIndex < 50; ++nIndex )
{
MD5( arrOwnerPass, 16, arrOwnerPass );
}
}
unsigned char arrOwnerKey[32];
unsigned char arrFState[256];
if ( nEncRevision == 2 )
{
RC4InitKey( arrOwnerPass, nKeyLength, arrFState );
unsigned char unFX = 0, unFY = 0;
for ( int nIndex = 0; nIndex < 32; ++nIndex )
{
arrOwnerKey[nIndex] = RC4DecryptByte( arrFState, &unFX, &unFY, seOwnerKey->GetAt(nIndex) );
}
}
else
{
memcpy( arrOwnerKey, seOwnerKey->GetBuffer(), 32 );
for ( int nIndex = 19; nIndex >= 0; --nIndex )
{
unsigned char arrTempKey[16];
for ( int nJ = 0; nJ < nKeyLength; ++nJ )
{
arrTempKey[nJ] = arrOwnerPass[nJ] ^ nIndex;
}
RC4InitKey( arrTempKey, nKeyLength, arrFState );
unsigned char unFX = 0, unFY = 0;
for ( int nJ = 0; nJ < 32; ++nJ )
{
arrOwnerKey[nJ] = RC4DecryptByte( arrFState, &unFX, &unFY, arrOwnerKey[nJ] );
}
}
}
StringExt *seUserPassword2 = new StringExt((char *)arrOwnerKey, 32);
if ( MakeFileKey2( nEncVersion, nEncRevision, nKeyLength, seOwnerKey, seUserKey, nPermissions, seFileID, seUserPassword2, sFileKey, bEncryptMetadata ) )
{
*pbOwnerPasswordValid = TRUE;
delete seUserPassword2;
return TRUE;
}
delete seUserPassword2;
}
// Ïîïûòàåìñÿ èñïîëüçîâàòü ïîëüçîâàòåëüñêèé ïàðîëü
return MakeFileKey2( nEncVersion, nEncRevision, nKeyLength, seOwnerKey, seUserKey, nPermissions, seFileID, seUserPassword, sFileKey, bEncryptMetadata );
}
BOOL Decrypt::MakeFileKey2(int nEncVersion, int nEncRevision, int nKeyLength, StringExt *seOwnerKey, StringExt *seUserKey, int nPermissions, StringExt *seFileID, StringExt *seUserPassword, unsigned char *sFileKey, BOOL bEncryptMetadata)
{
unsigned char sTest[32];
unsigned char sFState[256];
unsigned char sTempKey[16];
unsigned char unFx, unFy;
int nLen = 0;
BOOL bResult = TRUE;
unsigned char *pBuffer = (unsigned char *)MemUtilsMalloc(72 + seFileID->GetLength());
if ( seUserPassword )
{
nLen = seUserPassword->GetLength();
if ( nLen < 32 )
{
memcpy( pBuffer, seUserPassword->GetBuffer(), nLen );
memcpy( pBuffer + nLen, passwordPad, 32 - nLen );
}
else
{
memcpy( pBuffer, seUserPassword->GetBuffer(), 32);
}
}
else
{
memcpy( pBuffer, passwordPad, 32);
}
memcpy( pBuffer + 32, seOwnerKey->GetBuffer(), 32 );
pBuffer[64] = nPermissions & 0xff;
pBuffer[65] = (nPermissions >> 8) & 0xff;
pBuffer[66] = (nPermissions >> 16) & 0xff;
pBuffer[67] = (nPermissions >> 24) & 0xff;
memcpy( pBuffer + 68, seFileID->GetBuffer(), seFileID->GetLength() );
nLen = 68 + seFileID->GetLength();
if ( !bEncryptMetadata )
{
pBuffer[nLen++] = 0xff;
pBuffer[nLen++] = 0xff;
pBuffer[nLen++] = 0xff;
pBuffer[nLen++] = 0xff;
}
MD5( pBuffer, nLen, sFileKey );
if ( nEncRevision == 3 )
{
for ( int nIndex = 0; nIndex < 50; ++nIndex )
{
MD5( sFileKey, nKeyLength, sFileKey );
}
}
if ( nEncRevision == 2 )
{
RC4InitKey( sFileKey, nKeyLength, sFState );
unFx = unFy = 0;
for ( int nJ = 0; nJ < 32; ++nJ )
{
sTest[nJ] = RC4DecryptByte( sFState, &unFx, &unFy, seUserKey->GetAt(nJ) );
}
bResult = ( memcmp( sTest, passwordPad, 32 ) == 0 );
}
else if ( nEncRevision == 3 )
{
memcpy( sTest, seUserKey->GetBuffer(), 32 );
for ( int nIndex = 19; nIndex >= 0; --nIndex )
{
for ( int nJ = 0; nJ < nKeyLength; ++nJ )
{
sTempKey[nJ] = sFileKey[nJ] ^ nIndex;
}
RC4InitKey( sTempKey, nKeyLength, sFState );
unFx = unFy = 0;
for ( int nJ = 0; nJ < 32; ++nJ )
{
sTest[nJ] = RC4DecryptByte( sFState, &unFx, &unFy, sTest[nJ] );
}
}
memcpy( pBuffer, passwordPad, 32);
memcpy( pBuffer + 32, seFileID->GetBuffer(), seFileID->GetLength());
MD5( pBuffer, 32 + seFileID->GetLength(), pBuffer );
bResult = ( memcmp( sTest, pBuffer, 16 ) == 0 );
}
else
{
bResult = FALSE;
}
MemUtilsFree( pBuffer );
return bResult;
}
//-------------------------------------------------------------------------------------------------------------------------------
// DecryptStream
//-------------------------------------------------------------------------------------------------------------------------------
DecryptStream::DecryptStream(Stream *pStream, unsigned char *sFileKey, CryptAlgorithm eType, int nKeyLength, int nObjectNum, int nObjectGen):
FilterStream(pStream)
{
m_eCryptType = eType;
for ( int nIndex = 0; nIndex < nKeyLength; ++nIndex )
{
m_sObjectKey[nIndex] = sFileKey[nIndex];
}
m_sObjectKey[nKeyLength + 0] = nObjectNum & 0xff;
m_sObjectKey[nKeyLength + 1] = (nObjectNum >> 8) & 0xff;
m_sObjectKey[nKeyLength + 2] = (nObjectNum >> 16) & 0xff;
m_sObjectKey[nKeyLength + 3] = nObjectGen & 0xff;
m_sObjectKey[nKeyLength + 4] = (nObjectGen >> 8) & 0xff;
int nLen = 0;
if ( m_eCryptType == cryptAES )
{
m_sObjectKey[nKeyLength + 5] = 0x73; // 's'
m_sObjectKey[nKeyLength + 6] = 0x41; // 'A'
m_sObjectKey[nKeyLength + 7] = 0x6c; // 'l'
m_sObjectKey[nKeyLength + 8] = 0x54; // 'T'
nLen = nKeyLength + 9;
}
else
{
nLen = nKeyLength + 5;
}
MD5( m_sObjectKey, nLen, m_sObjectKey );
if ( ( m_nObjectKeyLength = nKeyLength + 5 ) > 16 )
{
m_nObjectKeyLength = 16;
}
}
DecryptStream::~DecryptStream()
{
delete m_pStream;
}
void DecryptStream::Reset()
{
m_pStream->Reset();
switch ( m_eCryptType )
{
case cryptRC4:
m_oState.oRC4.unX = m_oState.oRC4.unY = 0;
RC4InitKey( m_sObjectKey, m_nObjectKeyLength, m_oState.oRC4.sState );
m_oState.oRC4.nBuffer = EOF;
break;
case cryptAES:
AESKeyExpansion( &m_oState.oAES, m_sObjectKey, m_nObjectKeyLength);
for ( int nIndex = 0; nIndex < 16; ++nIndex )
{
m_oState.oAES.sCBC[nIndex] = m_pStream->GetChar();
}
m_oState.oAES.nBufferIndex = 16;
break;
}
}
int DecryptStream::GetChar()
{
unsigned char sIn[16];
int nChar = EOF;
switch ( m_eCryptType )
{
case cryptRC4:
if ( m_oState.oRC4.nBuffer == EOF)
{
nChar = m_pStream->GetChar();
if ( nChar != EOF )
{
m_oState.oRC4.nBuffer = RC4DecryptByte( m_oState.oRC4.sState, &m_oState.oRC4.unX, &m_oState.oRC4.unY, (unsigned char)nChar);
}
}
nChar = m_oState.oRC4.nBuffer;
m_oState.oRC4.nBuffer = EOF;
break;
case cryptAES:
if ( m_oState.oAES.nBufferIndex == 16 )
{
for ( int nIndex = 0; nIndex < 16; ++nIndex )
{
if ( ( nChar = m_pStream->GetChar()) == EOF )
{
return EOF;
}
sIn[nIndex] = (unsigned char)nChar;
}
AESDecryptBlock( &m_oState.oAES, sIn, m_pStream->LookChar() == EOF);
}
if ( m_oState.oAES.nBufferIndex == 16 )
{
nChar = EOF;
}
else
{
nChar = m_oState.oAES.sBuffer[m_oState.oAES.nBufferIndex++];
}
break;
}
return nChar;
}
int DecryptStream::LookChar()
{
unsigned char sIn[16];
int nChar = EOF;
switch ( m_eCryptType )
{
case cryptRC4:
if ( m_oState.oRC4.nBuffer == EOF )
{
nChar = m_pStream->GetChar();
if ( nChar != EOF )
{
m_oState.oRC4.nBuffer = RC4DecryptByte( m_oState.oRC4.sState, &m_oState.oRC4.unX, &m_oState.oRC4.unY, (unsigned char)nChar );
}
}
nChar = m_oState.oRC4.nBuffer;
break;
case cryptAES:
if ( m_oState.oAES.nBufferIndex == 16 )
{
for ( int nIndex = 0; nIndex < 16; ++nIndex )
{
if ( ( nChar = m_pStream->GetChar() ) == EOF )
{
return EOF;
}
sIn[nIndex] = nChar;
}
AESDecryptBlock( &m_oState.oAES, sIn, m_pStream->LookChar() == EOF );
}
if ( m_oState.oAES.nBufferIndex == 16 )
{
nChar = EOF;
}
else
{
nChar = m_oState.oAES.sBuffer[m_oState.oAES.nBufferIndex];
}
break;
}
return nChar;
}
BOOL DecryptStream::IsBinary(BOOL bLast)
{
return m_pStream->IsBinary( bLast );
}
//-------------------------------------------------------------------------------------------------------------------------------
// RC4
//-------------------------------------------------------------------------------------------------------------------------------
static void RC4InitKey(unsigned char *sKey, int nKeyLen, unsigned char *sState)
{
for ( int nIndex = 0; nIndex < 256; ++nIndex )
sState[nIndex] = nIndex;
//unsigned char unIndex1 = 0, unIndex2 = 0;
//for ( int nIndex = 0; nIndex < 256; ++nIndex )
//{
// unIndex2 = ( sKey[unIndex1] + sState[nIndex] + unIndex2 ) % 256;
// unsigned char unTemp = sState[nIndex];
// sState[nIndex] = sState[unIndex2];
// sState[unIndex2] = nIndex;
// unIndex1 = (unIndex1 + 1) % nKeyLen;
//}
for ( int i = 0, j = 0; i < 256; i++ )
{
j = ( j + sKey[i % nKeyLen] + sState[i] ) % 256;
unsigned char unTemp = sState[i];
sState[i] = sState[j];
sState[j] = unTemp;
}
}
static unsigned char RC4DecryptByte(unsigned char *sState, unsigned char *pX, unsigned char *pY, unsigned char nChar)
{
unsigned char unX1 = *pX = (*pX + 1) % 256;
unsigned char unY1 = *pY = (sState[*pX] + *pY) % 256;
unsigned char unTempX = sState[unX1];
unsigned char unTempY = sState[unY1];
sState[unX1] = unTempY;
sState[unY1] = unTempX;
return nChar ^ sState[(unTempX + unTempY) % 256];
}
//-------------------------------------------------------------------------------------------------------------------------------
// AES
//-------------------------------------------------------------------------------------------------------------------------------
static unsigned char c_sSbox[256] =
{
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
};
static unsigned char c_sInvSbox[256] =
{
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
};
static unsigned int c_arrRCon[11] =
{
0x00000000, // íå èñïîëüçóåòñÿ
0x01000000,
0x02000000,
0x04000000,
0x08000000,
0x10000000,
0x20000000,
0x40000000,
0x80000000,
0x1b000000,
0x36000000
};
static inline unsigned int SubWord(unsigned int unValue)
{
return (c_sSbox[unValue >> 24] << 24) | (c_sSbox[(unValue >> 16) & 0xff] << 16) | (c_sSbox[(unValue >> 8) & 0xff] << 8) | c_sSbox[unValue & 0xff];
}
static inline unsigned int RotWord(unsigned int unValue)
{
return ((unValue << 8) & 0xffffffff) | (unValue >> 24);
}
static inline void InvSubBytes(unsigned char *sState)
{
for ( int nIndex = 0; nIndex < 16; ++nIndex )
{
sState[nIndex] = c_sInvSbox[sState[nIndex]];
}
}
static inline void InvShiftRows(unsigned char *sState)
{
unsigned char unTemp = 0;
unTemp = sState[7];
sState[7] = sState[6];
sState[6] = sState[5];
sState[5] = sState[4];
sState[4] = unTemp;
unTemp = sState[8];
sState[8] = sState[10];
sState[10] = unTemp;
unTemp = sState[9];
sState[9] = sState[11];
sState[11] = unTemp;
unTemp = sState[12];
sState[12] = sState[13];
sState[13] = sState[14];
sState[14] = sState[15];
sState[15] = unTemp;
}
// 09 ... nChar
static inline unsigned char Mult09(unsigned char nChar)
{
unsigned char nChar2 = ( nChar & 0x80) ? (( nChar << 1) ^ 0x1b) : ( nChar << 1);
unsigned char nChar4 = (nChar2 & 0x80) ? ((nChar2 << 1) ^ 0x1b) : (nChar2 << 1);
unsigned char nChar8 = (nChar4 & 0x80) ? ((nChar4 << 1) ^ 0x1b) : (nChar4 << 1);
return nChar ^ nChar8;
}
// 0b ... nChar
static inline unsigned char Mult0b(unsigned char nChar)
{
unsigned char nChar2 = ( nChar & 0x80) ? (( nChar << 1) ^ 0x1b) : ( nChar << 1);
unsigned char nChar4 = (nChar2 & 0x80) ? ((nChar2 << 1) ^ 0x1b) : (nChar2 << 1);
unsigned char nChar8 = (nChar4 & 0x80) ? ((nChar4 << 1) ^ 0x1b) : (nChar4 << 1);
return nChar ^ nChar2 ^ nChar8;
}
// 0d ... nChar
static inline unsigned char Mult0d(unsigned char nChar)
{
unsigned char nChar2 = ( nChar & 0x80) ? (( nChar << 1) ^ 0x1b) : ( nChar << 1);
unsigned char nChar4 = (nChar2 & 0x80) ? ((nChar2 << 1) ^ 0x1b) : (nChar2 << 1);
unsigned char nChar8 = (nChar4 & 0x80) ? ((nChar4 << 1) ^ 0x1b) : (nChar4 << 1);
return nChar ^ nChar4 ^ nChar8;
}
// 0e ... nChar
static inline unsigned char Mult0e(unsigned char nChar)
{
unsigned char nChar2 = ( nChar & 0x80) ? (( nChar << 1) ^ 0x1b) : ( nChar << 1);
unsigned char nChar4 = (nChar2 & 0x80) ? ((nChar2 << 1) ^ 0x1b) : (nChar2 << 1);
unsigned char nChar8 = (nChar4 & 0x80) ? ((nChar4 << 1) ^ 0x1b) : (nChar4 << 1);
return nChar2 ^ nChar4 ^ nChar8;
}
static inline void InvMixColumns(unsigned char *sState)
{
for (int nChar = 0; nChar < 4; ++nChar )
{
unsigned char unS0 = sState[nChar + 0];
unsigned char unS4 = sState[nChar + 4];
unsigned char unS8 = sState[nChar + 8];
unsigned char unS12 = sState[nChar + 12];
sState[nChar + 0] = Mult0e(unS0) ^ Mult0b(unS4) ^ Mult0d(unS8) ^ Mult09(unS12);
sState[nChar + 4] = Mult09(unS0) ^ Mult0e(unS4) ^ Mult0b(unS8) ^ Mult0d(unS12);
sState[nChar + 8] = Mult0d(unS0) ^ Mult09(unS4) ^ Mult0e(unS8) ^ Mult0b(unS12);
sState[nChar + 12] = Mult0b(unS0) ^ Mult0d(unS4) ^ Mult09(unS8) ^ Mult0e(unS12);
}
}
static inline void InvMixColumnsW(unsigned int *pW)
{
for ( int nChar = 0; nChar < 4; ++nChar )
{
unsigned char unS0 = pW[nChar] >> 24;
unsigned char unS1 = pW[nChar] >> 16;
unsigned char unS2 = pW[nChar] >> 8;
unsigned char unS3 = pW[nChar];
pW[nChar] = ( (Mult0e(unS0) ^ Mult0b(unS1) ^ Mult0d(unS2) ^ Mult09(unS3)) << 24)
| ( (Mult09(unS0) ^ Mult0e(unS1) ^ Mult0b(unS2) ^ Mult0d(unS3)) << 16)
| ( (Mult0d(unS0) ^ Mult09(unS1) ^ Mult0e(unS2) ^ Mult0b(unS3)) << 8)
| (Mult0b(unS0) ^ Mult0d(unS1) ^ Mult09(unS2) ^ Mult0e(unS3));
}
}
static inline void AddRoundKey(unsigned char *sState, unsigned int *pW)
{
for ( int nChar = 0; nChar < 4; ++nChar )
{
sState[nChar + 0] ^= pW[nChar] >> 24;
sState[nChar + 4] ^= pW[nChar] >> 16;
sState[nChar + 8] ^= pW[nChar] >> 8;
sState[nChar + 12] ^= pW[nChar];
}
}
static void AESKeyExpansion(DecryptAESState *pState, unsigned char *sObjectKey, int nObjectKeyLen)
{
//Ïðåäïîëàãàåòñÿ, ÷òî nObjectKeyLen == 16
for ( int nIndex = 0; nIndex < 4; ++nIndex )
{
pState->arrW[nIndex] = (sObjectKey[4 * nIndex] << 24) + (sObjectKey[4 * nIndex + 1] << 16) + (sObjectKey[4 * nIndex + 2] << 8) + sObjectKey[4 * nIndex + 3];
}
for ( int nIndex = 4; nIndex < 44; ++nIndex )
{
unsigned int unTemp = pState->arrW[nIndex - 1];
if ( !(nIndex & 3) )
{
unTemp = SubWord( RotWord(unTemp) ) ^ c_arrRCon[nIndex / 4];
}
pState->arrW[nIndex] = pState->arrW[nIndex - 4] ^ unTemp;
}
for ( int nRound = 1; nRound <= 9; ++nRound )
{
InvMixColumnsW( &pState->arrW[nRound * 4] );
}
}
static void AESDecryptBlock(DecryptAESState *pState, unsigned char *sIn, BOOL bLast)
{
// Íà÷àëüíîå ñîñòîÿíèå
for ( int nChar = 0; nChar < 4; ++nChar )
{
pState->sState[nChar + 0] = sIn[4 * nChar + 0];
pState->sState[nChar + 4] = sIn[4 * nChar + 1];
pState->sState[nChar + 8] = sIn[4 * nChar + 2];
pState->sState[nChar + 12] = sIn[4 * nChar + 3];
}
// Round 0
AddRoundKey(pState->sState, &pState->arrW[10 * 4]);
// Round 1-9
for ( int nRound = 9; nRound >= 1; --nRound )
{
InvSubBytes(pState->sState);
InvShiftRows(pState->sState);
InvMixColumns(pState->sState);
AddRoundKey(pState->sState, &pState->arrW[nRound * 4]);
}
// Round 10
InvSubBytes(pState->sState);
InvShiftRows(pState->sState);
AddRoundKey(pState->sState, &pState->arrW[0]);
// CBC
for ( int nChar = 0; nChar < 4; ++nChar )
{
pState->sBuffer[4 * nChar + 0] = pState->sState[nChar + 0] ^ pState->sCBC[4 * nChar + 0];
pState->sBuffer[4 * nChar + 1] = pState->sState[nChar + 4] ^ pState->sCBC[4 * nChar + 1];
pState->sBuffer[4 * nChar + 2] = pState->sState[nChar + 8] ^ pState->sCBC[4 * nChar + 2];
pState->sBuffer[4 * nChar + 3] = pState->sState[nChar + 12] ^ pState->sCBC[4 * nChar + 3];
}
// ñîõðàíÿåì áëîê ñ ñëåäóþùèé CBC
for ( int nIndex = 0; nIndex < 16; ++nIndex )
{
pState->sCBC[nIndex] = sIn[nIndex];
}
// remove padding
pState->nBufferIndex = 0;
if ( bLast )
{
int nLen = pState->sBuffer[15];
for ( int nIndex = 15; nIndex >= nLen; --nIndex )
{
pState->sBuffer[nIndex] = pState->sBuffer[nIndex - nLen];
}
pState->nBufferIndex = nLen;
}
}
//------------------------------------------------------------------------
// MD5 message digest
//------------------------------------------------------------------------
static inline unsigned long RotateLeft(unsigned long x, int r)
{
x &= 0xffffffff;
return ((x << r) | (x >> (32 - r))) & 0xffffffff;
}
static inline unsigned long MD5Round1(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long Xk, unsigned long s, unsigned long Ti)
{
return b + RotateLeft((a + ((b & c) | (~b & d)) + Xk + Ti), s);
}
static inline unsigned long MD5Round2(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long Xk, unsigned long s, unsigned long Ti)
{
return b + RotateLeft((a + ((b & d) | (c & ~d)) + Xk + Ti), s);
}
static inline unsigned long MD5Round3(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long Xk, unsigned long s, unsigned long Ti)
{
return b + RotateLeft((a + (b ^ c ^ d) + Xk + Ti), s);
}
static inline unsigned long MD5Round4(unsigned long a, unsigned long b, unsigned long c, unsigned long d, unsigned long Xk, unsigned long s, unsigned long Ti)
{
return b + RotateLeft((a + (c ^ (b | ~d)) + Xk + Ti), s);
}
static void MD5(unsigned char *sMessage, int nMessageLen, unsigned char *sDigest)
{
unsigned long x[16];
unsigned long a, b, c, d, aa, bb, cc, dd;
int i, j, k;
// Âû÷èñëèì êîëè÷åñòâî áëîêîâ 64x64
// ( nMessageLen + pad byte (0x80) + 8 bytes for length )
int nBlocksCount = (nMessageLen + 1 + 8 + 63) / 64;
// Èíèöèàëèçèðóåì a, b, c, d
a = 0x67452301;
b = 0xefcdab89;
c = 0x98badcfe;
d = 0x10325476;
k = 0;
for ( i = 0; i < nBlocksCount; ++i )
{
// Ñ÷èòûâàåì îäèí áëîê
for ( j = 0; j < 16 && k < nMessageLen - 3; ++j, k += 4 )
x[j] = (((((sMessage[k + 3] << 8) + sMessage[k + 2]) << 8) + sMessage[k + 1]) << 8) + sMessage[k];
if ( i == nBlocksCount - 1 )
{
if ( k == nMessageLen - 3 )
x[j] = 0x80000000 + (((sMessage[k + 2] << 8) + sMessage[k + 1]) << 8) + sMessage[k];
else if ( k == nMessageLen - 2 )
x[j] = 0x800000 + (sMessage[k + 1] << 8) + sMessage[k];
else if ( k == nMessageLen - 1 )
x[j] = 0x8000 + sMessage[k];
else
x[j] = 0x80;
++j;
while ( j < 16 )
x[j++] = 0;
x[14] = nMessageLen << 3;
}
// Ñîõðàíÿåì a, b, c, d
aa = a;
bb = b;
cc = c;
dd = d;
// Round 1
a = MD5Round1(a, b, c, d, x[0], 7, 0xd76aa478);
d = MD5Round1(d, a, b, c, x[1], 12, 0xe8c7b756);
c = MD5Round1(c, d, a, b, x[2], 17, 0x242070db);
b = MD5Round1(b, c, d, a, x[3], 22, 0xc1bdceee);
a = MD5Round1(a, b, c, d, x[4], 7, 0xf57c0faf);
d = MD5Round1(d, a, b, c, x[5], 12, 0x4787c62a);
c = MD5Round1(c, d, a, b, x[6], 17, 0xa8304613);
b = MD5Round1(b, c, d, a, x[7], 22, 0xfd469501);
a = MD5Round1(a, b, c, d, x[8], 7, 0x698098d8);
d = MD5Round1(d, a, b, c, x[9], 12, 0x8b44f7af);
c = MD5Round1(c, d, a, b, x[10], 17, 0xffff5bb1);
b = MD5Round1(b, c, d, a, x[11], 22, 0x895cd7be);
a = MD5Round1(a, b, c, d, x[12], 7, 0x6b901122);
d = MD5Round1(d, a, b, c, x[13], 12, 0xfd987193);
c = MD5Round1(c, d, a, b, x[14], 17, 0xa679438e);
b = MD5Round1(b, c, d, a, x[15], 22, 0x49b40821);
// Round 2
a = MD5Round2(a, b, c, d, x[1], 5, 0xf61e2562);
d = MD5Round2(d, a, b, c, x[6], 9, 0xc040b340);
c = MD5Round2(c, d, a, b, x[11], 14, 0x265e5a51);
b = MD5Round2(b, c, d, a, x[0], 20, 0xe9b6c7aa);
a = MD5Round2(a, b, c, d, x[5], 5, 0xd62f105d);
d = MD5Round2(d, a, b, c, x[10], 9, 0x02441453);
c = MD5Round2(c, d, a, b, x[15], 14, 0xd8a1e681);
b = MD5Round2(b, c, d, a, x[4], 20, 0xe7d3fbc8);
a = MD5Round2(a, b, c, d, x[9], 5, 0x21e1cde6);
d = MD5Round2(d, a, b, c, x[14], 9, 0xc33707d6);
c = MD5Round2(c, d, a, b, x[3], 14, 0xf4d50d87);
b = MD5Round2(b, c, d, a, x[8], 20, 0x455a14ed);
a = MD5Round2(a, b, c, d, x[13], 5, 0xa9e3e905);
d = MD5Round2(d, a, b, c, x[2], 9, 0xfcefa3f8);
c = MD5Round2(c, d, a, b, x[7], 14, 0x676f02d9);
b = MD5Round2(b, c, d, a, x[12], 20, 0x8d2a4c8a);
// Round 3
a = MD5Round3(a, b, c, d, x[5], 4, 0xfffa3942);
d = MD5Round3(d, a, b, c, x[8], 11, 0x8771f681);
c = MD5Round3(c, d, a, b, x[11], 16, 0x6d9d6122);
b = MD5Round3(b, c, d, a, x[14], 23, 0xfde5380c);
a = MD5Round3(a, b, c, d, x[1], 4, 0xa4beea44);
d = MD5Round3(d, a, b, c, x[4], 11, 0x4bdecfa9);
c = MD5Round3(c, d, a, b, x[7], 16, 0xf6bb4b60);
b = MD5Round3(b, c, d, a, x[10], 23, 0xbebfbc70);
a = MD5Round3(a, b, c, d, x[13], 4, 0x289b7ec6);
d = MD5Round3(d, a, b, c, x[0], 11, 0xeaa127fa);
c = MD5Round3(c, d, a, b, x[3], 16, 0xd4ef3085);
b = MD5Round3(b, c, d, a, x[6], 23, 0x04881d05);
a = MD5Round3(a, b, c, d, x[9], 4, 0xd9d4d039);
d = MD5Round3(d, a, b, c, x[12], 11, 0xe6db99e5);
c = MD5Round3(c, d, a, b, x[15], 16, 0x1fa27cf8);
b = MD5Round3(b, c, d, a, x[2], 23, 0xc4ac5665);
// Round 4
a = MD5Round4(a, b, c, d, x[0], 6, 0xf4292244);
d = MD5Round4(d, a, b, c, x[7], 10, 0x432aff97);
c = MD5Round4(c, d, a, b, x[14], 15, 0xab9423a7);
b = MD5Round4(b, c, d, a, x[5], 21, 0xfc93a039);
a = MD5Round4(a, b, c, d, x[12], 6, 0x655b59c3);
d = MD5Round4(d, a, b, c, x[3], 10, 0x8f0ccc92);
c = MD5Round4(c, d, a, b, x[10], 15, 0xffeff47d);
b = MD5Round4(b, c, d, a, x[1], 21, 0x85845dd1);
a = MD5Round4(a, b, c, d, x[8], 6, 0x6fa87e4f);
d = MD5Round4(d, a, b, c, x[15], 10, 0xfe2ce6e0);
c = MD5Round4(c, d, a, b, x[6], 15, 0xa3014314);
b = MD5Round4(b, c, d, a, x[13], 21, 0x4e0811a1);
a = MD5Round4(a, b, c, d, x[4], 6, 0xf7537e82);
d = MD5Round4(d, a, b, c, x[11], 10, 0xbd3af235);
c = MD5Round4(c, d, a, b, x[2], 15, 0x2ad7d2bb);
b = MD5Round4(b, c, d, a, x[9], 21, 0xeb86d391);
// Óâåëè÷èâàåì a, b, c, d
a += aa;
b += bb;
c += cc;
d += dd;
}
// Ðàçáèâàåì sDigest íà áàéòû
sDigest[0] = (unsigned char)( a & 0xff);
sDigest[1] = (unsigned char)((a >>= 8) & 0xff);
sDigest[2] = (unsigned char)((a >>= 8) & 0xff);
sDigest[3] = (unsigned char)((a >>= 8) & 0xff);
sDigest[4] = (unsigned char)( b & 0xff);
sDigest[5] = (unsigned char)((b >>= 8) & 0xff);
sDigest[6] = (unsigned char)((b >>= 8) & 0xff);
sDigest[7] = (unsigned char)((b >>= 8) & 0xff);
sDigest[8] = (unsigned char)( c & 0xff);
sDigest[9] = (unsigned char)((c >>= 8) & 0xff);
sDigest[10] = (unsigned char)((c >>= 8) & 0xff);
sDigest[11] = (unsigned char)((c >>= 8) & 0xff);
sDigest[12] = (unsigned char)( d & 0xff);
sDigest[13] = (unsigned char)((d >>= 8) & 0xff);
sDigest[14] = (unsigned char)((d >>= 8) & 0xff);
sDigest[15] = (unsigned char)((d >>= 8) & 0xff);
}