mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Encryption bugfixing
This commit is contained in:
@ -316,10 +316,16 @@ PDFOperationResult PDFDocumentWriter::write(QIODevice* device, const PDFDocument
|
|||||||
device->write(entry.object.isNull() ? "f" : "n");
|
device->write(entry.object.isNull() ? "f" : "n");
|
||||||
writeCRLF(device);
|
writeCRLF(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Jakub Melka: Adjust trailer dictionary, to be really dictionary, not a stream
|
||||||
|
PDFDictionary trailerDictionary = *document->getTrailerDictionary();
|
||||||
|
trailerDictionary.removeEntry("XRefStm");
|
||||||
|
PDFObject trailerDictionaryObject = PDFObject::createDictionary(std::make_shared<PDFDictionary>(qMove(trailerDictionary)));
|
||||||
|
|
||||||
device->write("trailer");
|
device->write("trailer");
|
||||||
writeCRLF(device);
|
writeCRLF(device);
|
||||||
PDFWriteObjectVisitor trailerVisitor(device);
|
PDFWriteObjectVisitor trailerVisitor(device);
|
||||||
storage.getTrailerDictionary().accept(&trailerVisitor);
|
trailerDictionaryObject.accept(&trailerVisitor);
|
||||||
writeCRLF(device);
|
writeCRLF(device);
|
||||||
device->write("startxref");
|
device->write("startxref");
|
||||||
writeCRLF(device);
|
writeCRLF(device);
|
||||||
@ -339,7 +345,7 @@ void PDFDocumentWriter::writeCRLF(QIODevice* device)
|
|||||||
|
|
||||||
void PDFDocumentWriter::writeObjectHeader(QIODevice* device, PDFObjectReference reference)
|
void PDFDocumentWriter::writeObjectHeader(QIODevice* device, PDFObjectReference reference)
|
||||||
{
|
{
|
||||||
QString objectHeader = QString("%1 %2 obj").arg(QString::number(reference.objectNumber)).arg(QString::number(reference.generation));
|
QString objectHeader = QString("%1 %2 obj").arg(QString::number(reference.objectNumber), QString::number(reference.generation));
|
||||||
device->write(objectHeader.toLatin1());
|
device->write(objectHeader.toLatin1());
|
||||||
writeCRLF(device);
|
writeCRLF(device);
|
||||||
}
|
}
|
||||||
|
@ -708,7 +708,6 @@ QByteArray PDFStandardSecurityHandler::decryptUsingFilter(const QByteArray& data
|
|||||||
{
|
{
|
||||||
QByteArray initializationVector;
|
QByteArray initializationVector;
|
||||||
QByteArray paddedData;
|
QByteArray paddedData;
|
||||||
int paddingRemainder = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto prepareAES_data = [](const QByteArray& data)
|
auto prepareAES_data = [](const QByteArray& data)
|
||||||
@ -726,18 +725,31 @@ QByteArray PDFStandardSecurityHandler::decryptUsingFilter(const QByteArray& data
|
|||||||
|
|
||||||
result.paddedData = data.mid(AES_BLOCK_SIZE);
|
result.paddedData = data.mid(AES_BLOCK_SIZE);
|
||||||
|
|
||||||
// Add padding remainder according to the specification
|
// Remove errorneous data - we must have a data of multiple of AES_BLOCK_SIZE
|
||||||
int size = result.paddedData.size();
|
const int remainder = result.paddedData.size() % AES_BLOCK_SIZE;
|
||||||
result.paddingRemainder = AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE);
|
if (remainder != 0)
|
||||||
|
|
||||||
for (int i = 0; i < result.paddingRemainder; ++i)
|
|
||||||
{
|
{
|
||||||
result.paddedData.push_back(result.paddingRemainder);
|
result.paddedData = result.paddedData.left(result.paddedData.size() - remainder);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto removeAES_padding = [](const QByteArray& data)
|
||||||
|
{
|
||||||
|
if (data.isEmpty())
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If padding doesnt fit from 1 to AES_BLOCK_SIZE, then it is
|
||||||
|
// an error, but just clamp the value.
|
||||||
|
const int padding = data.back();
|
||||||
|
const int clampedPadding = qBound(1, padding, AES_BLOCK_SIZE);
|
||||||
|
|
||||||
|
return data.left(data.size() - clampedPadding);
|
||||||
|
};
|
||||||
|
|
||||||
switch (filter.type)
|
switch (filter.type)
|
||||||
{
|
{
|
||||||
case CryptFilterType::None: // The application shall decrypt the data using the security handler
|
case CryptFilterType::None: // The application shall decrypt the data using the security handler
|
||||||
@ -774,7 +786,7 @@ QByteArray PDFStandardSecurityHandler::decryptUsingFilter(const QByteArray& data
|
|||||||
{
|
{
|
||||||
decryptedData.resize(aes_data.paddedData.size());
|
decryptedData.resize(aes_data.paddedData.size());
|
||||||
AES_cbc_encrypt(convertByteArrayToUcharPtr(aes_data.paddedData), convertByteArrayToUcharPtr(decryptedData), aes_data.paddedData.length(), &key, convertByteArrayToUcharPtr(aes_data.initializationVector), AES_DECRYPT);
|
AES_cbc_encrypt(convertByteArrayToUcharPtr(aes_data.paddedData), convertByteArrayToUcharPtr(decryptedData), aes_data.paddedData.length(), &key, convertByteArrayToUcharPtr(aes_data.initializationVector), AES_DECRYPT);
|
||||||
decryptedData = decryptedData.left(data.length() - aes_data.paddingRemainder);
|
decryptedData = removeAES_padding(decryptedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -791,7 +803,7 @@ QByteArray PDFStandardSecurityHandler::decryptUsingFilter(const QByteArray& data
|
|||||||
{
|
{
|
||||||
decryptedData.resize(aes_data.paddedData.size());
|
decryptedData.resize(aes_data.paddedData.size());
|
||||||
AES_cbc_encrypt(convertByteArrayToUcharPtr(aes_data.paddedData), convertByteArrayToUcharPtr(decryptedData), aes_data.paddedData.length(), &key, convertByteArrayToUcharPtr(aes_data.initializationVector), AES_DECRYPT);
|
AES_cbc_encrypt(convertByteArrayToUcharPtr(aes_data.paddedData), convertByteArrayToUcharPtr(decryptedData), aes_data.paddedData.length(), &key, convertByteArrayToUcharPtr(aes_data.initializationVector), AES_DECRYPT);
|
||||||
decryptedData = decryptedData.left(data.length() - aes_data.paddingRemainder);
|
decryptedData = removeAES_padding(decryptedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -817,7 +829,6 @@ QByteArray PDFStandardSecurityHandler::encryptUsingFilter(const QByteArray& data
|
|||||||
{
|
{
|
||||||
QByteArray initializationVector;
|
QByteArray initializationVector;
|
||||||
QByteArray paddedData;
|
QByteArray paddedData;
|
||||||
int paddingRemainder = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto prepareAES_data = [](const QByteArray& data)
|
auto prepareAES_data = [](const QByteArray& data)
|
||||||
@ -836,11 +847,12 @@ QByteArray PDFStandardSecurityHandler::encryptUsingFilter(const QByteArray& data
|
|||||||
|
|
||||||
// Add padding remainder according to the specification
|
// Add padding remainder according to the specification
|
||||||
int size = data.size();
|
int size = data.size();
|
||||||
result.paddingRemainder = AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE);
|
const int paddingRemainder = AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE);
|
||||||
|
|
||||||
for (int i = 0; i < result.paddingRemainder; ++i)
|
result.initializationVector.reserve(result.initializationVector.size() + paddingRemainder);
|
||||||
|
for (int i = 0; i < paddingRemainder; ++i)
|
||||||
{
|
{
|
||||||
result.paddedData.push_back(result.paddingRemainder);
|
result.paddedData.push_back(paddingRemainder);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -881,10 +893,10 @@ QByteArray PDFStandardSecurityHandler::encryptUsingFilter(const QByteArray& data
|
|||||||
AES_data aes_data = prepareAES_data(data);
|
AES_data aes_data = prepareAES_data(data);
|
||||||
if (!aes_data.paddedData.isEmpty())
|
if (!aes_data.paddedData.isEmpty())
|
||||||
{
|
{
|
||||||
|
QByteArray initializationVectorCopy = aes_data.initializationVector;
|
||||||
encryptedData.resize(aes_data.paddedData.size());
|
encryptedData.resize(aes_data.paddedData.size());
|
||||||
AES_cbc_encrypt(convertByteArrayToUcharPtr(aes_data.paddedData), convertByteArrayToUcharPtr(encryptedData), aes_data.paddedData.length(), &key, convertByteArrayToUcharPtr(aes_data.initializationVector), AES_ENCRYPT);
|
AES_cbc_encrypt(convertByteArrayToUcharPtr(aes_data.paddedData), convertByteArrayToUcharPtr(encryptedData), aes_data.paddedData.length(), &key, convertByteArrayToUcharPtr(aes_data.initializationVector), AES_ENCRYPT);
|
||||||
encryptedData = encryptedData.left(data.length() - aes_data.paddingRemainder);
|
encryptedData.prepend(initializationVectorCopy);
|
||||||
encryptedData.prepend(aes_data.initializationVector);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -899,10 +911,10 @@ QByteArray PDFStandardSecurityHandler::encryptUsingFilter(const QByteArray& data
|
|||||||
AES_data aes_data = prepareAES_data(data);
|
AES_data aes_data = prepareAES_data(data);
|
||||||
if (!aes_data.paddedData.isEmpty())
|
if (!aes_data.paddedData.isEmpty())
|
||||||
{
|
{
|
||||||
|
QByteArray initializationVectorCopy = aes_data.initializationVector;
|
||||||
encryptedData.resize(aes_data.paddedData.size());
|
encryptedData.resize(aes_data.paddedData.size());
|
||||||
AES_cbc_encrypt(convertByteArrayToUcharPtr(aes_data.paddedData), convertByteArrayToUcharPtr(encryptedData), aes_data.paddedData.length(), &key, convertByteArrayToUcharPtr(aes_data.initializationVector), AES_ENCRYPT);
|
AES_cbc_encrypt(convertByteArrayToUcharPtr(aes_data.paddedData), convertByteArrayToUcharPtr(encryptedData), aes_data.paddedData.length(), &key, convertByteArrayToUcharPtr(aes_data.initializationVector), AES_ENCRYPT);
|
||||||
encryptedData = encryptedData.left(data.length() - aes_data.paddingRemainder);
|
encryptedData.prepend(initializationVectorCopy);
|
||||||
encryptedData.prepend(aes_data.initializationVector);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
Reference in New Issue
Block a user