namespace vcl::pdf
{ namespace
{ // the maximum password length
constexpr sal_Int32 MD5_DIGEST_SIZE = 16;
// security 128 bit
constexpr sal_Int32 SECUR_128BIT_KEY = 16;
// maximum length of MD5 digest input, in step 2 of algorithm 3.1 // PDF spec ver. 1.4: see there for details
constexpr sal_Int32 MAXIMUM_RC4_KEY_LENGTH = SECUR_128BIT_KEY + 3 + 2;
//step 5, get the document ID, binary form
pDigest->update(io_rProperties.DocumentIdentifier.data(),
io_rProperties.DocumentIdentifier.size()); //get the digest
nMD5Sum = pDigest->finalize();
//step 6, only if 128 bit for (sal_Int32 i = 0; i < 50; i++)
{
nMD5Sum = ::comphelper::Hash::calculateHash(nMD5Sum.data(), nMD5Sum.size(),
::comphelper::HashType::MD5);
}
} else
bSuccess = false;
i_pTransporter->invalidate();
//Step 7 if (bSuccess)
{
io_rProperties.EncryptionKey.resize(MAXIMUM_RC4_KEY_LENGTH); for (sal_Int32 i = 0; i < MD5_DIGEST_SIZE; i++)
io_rProperties.EncryptionKey[i] = nMD5Sum[i];
} else
io_rProperties.EncryptionKey.clear();
rtlCipher aCipher = rtl_cipher_createARCFOUR(rtl_Cipher_ModeStream); if (aCipher)
{ //step 1 already done, data is in i_pPaddedOwnerPassword //step 2
::std::vector<unsignedchar> nMD5Sum(::comphelper::Hash::calculateHash(
i_pPaddedOwnerPassword, ENCRYPTED_PWD_SIZE, ::comphelper::HashType::MD5)); //step 3, only if 128 bit if (i_nKeyLength == SECUR_128BIT_KEY)
{
sal_Int32 i; for (i = 0; i < 50; i++)
{
nMD5Sum = ::comphelper::Hash::calculateHash(nMD5Sum.data(), nMD5Sum.size(),
::comphelper::HashType::MD5);
}
} //Step 4, the key is in nMD5Sum //step 5 already done, data is in i_pPaddedUserPassword //step 6 if (rtl_cipher_initARCFOUR(aCipher, rtl_Cipher_DirectionEncode, nMD5Sum.data(),
i_nKeyLength, nullptr, 0)
== rtl_Cipher_E_None)
{ // encrypt the user password using the key set above
rtl_cipher_encodeARCFOUR(
aCipher, i_pPaddedUserPassword, ENCRYPTED_PWD_SIZE, // the data to be encrypted
io_rOValue.data(), sal_Int32(io_rOValue.size())); //encrypted data //Step 7, only if 128 bit if (i_nKeyLength == SECUR_128BIT_KEY)
{
sal_uInt32 i;
size_t y;
sal_uInt8 nLocalKey[SECUR_128BIT_KEY]; // 16 = 128 bit key
for (i = 1; i <= 19; i++) // do it 19 times, start with 1
{ for (y = 0; y < sizeof(nLocalKey); y++)
nLocalKey[y] = static_cast<sal_uInt8>(nMD5Sum[y] ^ i);
if (rtl_cipher_initARCFOUR(aCipher, rtl_Cipher_DirectionEncode, nLocalKey,
SECUR_128BIT_KEY, nullptr, 0) //destination data area, on init can be NULL
!= rtl_Cipher_E_None)
{
bSuccess = false; break;
}
rtl_cipher_encodeARCFOUR(
aCipher, io_rOValue.data(),
sal_Int32(io_rOValue.size()), // the data to be encrypted
io_rOValue.data(), sal_Int32(io_rOValue.size())); // encrypted data, can be the same as the input, encrypt "in place" //step 8, store in class data member
}
}
} else
bSuccess = false;
} else
bSuccess = false;
if (aCipher)
rtl_cipher_destroyARCFOUR(aCipher);
if (!bSuccess)
io_rOValue.clear(); return bSuccess;
}
::comphelper::Hash aDigest(::comphelper::HashType::MD5);
rtlCipher aCipher = rtl_cipher_createARCFOUR(rtl_Cipher_ModeStream); if (aCipher)
{ //step 1, common to both 3.4 and 3.5 if (computeEncryptionKey(i_pTransporter, io_rProperties, i_nAccessPermissions))
{ // prepare encryption key for object for (sal_Int32 i = i_nKeyLength, y = 0; y < 5; y++)
io_rProperties.EncryptionKey[i++] = 0;
//or 3.5, for 128 bit security //step6, initialize the last 16 bytes of the encrypted user password to 0 for (sal_uInt32 i = MD5_DIGEST_SIZE; i < sal_uInt32(io_rProperties.UValue.size()); i++)
io_rProperties.UValue[i] = 0; //steps 2 and 3
aDigest.update(s_nPadString.data(), sizeof(s_nPadString));
aDigest.update(io_rProperties.DocumentIdentifier.data(),
io_rProperties.DocumentIdentifier.size());
::std::vector<unsignedchar> const nMD5Sum(aDigest.finalize()); //Step 4
rtl_cipher_initARCFOUR(aCipher, rtl_Cipher_DirectionEncode,
io_rProperties.EncryptionKey.data(), SECUR_128BIT_KEY, nullptr, 0); //destination data area
rtl_cipher_encodeARCFOUR(
aCipher, nMD5Sum.data(), nMD5Sum.size(), // the data to be encrypted
io_rProperties.UValue.data(),
SECUR_128BIT_KEY); //encrypted data, stored in class data member //step 5
sal_uInt32 i;
size_t y;
sal_uInt8 nLocalKey[SECUR_128BIT_KEY];
for (i = 1; i <= 19; i++) // do it 19 times, start with 1
{ for (y = 0; y < sizeof(nLocalKey); y++)
nLocalKey[y] = static_cast<sal_uInt8>(io_rProperties.EncryptionKey[y] ^ i);
rtl_cipher_initARCFOUR(aCipher, rtl_Cipher_DirectionEncode, nLocalKey,
SECUR_128BIT_KEY, // key and key length
nullptr, 0); //destination data area, on init can be NULL
rtl_cipher_encodeARCFOUR(
aCipher, io_rProperties.UValue.data(),
SECUR_128BIT_KEY, // the data to be encrypted
io_rProperties.UValue.data(),
SECUR_128BIT_KEY); // encrypted data, can be the same as the input, encrypt "in place"
}
} else
bSuccess = false;
} else
bSuccess = false;
if (aCipher)
rtl_cipher_destroyARCFOUR(aCipher);
if (!bSuccess)
io_rProperties.UValue.clear(); return bSuccess;
}
if (!bSuccess)
{
rProperties.clear();
} return bSuccess;
}
/* this function implements part of the PDF spec algorithm 3.1 in encryption */ void PDFEncryptor::setupKeysAndCheck(vcl::PDFEncryptionProperties& rProperties)
{ // sanity check if (rProperties.OValue.size() != ENCRYPTED_PWD_SIZE
|| rProperties.UValue.size() != ENCRYPTED_PWD_SIZE
|| rProperties.EncryptionKey.size() != MAXIMUM_RC4_KEY_LENGTH)
{ // the field lengths are invalid ? This was not setup by initEncryption. // do not encrypt after all
rProperties.clear();
OSL_ENSURE(false, "encryption data failed sanity check, encryption disabled");
} else// setup key lengths
{
m_nAccessPermissions = computeAccessPermissions(rProperties, m_nKeyLength, m_nRC4KeyLength);
}
}
// do the MD5 hash autoconst nMD5Sum
= comphelper::Hash::calculateHash(aKey.data(), aKey.size(), ::comphelper::HashType::MD5);
// initialize the RC4 with the key // key length: see algorithm 3.1, step 4: (N+5) max 16
rtl_cipher_initARCFOUR(m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum.data(), getRC4KeyLength(),
nullptr, 0);
}
/* implement the encryption part of the PDF spec encryption algorithm 3.1 */ void PDFEncryptor::encrypt(constvoid* pInput, sal_uInt64 nInputSize,
std::vector<sal_uInt8>& rOutput, sal_uInt64 nOutputsSize)
{
rtl_cipher_encodeARCFOUR(m_aCipher, pInput, sal_Size(nInputSize), rOutput.data(),
sal_Size(nOutputsSize));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.