Files
core/PdfReader/Src/Decrypt.cpp
Ilya.Kirillov 65d72ae4ec Убраны лишние файлы. Все файлы сконвертированы в UTF8.
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@62550 954022d7-b5bf-4e40-9824-e11837661b57
2016-05-21 00:02:55 +03:00

818 lines
27 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <string.h>
#include "MemoryUtils.h"
#include "Decrypt.h"
namespace PdfReader
{
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);
}
}