mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Encryption bugfixing (RC4)
This commit is contained in:
@@ -43,6 +43,26 @@ bool PDFDocument::operator==(const PDFDocument& other) const
|
||||
return m_pdfObjectStorage == other.m_pdfObjectStorage;
|
||||
}
|
||||
|
||||
QByteArray PDFDocument::getIdPart(size_t index) const
|
||||
{
|
||||
QByteArray id;
|
||||
const PDFObject& idArrayObject = getTrailerDictionary()->get("ID");
|
||||
if (idArrayObject.isArray())
|
||||
{
|
||||
const PDFArray* idArray = idArrayObject.getArray();
|
||||
if (idArray->getCount() > index)
|
||||
{
|
||||
const PDFObject& idArrayItem = idArray->getItem(index);
|
||||
if (idArrayItem.isString())
|
||||
{
|
||||
id = idArrayItem.getString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
QByteArray PDFDocument::getDecodedStream(const PDFStream* stream) const
|
||||
{
|
||||
return m_pdfObjectStorage.getDecodedStream(stream);
|
||||
|
@@ -419,6 +419,10 @@ public:
|
||||
/// Returns info about the document (title, author, etc.)
|
||||
const PDFDocumentInfo* getInfo() const { return &m_info; }
|
||||
|
||||
/// Returns document id part with given index. If index is invalid,
|
||||
/// then empty id is returned.
|
||||
QByteArray getIdPart(size_t index) const;
|
||||
|
||||
/// If object is reference, the dereference attempt is performed
|
||||
/// and object is returned. If it is not a reference, then self
|
||||
/// is returned. If dereference attempt fails, then null object
|
||||
|
@@ -1143,6 +1143,31 @@ void PDFDocumentBuilder::copyAnnotation(PDFObjectReference pageReference, PDFObj
|
||||
|
||||
void PDFDocumentBuilder::setSecurityHandler(PDFSecurityHandlerPointer handler)
|
||||
{
|
||||
if (!handler)
|
||||
{
|
||||
handler.reset(new PDFNoneSecurityHandler());
|
||||
}
|
||||
|
||||
PDFObjectFactory objectBuilder;
|
||||
|
||||
objectBuilder.beginDictionary();
|
||||
objectBuilder.beginDictionaryItem("Encrypt");
|
||||
|
||||
PDFObject encryptionDictionaryObject = handler->createEncryptionDictionaryObject();
|
||||
Q_ASSERT(!encryptionDictionaryObject.isReference());
|
||||
|
||||
if (!encryptionDictionaryObject.isNull())
|
||||
{
|
||||
encryptionDictionaryObject = PDFObject::createReference(addObject(encryptionDictionaryObject));
|
||||
}
|
||||
|
||||
objectBuilder << encryptionDictionaryObject;
|
||||
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.endDictionary();
|
||||
PDFObject updatedTrailerDictionary = objectBuilder.takeObject();
|
||||
m_storage.updateTrailerDictionary(qMove(updatedTrailerDictionary));
|
||||
|
||||
m_storage.setSecurityHandler(qMove(handler));
|
||||
}
|
||||
|
||||
@@ -4297,13 +4322,7 @@ void PDFDocumentBuilder::removeEncryption()
|
||||
{
|
||||
PDFObjectFactory objectBuilder;
|
||||
|
||||
objectBuilder.beginDictionary();
|
||||
objectBuilder.beginDictionaryItem("Encrypt");
|
||||
objectBuilder << PDFObject();
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.endDictionary();
|
||||
PDFObject updatedTrailerDictionary = objectBuilder.takeObject();
|
||||
m_storage.updateTrailerDictionary(qMove(updatedTrailerDictionary));
|
||||
setSecurityHandler(nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -72,6 +72,12 @@ struct WrapString
|
||||
|
||||
}
|
||||
|
||||
WrapString(const QByteArray& byteArray) :
|
||||
string(byteArray)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QByteArray string;
|
||||
};
|
||||
|
||||
@@ -421,9 +427,10 @@ public:
|
||||
/// \param annotationReference Annotation reference
|
||||
void copyAnnotation(PDFObjectReference pageReference, PDFObjectReference annotationReference);
|
||||
|
||||
/// Sets security handler to the object storage. Trailer dictionary is not
|
||||
/// updated and so must be updated manually.
|
||||
/// \param handler New security handler
|
||||
/// Sets security handler to the object storage. Trailer dictionary is also
|
||||
/// updated, so it is not needed to update it. Pass nullptr as handler to remove
|
||||
/// security.
|
||||
/// \param handler New security handler, or nullptr
|
||||
void setSecurityHandler(PDFSecurityHandlerPointer handler);
|
||||
|
||||
/* START GENERATED CODE */
|
||||
|
@@ -319,8 +319,18 @@ PDFOperationResult PDFDocumentWriter::write(QIODevice* device, const PDFDocument
|
||||
|
||||
// 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)));
|
||||
PDFDictionary newTrailerDictionary;
|
||||
|
||||
for (const char* entry : { "Size", "Root", "Encrypt", "Info", "ID"})
|
||||
{
|
||||
PDFObject object = trailerDictionary.get(entry);
|
||||
if (!object.isNull())
|
||||
{
|
||||
newTrailerDictionary.addEntry(PDFInplaceOrMemoryString(entry), qMove(object));
|
||||
}
|
||||
}
|
||||
|
||||
PDFObject trailerDictionaryObject = PDFObject::createDictionary(std::make_shared<PDFDictionary>(qMove(newTrailerDictionary)));
|
||||
|
||||
device->write("trailer");
|
||||
writeCRLF(device);
|
||||
|
@@ -509,7 +509,7 @@ PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObj
|
||||
return PDFSecurityHandlerPointer(new PDFStandardSecurityHandler(qMove(handler)));
|
||||
}
|
||||
|
||||
void PDFSecurityHandler::fillEncryptionDictionary(PDFObjectFactory& factory)
|
||||
void PDFSecurityHandler::fillEncryptionDictionary(PDFObjectFactory& factory) const
|
||||
{
|
||||
factory.beginDictionaryItem("V");
|
||||
factory << PDFInteger(m_V);
|
||||
@@ -621,15 +621,15 @@ void PDFSecurityHandler::fillEncryptionDictionary(PDFObjectFactory& factory)
|
||||
|
||||
// Store StmF, StrF, EFF
|
||||
factory.beginDictionaryItem("StmF");
|
||||
factory << stmfName;
|
||||
factory << WrapName(stmfName);
|
||||
factory.endDictionaryItem();
|
||||
|
||||
factory.beginDictionaryItem("StrF");
|
||||
factory << strfName;
|
||||
factory << WrapName(strfName);
|
||||
factory.endDictionaryItem();
|
||||
|
||||
factory.beginDictionaryItem("EFF");
|
||||
factory << effName;
|
||||
factory << WrapName(effName);
|
||||
factory.endDictionaryItem();
|
||||
}
|
||||
}
|
||||
@@ -1141,6 +1141,8 @@ PDFObject PDFStandardSecurityHandler::createEncryptionDictionaryObject() const
|
||||
|
||||
factory.beginDictionary();
|
||||
|
||||
fillEncryptionDictionary(factory);
|
||||
|
||||
factory.beginDictionaryItem("Filter");
|
||||
factory << WrapName("Standard");
|
||||
factory.endDictionaryItem();
|
||||
@@ -1150,21 +1152,21 @@ PDFObject PDFStandardSecurityHandler::createEncryptionDictionaryObject() const
|
||||
factory.endDictionaryItem();
|
||||
|
||||
factory.beginDictionaryItem("O");
|
||||
factory << m_O;
|
||||
factory << WrapString(m_O);
|
||||
factory.endDictionaryItem();
|
||||
|
||||
factory.beginDictionaryItem("U");
|
||||
factory << m_U;
|
||||
factory << WrapString(m_U);
|
||||
factory.endDictionaryItem();
|
||||
|
||||
if (m_R == 6)
|
||||
{
|
||||
factory.beginDictionaryItem("OE");
|
||||
factory << m_OE;
|
||||
factory << WrapString(m_OE);
|
||||
factory.endDictionaryItem();
|
||||
|
||||
factory.beginDictionaryItem("UE");
|
||||
factory << m_UE;
|
||||
factory << WrapString(m_UE);
|
||||
factory.endDictionaryItem();
|
||||
}
|
||||
|
||||
@@ -1175,7 +1177,7 @@ PDFObject PDFStandardSecurityHandler::createEncryptionDictionaryObject() const
|
||||
if (m_R == 6)
|
||||
{
|
||||
factory.beginDictionaryItem("Perms");
|
||||
factory << m_Perms;
|
||||
factory << WrapString(m_Perms);
|
||||
factory.endDictionaryItem();
|
||||
}
|
||||
|
||||
@@ -1689,6 +1691,7 @@ PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const
|
||||
|
||||
// Jakub Melka: create standard security handler, with given settings
|
||||
PDFStandardSecurityHandler* handler = new PDFStandardSecurityHandler();
|
||||
handler->m_ID = settings.id;
|
||||
|
||||
const bool isEncryptingEmbeddedFilesOnly = settings.encryptContents == EncryptContents::EmbeddedFiles;
|
||||
|
||||
@@ -1820,7 +1823,8 @@ PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const
|
||||
}
|
||||
}
|
||||
|
||||
handler->authenticate([&settings](bool* b) { *b = false; return settings.ownerPassword; }, true);
|
||||
bool firstTry = true;
|
||||
handler->authenticate([&settings, &firstTry](bool* b) { *b = firstTry; firstTry = false; return settings.ownerPassword; }, true);
|
||||
Q_ASSERT(handler->getAuthorizationResult() == PDFSecurityHandler::AuthorizationResult::OwnerAuthorized);
|
||||
return PDFSecurityHandlerPointer(handler);
|
||||
}
|
||||
@@ -1884,7 +1888,7 @@ int PDFSecurityHandlerFactory::getRevisionFromAlgorithm(Algorithm algorithm)
|
||||
return 0;
|
||||
|
||||
case RC4:
|
||||
return 3;
|
||||
return 4;
|
||||
|
||||
case AES_128:
|
||||
return 4;
|
||||
|
@@ -199,7 +199,7 @@ protected:
|
||||
|
||||
/// Fills encryption dictionary with basic data
|
||||
/// \param factory Factory
|
||||
void fillEncryptionDictionary(PDFObjectFactory& factory);
|
||||
void fillEncryptionDictionary(PDFObjectFactory& factory) const;
|
||||
|
||||
/// Version of the encryption, shall be a number from 1 to 5, according the
|
||||
/// PDF specification. Other values are invalid.
|
||||
@@ -404,6 +404,7 @@ public:
|
||||
QString userPassword;
|
||||
QString ownerPassword;
|
||||
uint32_t permissions = 0;
|
||||
QByteArray id;
|
||||
};
|
||||
|
||||
/// Creates security handler based on given settings. If security handler cannot
|
||||
|
Reference in New Issue
Block a user