Files
core/ASCOfficePDFWriter/PdfWriterLib/Encrypt.cpp

431 lines
16 KiB
C++

#include "Encrypt.h"
#include "Objects.h"
// Основной шаг в алгоритме MD5.
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
// The core of the MD5 algorithm, this alters an existing MD5 hash to
// reflect the addition of 16 longwords of new data. MD5Update blocks
// the data and converts bytes into longwords for this routine.
static void MD5ByteReverse(BYTE *pBuf, unsigned int nLongs)
{
unsigned int nTemp = 0;
do
{
nTemp = (unsigned int) ((unsigned int) pBuf[3] << 8 | pBuf[2]) << 16 | ((unsigned int) pBuf[1] << 8 | pBuf[0]);
*(unsigned int *) pBuf = nTemp;
pBuf += 4;
}
while (--nLongs);
}
static void MD5Transform (unsigned int anBuf[4], const unsigned int anIn[16])
{
register unsigned int a, b, c, d;
a = anBuf[0];
b = anBuf[1];
c = anBuf[2];
d = anBuf[3];
MD5STEP( OptFunc1, a, b, c, d, anIn[0] + 0xd76aa478, 7);
MD5STEP( OptFunc1, d, a, b, c, anIn[1] + 0xe8c7b756, 12);
MD5STEP( OptFunc1, c, d, a, b, anIn[2] + 0x242070db, 17);
MD5STEP( OptFunc1, b, c, d, a, anIn[3] + 0xc1bdceee, 22);
MD5STEP( OptFunc1, a, b, c, d, anIn[4] + 0xf57c0faf, 7);
MD5STEP( OptFunc1, d, a, b, c, anIn[5] + 0x4787c62a, 12);
MD5STEP( OptFunc1, c, d, a, b, anIn[6] + 0xa8304613, 17);
MD5STEP( OptFunc1, b, c, d, a, anIn[7] + 0xfd469501, 22);
MD5STEP( OptFunc1, a, b, c, d, anIn[8] + 0x698098d8, 7);
MD5STEP( OptFunc1, d, a, b, c, anIn[9] + 0x8b44f7af, 12);
MD5STEP( OptFunc1, c, d, a, b, anIn[10] + 0xffff5bb1, 17);
MD5STEP( OptFunc1, b, c, d, a, anIn[11] + 0x895cd7be, 22);
MD5STEP( OptFunc1, a, b, c, d, anIn[12] + 0x6b901122, 7);
MD5STEP( OptFunc1, d, a, b, c, anIn[13] + 0xfd987193, 12);
MD5STEP( OptFunc1, c, d, a, b, anIn[14] + 0xa679438e, 17);
MD5STEP( OptFunc1, b, c, d, a, anIn[15] + 0x49b40821, 22);
MD5STEP( OptFunc2, a, b, c, d, anIn[1] + 0xf61e2562, 5);
MD5STEP( OptFunc2, d, a, b, c, anIn[6] + 0xc040b340, 9);
MD5STEP( OptFunc2, c, d, a, b, anIn[11] + 0x265e5a51, 14);
MD5STEP( OptFunc2, b, c, d, a, anIn[0] + 0xe9b6c7aa, 20);
MD5STEP( OptFunc2, a, b, c, d, anIn[5] + 0xd62f105d, 5);
MD5STEP( OptFunc2, d, a, b, c, anIn[10] + 0x02441453, 9);
MD5STEP( OptFunc2, c, d, a, b, anIn[15] + 0xd8a1e681, 14);
MD5STEP( OptFunc2, b, c, d, a, anIn[4] + 0xe7d3fbc8, 20);
MD5STEP( OptFunc2, a, b, c, d, anIn[9] + 0x21e1cde6, 5);
MD5STEP( OptFunc2, d, a, b, c, anIn[14] + 0xc33707d6, 9);
MD5STEP( OptFunc2, c, d, a, b, anIn[3] + 0xf4d50d87, 14);
MD5STEP( OptFunc2, b, c, d, a, anIn[8] + 0x455a14ed, 20);
MD5STEP( OptFunc2, a, b, c, d, anIn[13] + 0xa9e3e905, 5);
MD5STEP( OptFunc2, d, a, b, c, anIn[2] + 0xfcefa3f8, 9);
MD5STEP( OptFunc2, c, d, a, b, anIn[7] + 0x676f02d9, 14);
MD5STEP( OptFunc2, b, c, d, a, anIn[12] + 0x8d2a4c8a, 20);
MD5STEP( OptFunc3, a, b, c, d, anIn[5] + 0xfffa3942, 4);
MD5STEP( OptFunc3, d, a, b, c, anIn[8] + 0x8771f681, 11);
MD5STEP( OptFunc3, c, d, a, b, anIn[11] + 0x6d9d6122, 16);
MD5STEP( OptFunc3, b, c, d, a, anIn[14] + 0xfde5380c, 23);
MD5STEP( OptFunc3, a, b, c, d, anIn[1] + 0xa4beea44, 4);
MD5STEP( OptFunc3, d, a, b, c, anIn[4] + 0x4bdecfa9, 11);
MD5STEP( OptFunc3, c, d, a, b, anIn[7] + 0xf6bb4b60, 16);
MD5STEP( OptFunc3, b, c, d, a, anIn[10] + 0xbebfbc70, 23);
MD5STEP( OptFunc3, a, b, c, d, anIn[13] + 0x289b7ec6, 4);
MD5STEP( OptFunc3, d, a, b, c, anIn[0] + 0xeaa127fa, 11);
MD5STEP( OptFunc3, c, d, a, b, anIn[3] + 0xd4ef3085, 16);
MD5STEP( OptFunc3, b, c, d, a, anIn[6] + 0x04881d05, 23);
MD5STEP( OptFunc3, a, b, c, d, anIn[9] + 0xd9d4d039, 4);
MD5STEP( OptFunc3, d, a, b, c, anIn[12] + 0xe6db99e5, 11);
MD5STEP( OptFunc3, c, d, a, b, anIn[15] + 0x1fa27cf8, 16);
MD5STEP( OptFunc3, b, c, d, a, anIn[2] + 0xc4ac5665, 23);
MD5STEP( OptFunc4, a, b, c, d, anIn[0] + 0xf4292244, 6);
MD5STEP( OptFunc4, d, a, b, c, anIn[7] + 0x432aff97, 10);
MD5STEP( OptFunc4, c, d, a, b, anIn[14] + 0xab9423a7, 15);
MD5STEP( OptFunc4, b, c, d, a, anIn[5] + 0xfc93a039, 21);
MD5STEP( OptFunc4, a, b, c, d, anIn[12] + 0x655b59c3, 6);
MD5STEP( OptFunc4, d, a, b, c, anIn[3] + 0x8f0ccc92, 10);
MD5STEP( OptFunc4, c, d, a, b, anIn[10] + 0xffeff47d, 15);
MD5STEP( OptFunc4, b, c, d, a, anIn[1] + 0x85845dd1, 21);
MD5STEP( OptFunc4, a, b, c, d, anIn[8] + 0x6fa87e4f, 6);
MD5STEP( OptFunc4, d, a, b, c, anIn[15] + 0xfe2ce6e0, 10);
MD5STEP( OptFunc4, c, d, a, b, anIn[6] + 0xa3014314, 15);
MD5STEP( OptFunc4, b, c, d, a, anIn[13] + 0x4e0811a1, 21);
MD5STEP( OptFunc4, a, b, c, d, anIn[4] + 0xf7537e82, 6);
MD5STEP( OptFunc4, d, a, b, c, anIn[11] + 0xbd3af235, 10);
MD5STEP( OptFunc4, c, d, a, b, anIn[2] + 0x2ad7d2bb, 15);
MD5STEP( OptFunc4, b, c, d, a, anIn[9] + 0xeb86d391, 21);
anBuf[0] += a;
anBuf[1] += b;
anBuf[2] += c;
anBuf[3] += d;
}
void MD5Init (MD5Context *pContext)
{
pContext->anBuf[0] = 0x67452301;
pContext->anBuf[1] = 0xefcdab89;
pContext->anBuf[2] = 0x98badcfe;
pContext->anBuf[3] = 0x10325476;
pContext->anBits[0] = 0;
pContext->anBits[1] = 0;
}
void MD5Update(MD5Context *pContext, const BYTE *pBuf, unsigned int nLen)
{
// Update bitcount
unsigned int nTempBit = pContext->anBits[0];
if ( ( pContext->anBits[0] = nTempBit + ((unsigned int) nLen << 3) ) < nTempBit )
pContext->anBits[1]++; // Carry from low to high
pContext->anBits[1] += nLen >> 29;
nTempBit = (nTempBit >> 3) & 0x3f; // Bytes already in shsInfo->data
// Handle any leading odd-sized chunks
if ( nTempBit )
{
BYTE *pTemp = (BYTE *) pContext->anIn + nTempBit;
nTempBit = 64 - nTempBit;
if ( nLen < nTempBit && pBuf )
{
UtilsMemCpy( pTemp, pBuf, nLen);
return;
}
if (pBuf ) UtilsMemCpy( pTemp, pBuf, nTempBit);
MD5ByteReverse( pContext->anIn, 16);
MD5Transform( pContext->anBuf, (unsigned int *) pContext->anIn);
pBuf += nTempBit;
nLen -= nTempBit;
}
// Process data in 64-byte chunks
while ( nLen >= 64 )
{
UtilsMemCpy( pContext->anIn, pBuf, 64);
MD5ByteReverse( pContext->anIn, 16);
MD5Transform( pContext->anBuf, (unsigned int *) pContext->anIn);
pBuf += 64;
nLen -= 64;
}
// Handle any remaining bytes of data.
UtilsMemCpy( pContext->anIn, pBuf, nLen);
}
// Final wrapup - pad to 64-byte boundary with the bit pattern
// 1 0* (64-bit count of bits processed, MSB-first)
void MD5Final (BYTE anDigest[16], MD5Context *pContext)
{
// Вычисляем количество байтов по модулю 64
unsigned int nCount = ( pContext->anBits[0] >> 3 ) & 0x3F;
// Устанавливаем первый символ в дополнительной строке(padding) значением 0x80.
// Это безопасно, поскольку всегда как минимум один байт свободен.
BYTE *pTemp = pContext->anIn + nCount;
*pTemp++ = 0x80;
// Bytes of padding needed to make 64 bytes
nCount = 64 - 1 - nCount;
// Pad out to 56 mod 64
if ( nCount < 8 )
{
// Two lots of padding: Pad the first block to 64 bytes
UtilsMemSet( pTemp, 0, nCount);
MD5ByteReverse( pContext->anIn, 16);
MD5Transform( pContext->anBuf, (unsigned int *) pContext->anIn);
// Now fill the next block with 56 bytes
UtilsMemSet( pContext->anIn, 0, 56);
}
else
{
// Pad block to 56 bytes
UtilsMemSet( pTemp, 0, nCount - 8);
}
MD5ByteReverse( pContext->anIn, 14);
// Append length in bits and transform
((unsigned int *) pContext->anIn)[14] = pContext->anBits[0];
((unsigned int *) pContext->anIn)[15] = pContext->anBits[1];
MD5Transform( pContext->anBuf, (unsigned int *) pContext->anIn);
MD5ByteReverse( (BYTE *)pContext->anBuf, 4);
UtilsMemCpy( (BYTE *)anDigest, (BYTE *)pContext->anBuf, 16);
UtilsMemSet( (BYTE *)pContext, 0, sizeof (pContext)); // In case it's sensitive
}
//-------- EncryptRecPtr - Вспомогательные функции ---------------------------------------------
void ARC4Init (ARC4ContextRec *pContext, const BYTE *pKey, unsigned int nKeyLen)
{
BYTE pTempArray[ARC4_BUF_SIZE];
unsigned int nJ = 0;
for ( unsigned int nIndex = 0; nIndex < ARC4_BUF_SIZE; nIndex++)
pContext->anState[nIndex] = nIndex;
for ( unsigned int nIndex = 0; nIndex < ARC4_BUF_SIZE; nIndex++)
pTempArray[nIndex] = pKey[nIndex % nKeyLen];
for ( unsigned int nIndex = 0; nIndex < ARC4_BUF_SIZE; nIndex++)
{
nJ = ( nJ + pContext->anState[nIndex] + pTempArray[nIndex] ) % ARC4_BUF_SIZE;
BYTE nTemp = pContext->anState[nIndex];
pContext->anState[nIndex] = pContext->anState[nJ];
pContext->anState[nJ] = nTemp;
}
pContext->nIndex1 = 0;
pContext->nIndex2 = 0;
}
void ARC4CryptBuf (ARC4ContextRec *pContext, const BYTE *pIn, BYTE *pOut, unsigned int nLen )
{
for ( unsigned int nIndex = 0; nIndex < nLen; nIndex++)
{
pContext->nIndex1 = ( pContext->nIndex1 + 1 ) % 256;
pContext->nIndex2 = ( pContext->nIndex2 + pContext->anState[ pContext->nIndex1 ] ) % 256;
BYTE nTemp = pContext->anState[ pContext->nIndex1 ];
pContext->anState[ pContext->nIndex1 ] = pContext->anState[ pContext->nIndex2 ];
pContext->anState[ pContext->nIndex2 ] = nTemp;
unsigned int nTempIndex = ( pContext->anState[ pContext->nIndex1 ] + pContext->anState[ pContext->nIndex2 ] ) % 256;
BYTE nKoef = pContext->anState[nTempIndex];
pOut[nIndex] = pIn[nIndex] ^ nKoef;
}
}
//-------- EncryptRecPtr - Основные функции ----------------------------------------------------
void PadOrTrancatePassword (const char *sPassword, BYTE *pNewPassword)
{
unsigned int nLen = UtilsStrLen( sPassword, PASSWD_LEN + 1);
UtilsMemSet( pNewPassword, 0x00, PASSWD_LEN);
if ( nLen >= PASSWD_LEN )
UtilsMemCpy( pNewPassword, (BYTE*)sPassword, PASSWD_LEN);
else
{
if ( nLen > 0 )
UtilsMemCpy( pNewPassword, (BYTE*)sPassword, nLen);
UtilsMemCpy( pNewPassword + nLen, c_sPaddingString, PASSWD_LEN - nLen);
}
}
void EncryptInit (EncryptRecPtr pAttr)
{
UtilsMemSet( pAttr, 0, sizeof(EncryptRec) );
pAttr->eMode = EncryptR2;
pAttr->nKeyLen = 5;
UtilsMemCpy( pAttr->anOwnerPassword, c_sPaddingString, PASSWD_LEN);
UtilsMemCpy( pAttr->anUserPassword, c_sPaddingString, PASSWD_LEN);
pAttr->nPermission = ENABLE_PRINT | ENABLE_EDIT_ALL | ENABLE_COPY | ENABLE_EDIT | PERMISSION_PAD;
}
void EncryptCreateUserKey (EncryptRecPtr pAttr)
{
ARC4ContextRec oContext;
// Algorithm 3.4/5 step1
// Algorithm 3.4 step2
ARC4Init( &oContext, pAttr->anEncryptionKey, pAttr->nKeyLen);
ARC4CryptBuf( &oContext, c_sPaddingString, pAttr->anUserKey, PASSWD_LEN);
if ( EncryptR3 == pAttr->eMode )
{
MD5Context oMD5Context;
BYTE anDigest[MD5_KEY_LEN];
BYTE anDigest2[MD5_KEY_LEN];
// Algorithm 3.5 step2 (same as Algorithm3.2 step2)
MD5Init( &oMD5Context);
MD5Update( &oMD5Context, c_sPaddingString, PASSWD_LEN);
// Algorithm 3.5 step3
MD5Update( &oMD5Context, pAttr->anEncryptID, ID_LEN);
MD5Final( anDigest, &oMD5Context);
// Algorithm 3.5 step4
ARC4Init( &oContext, pAttr->anEncryptionKey, pAttr->nKeyLen);
ARC4CryptBuf( &oContext, anDigest, anDigest2, MD5_KEY_LEN);
// Algorithm 3.5 step5 */
for ( unsigned int nI = 1; nI <= 19; nI++ )
{
BYTE pNewKey[MD5_KEY_LEN];
for ( unsigned int nJ = 0; nJ < pAttr->nKeyLen; nJ++ )
pNewKey[nJ] = pAttr->anEncryptionKey[nJ] ^ nI;
UtilsMemCpy( anDigest, anDigest2, MD5_KEY_LEN);
ARC4Init( &oContext, pNewKey, pAttr->nKeyLen );
ARC4CryptBuf( &oContext, anDigest, anDigest2, MD5_KEY_LEN );
}
// use the result of Algorithm 3.4 as 'arbitrary padding'
UtilsMemSet( pAttr->anUserKey, 0, PASSWD_LEN);
UtilsMemCpy( pAttr->anUserKey, anDigest2, MD5_KEY_LEN);
}
}
void EncryptCreateOwnerKey (EncryptRecPtr pAttr)
{
ARC4ContextRec oARC4Context;
MD5Context oMD5Context;
BYTE anDigest[MD5_KEY_LEN];
BYTE anTempPassword[PASSWD_LEN];
// create md5-digest using the value of anOwnerPassword
// Algorithm 3.3 step 2
MD5Init( &oMD5Context);
MD5Update( &oMD5Context, pAttr->anOwnerPassword, PASSWD_LEN);
MD5Final( anDigest, &oMD5Context);
// Algorithm 3.3 step 3 (Revision 3 only)
if ( EncryptR3 == pAttr->eMode )
{
for (unsigned int nIndex = 0; nIndex < 50; nIndex++)
{
MD5Init( &oMD5Context);
//MD5Update( &oMD5Context, anDigest, MD5_KEY_LEN);
MD5Update ( &oMD5Context, anDigest, pAttr->nKeyLen );
MD5Final( anDigest, &oMD5Context);
}
}
// Algorithm 3.3 step 4
ARC4Init( &oARC4Context, anDigest, pAttr->nKeyLen );
// Algorithm 3.3 step 6
ARC4CryptBuf( &oARC4Context, pAttr->anUserPassword, anTempPassword, PASSWD_LEN);
// Algorithm 3.3 step 7
if ( EncryptR3 == pAttr->eMode )
{
BYTE anTempPassword2[PASSWD_LEN];
for (unsigned int i = 1; i <= 19; i++)
{
BYTE anNewKey[MD5_KEY_LEN];
for (unsigned int j = 0; j < pAttr->nKeyLen; j++)
anNewKey[j] = anDigest[j] ^ i;
UtilsMemCpy( anTempPassword2, anTempPassword, PASSWD_LEN);
ARC4Init( &oARC4Context, anNewKey, pAttr->nKeyLen);
ARC4CryptBuf( &oARC4Context, anTempPassword2, anTempPassword, PASSWD_LEN);
}
}
// Algorithm 3.3 step 8
UtilsMemCpy( pAttr->anOwnerKey, anTempPassword, PASSWD_LEN);
}
void EncryptCreateEncryptionKey (EncryptRecPtr pAttr)
{
MD5Context oMD5Context;
BYTE anTempFlag[4];
// Algorithm3.2 step2
MD5Init( &oMD5Context);
MD5Update( &oMD5Context, pAttr->anUserPassword, PASSWD_LEN);
// Algorithm3.2 step3
MD5Update( &oMD5Context, pAttr->anOwnerKey, PASSWD_LEN);
// Algorithm3.2 step4
anTempFlag[0] = pAttr->nPermission;
anTempFlag[1] = (pAttr->nPermission >> 8);
anTempFlag[2] = (pAttr->nPermission >> 16);
anTempFlag[3] = (pAttr->nPermission >> 24);
MD5Update( &oMD5Context, anTempFlag, 4);
// Algorithm3.2 step5
MD5Update(&oMD5Context, pAttr->anEncryptID, ID_LEN);
MD5Final( pAttr->anEncryptionKey, &oMD5Context);
// Algorithm 3.2 step6 (Revision 3 only)
if ( EncryptR3 == pAttr->eMode )
{
for ( unsigned int nIndex = 0; nIndex < 50; nIndex++)
{
MD5Init( &oMD5Context);
MD5Update( &oMD5Context, pAttr->anEncryptionKey, pAttr->nKeyLen);
MD5Final( pAttr->anEncryptionKey, &oMD5Context);
}
}
}
void EncryptInitKey (EncryptRecPtr pAttr, unsigned int nObjectId, unsigned short nGenNo )
{
MD5Context oContext;
pAttr->anEncryptionKey[pAttr->nKeyLen] = nObjectId;
pAttr->anEncryptionKey[pAttr->nKeyLen + 1] = (nObjectId >> 8);
pAttr->anEncryptionKey[pAttr->nKeyLen + 2] = (nObjectId >> 16);
pAttr->anEncryptionKey[pAttr->nKeyLen + 3] = nGenNo;
pAttr->anEncryptionKey[pAttr->nKeyLen + 4] = (nGenNo >> 8);
MD5Init( &oContext);
MD5Update( &oContext, pAttr->anEncryptionKey, pAttr->nKeyLen + 5);
MD5Final( pAttr->anMD5EncryptionKey, &oContext);
unsigned int nKeyLen = ( pAttr->nKeyLen + 5 > ENCRYPT_KEY_MAX) ? ENCRYPT_KEY_MAX : pAttr->nKeyLen + 5;
ARC4Init( &pAttr->oARC4Context, pAttr->anMD5EncryptionKey, nKeyLen );
}
void EncryptReset (EncryptRecPtr pAttr)
{
unsigned int nKeyLen = ( pAttr->nKeyLen + 5 > ENCRYPT_KEY_MAX) ? ENCRYPT_KEY_MAX : pAttr->nKeyLen + 5;
ARC4Init( &pAttr->oARC4Context, pAttr->anMD5EncryptionKey, nKeyLen );
}
void EncryptCryptBuf (EncryptRecPtr pAttr, const BYTE *pSrc, BYTE *pDst, unsigned int nLen)
{
ARC4CryptBuf( &pAttr->oARC4Context, pSrc, pDst, nLen);
}