mirror of
				https://github.com/JakubMelka/PDF4QT.git
				synced 2025-06-05 21:59:17 +02:00 
			
		
		
		
	Save document with encryption
This commit is contained in:
		| @@ -223,7 +223,8 @@ PDFOperationResult PDFDocumentWriter::write(QIODevice* device, const PDFDocument | |||||||
|     const PDFObjectStorage& storage = document->getStorage(); |     const PDFObjectStorage& storage = document->getStorage(); | ||||||
|     const PDFObjectStorage::PDFObjects& objects = storage.getObjects(); |     const PDFObjectStorage::PDFObjects& objects = storage.getObjects(); | ||||||
|     const size_t objectCount = objects.size(); |     const size_t objectCount = objects.size(); | ||||||
|     if (storage.getSecurityHandler()->getMode() != EncryptionMode::None) |     const bool isEncrypted = storage.getSecurityHandler()->getMode() != EncryptionMode::None; | ||||||
|  |     if (!storage.getSecurityHandler()->isEncryptionAllowed()) | ||||||
|     { |     { | ||||||
|         return tr("Writing of encrypted documents is not supported."); |         return tr("Writing of encrypted documents is not supported."); | ||||||
|     } |     } | ||||||
| @@ -238,6 +239,13 @@ PDFOperationResult PDFDocumentWriter::write(QIODevice* device, const PDFDocument | |||||||
|     writeCRLF(device); |     writeCRLF(device); | ||||||
|     writeCRLF(device); |     writeCRLF(device); | ||||||
|  |  | ||||||
|  |     PDFObjectReference encryptObjectReference; | ||||||
|  |     PDFObject encryptObject = document->getTrailerDictionary()->get("Encrypt"); | ||||||
|  |     if (encryptObject.isReference()) | ||||||
|  |     { | ||||||
|  |         encryptObjectReference = encryptObject.getReference(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Write objects |     // Write objects | ||||||
|     std::vector<PDFInteger> offsets(objectCount, -1); |     std::vector<PDFInteger> offsets(objectCount, -1); | ||||||
|     for (size_t i = 0; i < objectCount; ++i) |     for (size_t i = 0; i < objectCount; ++i) | ||||||
| @@ -251,11 +259,29 @@ PDFOperationResult PDFDocumentWriter::write(QIODevice* device, const PDFDocument | |||||||
|         // Jakub Melka: we must mark actual position of object |         // Jakub Melka: we must mark actual position of object | ||||||
|         offsets[i] = device->pos(); |         offsets[i] = device->pos(); | ||||||
|  |  | ||||||
|  |         if (isEncrypted) | ||||||
|  |         { | ||||||
|  |             PDFObjectReference reference(i, entry.generation); | ||||||
|  |             PDFObject objectToWrite = entry.object; | ||||||
|  |  | ||||||
|  |             if (reference != encryptObjectReference) | ||||||
|  |             { | ||||||
|  |                 objectToWrite = storage.getSecurityHandler()->encryptObject(objectToWrite, reference); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             PDFWriteObjectVisitor visitor(device); | ||||||
|  |             writeObjectHeader(device, reference); | ||||||
|  |             objectToWrite.accept(&visitor); | ||||||
|  |             writeObjectFooter(device); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|             PDFWriteObjectVisitor visitor(device); |             PDFWriteObjectVisitor visitor(device); | ||||||
|             writeObjectHeader(device, PDFObjectReference(i, entry.generation)); |             writeObjectHeader(device, PDFObjectReference(i, entry.generation)); | ||||||
|             entry.object.accept(&visitor); |             entry.object.accept(&visitor); | ||||||
|             writeObjectFooter(device); |             writeObjectFooter(device); | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Write cross-reference table |     // Write cross-reference table | ||||||
|     PDFInteger xrefOffset = device->pos(); |     PDFInteger xrefOffset = device->pos(); | ||||||
|   | |||||||
| @@ -291,6 +291,15 @@ const PDFObject& PDFDictionary::get(const PDFInplaceOrMemoryString& key) const | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void PDFDictionary::removeEntry(const char* key) | ||||||
|  | { | ||||||
|  |     auto it = find(key); | ||||||
|  |     if (it != m_dictionary.end()) | ||||||
|  |     { | ||||||
|  |         m_dictionary.erase(it); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| void PDFDictionary::setEntry(const PDFInplaceOrMemoryString& key, PDFObject&& value) | void PDFDictionary::setEntry(const PDFInplaceOrMemoryString& key, PDFObject&& value) | ||||||
| { | { | ||||||
|     auto it = find(key); |     auto it = find(key); | ||||||
| @@ -327,7 +336,7 @@ std::vector<PDFDictionary::DictionaryEntry>::iterator PDFDictionary::find(const | |||||||
|  |  | ||||||
| std::vector<PDFDictionary::DictionaryEntry>::const_iterator PDFDictionary::find(const char* key) const | std::vector<PDFDictionary::DictionaryEntry>::const_iterator PDFDictionary::find(const char* key) const | ||||||
| { | { | ||||||
|     return std::find_if(m_dictionary.cbegin(), m_dictionary.cend(), [&key](const DictionaryEntry& entry) { return entry.first == key; }); |     return std::find_if(m_dictionary.cbegin(), m_dictionary.cend(), [key](const DictionaryEntry& entry) { return entry.first == key; }); | ||||||
| } | } | ||||||
|  |  | ||||||
| std::vector<PDFDictionary::DictionaryEntry>::const_iterator PDFDictionary::find(const PDFInplaceOrMemoryString& key) const | std::vector<PDFDictionary::DictionaryEntry>::const_iterator PDFDictionary::find(const PDFInplaceOrMemoryString& key) const | ||||||
| @@ -340,6 +349,11 @@ std::vector<PDFDictionary::DictionaryEntry>::iterator PDFDictionary::find(const | |||||||
|     return std::find_if(m_dictionary.begin(), m_dictionary.end(), [&key](const DictionaryEntry& entry) { return entry.first == key; }); |     return std::find_if(m_dictionary.begin(), m_dictionary.end(), [&key](const DictionaryEntry& entry) { return entry.first == key; }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | std::vector<PDFDictionary::DictionaryEntry>::iterator PDFDictionary::find(const char* key) | ||||||
|  | { | ||||||
|  |     return std::find_if(m_dictionary.begin(), m_dictionary.end(), [key](const DictionaryEntry& entry) { return entry.first == key; }); | ||||||
|  | } | ||||||
|  |  | ||||||
| bool PDFStream::equals(const PDFObjectContent* other) const | bool PDFStream::equals(const PDFObjectContent* other) const | ||||||
| { | { | ||||||
|     Q_ASSERT(dynamic_cast<const PDFStream*>(other)); |     Q_ASSERT(dynamic_cast<const PDFStream*>(other)); | ||||||
|   | |||||||
| @@ -383,6 +383,11 @@ public: | |||||||
|     /// \param key Key to be found in the dictionary |     /// \param key Key to be found in the dictionary | ||||||
|     bool hasKey(const char* key) const { return find(key) != m_dictionary.cend(); } |     bool hasKey(const char* key) const { return find(key) != m_dictionary.cend(); } | ||||||
|  |  | ||||||
|  |     /// Removes entry with given key. If entry with this key is not found, | ||||||
|  |     /// nothing happens. | ||||||
|  |     /// \param key Key to be removed | ||||||
|  |     void removeEntry(const char* key); | ||||||
|  |  | ||||||
|     /// Adds a new entry to the dictionary. |     /// Adds a new entry to the dictionary. | ||||||
|     /// \param key Key |     /// \param key Key | ||||||
|     /// \param value Value |     /// \param value Value | ||||||
| @@ -435,6 +440,11 @@ private: | |||||||
|     /// \param key Key to be found |     /// \param key Key to be found | ||||||
|     std::vector<DictionaryEntry>::const_iterator find(const char* key) const; |     std::vector<DictionaryEntry>::const_iterator find(const char* key) const; | ||||||
|  |  | ||||||
|  |     /// Finds an item in the dictionary array, if the item is not in the dictionary, | ||||||
|  |     /// then end iterator is returned. | ||||||
|  |     /// \param key Key to be found | ||||||
|  |     std::vector<DictionaryEntry>::iterator find(const char* key); | ||||||
|  |  | ||||||
|     /// Finds an item in the dictionary array, if the item is not in the dictionary, |     /// Finds an item in the dictionary array, if the item is not in the dictionary, | ||||||
|     /// then end iterator is returned. |     /// then end iterator is returned. | ||||||
|     /// \param key Key to be found |     /// \param key Key to be found | ||||||
|   | |||||||
| @@ -21,6 +21,8 @@ | |||||||
| #include "pdfvisitor.h" | #include "pdfvisitor.h" | ||||||
| #include "pdfutils.h" | #include "pdfutils.h" | ||||||
|  |  | ||||||
|  | #include <QRandomGenerator> | ||||||
|  |  | ||||||
| #include <openssl/rc4.h> | #include <openssl/rc4.h> | ||||||
| #include <openssl/md5.h> | #include <openssl/md5.h> | ||||||
| #include <openssl/aes.h> | #include <openssl/aes.h> | ||||||
| @@ -39,12 +41,20 @@ static constexpr std::array<uint8_t, 32> PDFPasswordPadding = { | |||||||
|     0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A |     0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class PDFDecryptObjectVisitor : public PDFAbstractVisitor | class PDFDecryptOrEncryptObjectVisitor : public PDFAbstractVisitor | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     explicit PDFDecryptObjectVisitor(const PDFSecurityHandler* securityHandler, PDFObjectReference reference) : |  | ||||||
|  |     enum class Mode | ||||||
|  |     { | ||||||
|  |         Decrypt, | ||||||
|  |         Encrypt | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     explicit PDFDecryptOrEncryptObjectVisitor(const PDFSecurityHandler* securityHandler, PDFObjectReference reference, Mode mode) : | ||||||
|         m_securityHandler(securityHandler), |         m_securityHandler(securityHandler), | ||||||
|         m_reference(reference) |         m_reference(reference), | ||||||
|  |         m_mode(mode) | ||||||
|     { |     { | ||||||
|         m_objectStack.reserve(32); |         m_objectStack.reserve(32); | ||||||
|     } |     } | ||||||
| @@ -60,45 +70,58 @@ public: | |||||||
|     virtual void visitStream(const PDFStream* stream) override; |     virtual void visitStream(const PDFStream* stream) override; | ||||||
|     virtual void visitReference(const PDFObjectReference reference) override; |     virtual void visitReference(const PDFObjectReference reference) override; | ||||||
|  |  | ||||||
|     PDFObject getDecryptedObject(); |     PDFObject getProcessedObject(); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     const PDFSecurityHandler* m_securityHandler; |     const PDFSecurityHandler* m_securityHandler = nullptr; | ||||||
|     std::vector<PDFObject> m_objectStack; |     std::vector<PDFObject> m_objectStack; | ||||||
|     PDFObjectReference m_reference; |     PDFObjectReference m_reference; | ||||||
|  |     Mode m_mode = Mode::Decrypt; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| void PDFDecryptObjectVisitor::visitNull() | void PDFDecryptOrEncryptObjectVisitor::visitNull() | ||||||
| { | { | ||||||
|     m_objectStack.push_back(PDFObject::createNull()); |     m_objectStack.push_back(PDFObject::createNull()); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PDFDecryptObjectVisitor::visitBool(bool value) | void PDFDecryptOrEncryptObjectVisitor::visitBool(bool value) | ||||||
| { | { | ||||||
|     m_objectStack.push_back(PDFObject::createBool(value)); |     m_objectStack.push_back(PDFObject::createBool(value)); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PDFDecryptObjectVisitor::visitInt(PDFInteger value) | void PDFDecryptOrEncryptObjectVisitor::visitInt(PDFInteger value) | ||||||
| { | { | ||||||
|     m_objectStack.push_back(PDFObject::createInteger(value)); |     m_objectStack.push_back(PDFObject::createInteger(value)); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PDFDecryptObjectVisitor::visitReal(PDFReal value) | void PDFDecryptOrEncryptObjectVisitor::visitReal(PDFReal value) | ||||||
| { | { | ||||||
|     m_objectStack.push_back(PDFObject::createReal(value)); |     m_objectStack.push_back(PDFObject::createReal(value)); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PDFDecryptObjectVisitor::visitString(PDFStringRef string) | void PDFDecryptOrEncryptObjectVisitor::visitString(PDFStringRef string) | ||||||
| { | { | ||||||
|  |     switch (m_mode) | ||||||
|  |     { | ||||||
|  |         case pdf::PDFDecryptOrEncryptObjectVisitor::Mode::Decrypt: | ||||||
|             m_objectStack.push_back(PDFObject::createString(m_securityHandler->decrypt(string.getString(), m_reference, PDFSecurityHandler::EncryptionScope::String))); |             m_objectStack.push_back(PDFObject::createString(m_securityHandler->decrypt(string.getString(), m_reference, PDFSecurityHandler::EncryptionScope::String))); | ||||||
|  |             break; | ||||||
|  |         case pdf::PDFDecryptOrEncryptObjectVisitor::Mode::Encrypt: | ||||||
|  |             m_objectStack.push_back(PDFObject::createString(m_securityHandler->encrypt(string.getString(), m_reference, PDFSecurityHandler::EncryptionScope::String))); | ||||||
|  |             break; | ||||||
|  |  | ||||||
|  |         default: | ||||||
|  |             Q_ASSERT(false); | ||||||
|  |             break; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void PDFDecryptObjectVisitor::visitName(PDFStringRef name) | void PDFDecryptOrEncryptObjectVisitor::visitName(PDFStringRef name) | ||||||
| { | { | ||||||
|     m_objectStack.push_back(PDFObject::createName(name)); |     m_objectStack.push_back(PDFObject::createName(name)); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PDFDecryptObjectVisitor::visitArray(const PDFArray* array) | void PDFDecryptOrEncryptObjectVisitor::visitArray(const PDFArray* array) | ||||||
| { | { | ||||||
|     acceptArray(array); |     acceptArray(array); | ||||||
|  |  | ||||||
| @@ -112,12 +135,12 @@ void PDFDecryptObjectVisitor::visitArray(const PDFArray* array) | |||||||
|     m_objectStack.push_back(object); |     m_objectStack.push_back(object); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PDFDecryptObjectVisitor::visitDictionary(const PDFDictionary* dictionary) | void PDFDecryptOrEncryptObjectVisitor::visitDictionary(const PDFDictionary* dictionary) | ||||||
| { | { | ||||||
|     Q_ASSERT(dictionary); |     Q_ASSERT(dictionary); | ||||||
|  |  | ||||||
|     // We must check, if it is or isn't a signature dictionary. If it is, |     // We must check, if it is or isn't a signature dictionary. If it is, | ||||||
|     // then don't decrypt the Content value. We also don't check, if signature |     // then don't decrypt/encrypt the Content value. We also don't check, if signature | ||||||
|     // isn't indirectly referenced by reference. Hope it isn't... |     // isn't indirectly referenced by reference. Hope it isn't... | ||||||
|     const PDFObject& typeObject = dictionary->get("Type"); |     const PDFObject& typeObject = dictionary->get("Type"); | ||||||
|     bool isSignatureObject = (typeObject.isName() && typeObject.getString() == "Sig"); |     bool isSignatureObject = (typeObject.isName() && typeObject.getString() == "Sig"); | ||||||
| @@ -142,9 +165,9 @@ void PDFDecryptObjectVisitor::visitDictionary(const PDFDictionary* dictionary) | |||||||
|     m_objectStack.push_back(PDFObject::createDictionary(std::make_shared<PDFDictionary>(qMove(entries)))); |     m_objectStack.push_back(PDFObject::createDictionary(std::make_shared<PDFDictionary>(qMove(entries)))); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PDFDecryptObjectVisitor::visitStream(const PDFStream* stream) | void PDFDecryptOrEncryptObjectVisitor::visitStream(const PDFStream* stream) | ||||||
| { | { | ||||||
|     // Don't decrypt, if it is a Metadata stream and Metadata encryption is turned off |     // Don't decrypt/encrypt, if it is a Metadata stream and Metadata encryption is turned off | ||||||
|     const PDFDictionary* dictionary = stream->getDictionary(); |     const PDFDictionary* dictionary = stream->getDictionary(); | ||||||
|  |  | ||||||
|     const PDFObject& typeObject = dictionary->get("Type"); |     const PDFObject& typeObject = dictionary->get("Type"); | ||||||
| @@ -156,34 +179,66 @@ void PDFDecryptObjectVisitor::visitStream(const PDFStream* stream) | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Decrypt the dictionary |     // Decrypt/encrypt the dictionary | ||||||
|     visitDictionary(dictionary); |     visitDictionary(dictionary); | ||||||
|     PDFObject dictionaryObject = m_objectStack.back(); |     PDFObject dictionaryObject = m_objectStack.back(); | ||||||
|     m_objectStack.pop_back(); |     m_objectStack.pop_back(); | ||||||
|  |  | ||||||
|     // We must also handle situation, that stream has specified Crypt filter. |     // We must also handle situation, that stream has specified Crypt filter. | ||||||
|     // In this case, we must delegate decryption to the stream filters. |     // In this case, we must delegate decryption/encryption to the stream filters. | ||||||
|     PDFDictionary decryptedDictionary(*dictionaryObject.getDictionary()); |     PDFDictionary processedDictionary(*dictionaryObject.getDictionary()); | ||||||
|     QByteArray decryptedData; |     QByteArray processedData; | ||||||
|     if (!decryptedDictionary.hasKey("Crypt")) |     if (!processedDictionary.hasKey("Crypt")) | ||||||
|     { |     { | ||||||
|         decryptedData = m_securityHandler->decrypt(*stream->getContent(), m_reference, PDFSecurityHandler::EncryptionScope::Stream); |         switch (m_mode) | ||||||
|  |         { | ||||||
|  |             case pdf::PDFDecryptOrEncryptObjectVisitor::Mode::Decrypt: | ||||||
|  |                 processedData = m_securityHandler->decrypt(*stream->getContent(), m_reference, PDFSecurityHandler::EncryptionScope::Stream); | ||||||
|  |                 break; | ||||||
|  |             case pdf::PDFDecryptOrEncryptObjectVisitor::Mode::Encrypt: | ||||||
|  |                 processedData = m_securityHandler->encrypt(*stream->getContent(), m_reference, PDFSecurityHandler::EncryptionScope::Stream); | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             default: | ||||||
|  |                 Q_ASSERT(false); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         decryptedData = *stream->getContent(); |         switch (m_mode) | ||||||
|         decryptedDictionary.addEntry(PDFInplaceOrMemoryString(PDFSecurityHandler::OBJECT_REFERENCE_DICTIONARY_NAME), PDFObject::createReference(m_reference)); |         { | ||||||
|  |             case pdf::PDFDecryptOrEncryptObjectVisitor::Mode::Decrypt: | ||||||
|  |             { | ||||||
|  |                 processedData = *stream->getContent(); | ||||||
|  |                 processedDictionary.removeEntry(PDFSecurityHandler::OBJECT_REFERENCE_DICTIONARY_NAME); | ||||||
|  |                 processedDictionary.addEntry(PDFInplaceOrMemoryString(PDFSecurityHandler::OBJECT_REFERENCE_DICTIONARY_NAME), PDFObject::createReference(m_reference)); | ||||||
|  |                 break; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|     m_objectStack.push_back(PDFObject::createStream(std::make_shared<PDFStream>(qMove(decryptedDictionary), qMove(decryptedData)))); |             case pdf::PDFDecryptOrEncryptObjectVisitor::Mode::Encrypt: | ||||||
|  |             { | ||||||
|  |                 processedData = *stream->getContent(); | ||||||
|  |                 processedDictionary.removeEntry(PDFSecurityHandler::OBJECT_REFERENCE_DICTIONARY_NAME); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             default: | ||||||
|  |                 Q_ASSERT(false); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     m_objectStack.push_back(PDFObject::createStream(std::make_shared<PDFStream>(qMove(processedDictionary), qMove(processedData)))); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PDFDecryptObjectVisitor::visitReference(const PDFObjectReference reference) | void PDFDecryptOrEncryptObjectVisitor::visitReference(const PDFObjectReference reference) | ||||||
| { | { | ||||||
|     m_objectStack.push_back(PDFObject::createReference(reference)); |     m_objectStack.push_back(PDFObject::createReference(reference)); | ||||||
| } | } | ||||||
|  |  | ||||||
| PDFObject PDFDecryptObjectVisitor::getDecryptedObject() | PDFObject PDFDecryptOrEncryptObjectVisitor::getProcessedObject() | ||||||
| { | { | ||||||
|     Q_ASSERT(m_objectStack.size() == 1); |     Q_ASSERT(m_objectStack.size() == 1); | ||||||
|     return qMove(m_objectStack.back()); |     return qMove(m_objectStack.back()); | ||||||
| @@ -191,9 +246,16 @@ PDFObject PDFDecryptObjectVisitor::getDecryptedObject() | |||||||
|  |  | ||||||
| PDFObject PDFSecurityHandler::decryptObject(const PDFObject& object, PDFObjectReference reference) const | PDFObject PDFSecurityHandler::decryptObject(const PDFObject& object, PDFObjectReference reference) const | ||||||
| { | { | ||||||
|     PDFDecryptObjectVisitor visitor(this, reference); |     PDFDecryptOrEncryptObjectVisitor visitor(this, reference, PDFDecryptOrEncryptObjectVisitor::Mode::Decrypt); | ||||||
|     object.accept(&visitor); |     object.accept(&visitor); | ||||||
|     return visitor.getDecryptedObject(); |     return visitor.getProcessedObject(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PDFObject PDFSecurityHandler::encryptObject(const PDFObject& object, PDFObjectReference reference) const | ||||||
|  | { | ||||||
|  |     PDFDecryptOrEncryptObjectVisitor visitor(this, reference, PDFDecryptOrEncryptObjectVisitor::Mode::Encrypt); | ||||||
|  |     object.accept(&visitor); | ||||||
|  |     return visitor.getProcessedObject(); | ||||||
| } | } | ||||||
|  |  | ||||||
| PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id) | PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id) | ||||||
| @@ -608,6 +670,34 @@ PDFSecurityHandler::AuthorizationResult PDFStandardSecurityHandler::authenticate | |||||||
|     return AuthorizationResult::Cancelled; |     return AuthorizationResult::Cancelled; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | std::vector<uint8_t> PDFStandardSecurityHandler::createV2_ObjectEncryptionKey(PDFObjectReference reference, CryptFilter filter) const | ||||||
|  | { | ||||||
|  |     std::vector<uint8_t> inputKeyData = convertByteArrayToVector(m_authorizationData.fileEncryptionKey); | ||||||
|  |     uint32_t objectNumber = qToLittleEndian(static_cast<uint32_t>(reference.objectNumber)); | ||||||
|  |     uint32_t generation = qToLittleEndian(static_cast<uint32_t>(reference.generation)); | ||||||
|  |     inputKeyData.insert(inputKeyData.cend(), { uint8_t(objectNumber & 0xFF), uint8_t((objectNumber >> 8) & 0xFF), uint8_t((objectNumber >> 16) & 0xFF), uint8_t(generation & 0xFF), uint8_t((generation >> 8) & 0xFF) }); | ||||||
|  |     std::vector<uint8_t> objectEncryptionKey(MD5_DIGEST_LENGTH, uint8_t(0)); | ||||||
|  |     MD5(inputKeyData.data(), inputKeyData.size(), objectEncryptionKey.data()); | ||||||
|  |  | ||||||
|  |     // Use up to (n + 5) bytes, maximally 16, from the digest as object encryption key | ||||||
|  |     size_t objectEncryptionKeySize = qMin(filter.keyLength + 5, MD5_DIGEST_LENGTH); | ||||||
|  |     objectEncryptionKey.resize(objectEncryptionKeySize); | ||||||
|  |  | ||||||
|  |     return objectEncryptionKey; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::vector<uint8_t> PDFStandardSecurityHandler::createAESV2_ObjectEncryptionKey(PDFObjectReference reference) const | ||||||
|  | { | ||||||
|  |     std::vector<uint8_t> inputKeyData = convertByteArrayToVector(m_authorizationData.fileEncryptionKey); | ||||||
|  |     uint32_t objectNumber = qToLittleEndian(static_cast<uint32_t>(reference.objectNumber)); | ||||||
|  |     uint32_t generation = qToLittleEndian(static_cast<uint32_t>(reference.generation)); | ||||||
|  |     inputKeyData.insert(inputKeyData.cend(), { uint8_t(objectNumber & 0xFF), uint8_t((objectNumber >> 8) & 0xFF), uint8_t((objectNumber >> 16) & 0xFF), uint8_t(generation & 0xFF), uint8_t((generation >> 8) & 0xFF), 0x73, 0x41, 0x6C, 0x54 }); | ||||||
|  |     std::vector<uint8_t> objectEncryptionKey(MD5_DIGEST_LENGTH, uint8_t(0)); | ||||||
|  |     MD5(inputKeyData.data(), inputKeyData.size(), objectEncryptionKey.data()); | ||||||
|  |  | ||||||
|  |     return objectEncryptionKey; | ||||||
|  | } | ||||||
|  |  | ||||||
| QByteArray PDFStandardSecurityHandler::decryptUsingFilter(const QByteArray& data, CryptFilter filter, PDFObjectReference reference) const | QByteArray PDFStandardSecurityHandler::decryptUsingFilter(const QByteArray& data, CryptFilter filter, PDFObjectReference reference) const | ||||||
| { | { | ||||||
|     QByteArray decryptedData; |     QByteArray decryptedData; | ||||||
| @@ -618,6 +708,7 @@ 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) | ||||||
| @@ -637,11 +728,11 @@ QByteArray PDFStandardSecurityHandler::decryptUsingFilter(const QByteArray& data | |||||||
|  |  | ||||||
|         // Add padding remainder according to the specification |         // Add padding remainder according to the specification | ||||||
|         int size = result.paddedData.size(); |         int size = result.paddedData.size(); | ||||||
|         int paddingRemainder = AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE); |         result.paddingRemainder = AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE); | ||||||
|  |  | ||||||
|         for (int i = 0; i < paddingRemainder; ++i) |         for (int i = 0; i < result.paddingRemainder; ++i) | ||||||
|         { |         { | ||||||
|             result.paddedData.push_back(paddingRemainder); |             result.paddedData.push_back(result.paddingRemainder); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return result; |         return result; | ||||||
| @@ -659,17 +750,7 @@ QByteArray PDFStandardSecurityHandler::decryptUsingFilter(const QByteArray& data | |||||||
|  |  | ||||||
|         case CryptFilterType::V2:         // Use file encryption key for RC4 algorithm |         case CryptFilterType::V2:         // Use file encryption key for RC4 algorithm | ||||||
|         { |         { | ||||||
|             std::vector<uint8_t> inputKeyData = convertByteArrayToVector(m_authorizationData.fileEncryptionKey); |             std::vector<uint8_t> objectEncryptionKey = createV2_ObjectEncryptionKey(reference, filter); | ||||||
|             uint32_t objectNumber = qToLittleEndian(static_cast<uint32_t>(reference.objectNumber)); |  | ||||||
|             uint32_t generation = qToLittleEndian(static_cast<uint32_t>(reference.generation)); |  | ||||||
|             inputKeyData.insert(inputKeyData.cend(), { uint8_t(objectNumber & 0xFF), uint8_t((objectNumber >> 8) & 0xFF), uint8_t((objectNumber >> 16) & 0xFF), uint8_t(generation & 0xFF), uint8_t((generation >> 8) & 0xFF) }); |  | ||||||
|             std::vector<uint8_t> objectEncryptionKey(MD5_DIGEST_LENGTH, uint8_t(0)); |  | ||||||
|             MD5(inputKeyData.data(), inputKeyData.size(), objectEncryptionKey.data()); |  | ||||||
|  |  | ||||||
|             // Use up to (n + 5) bytes, maximally 16, from the digest as object encryption key |  | ||||||
|             size_t objectEncryptionKeySize = qMin(filter.keyLength + 5, MD5_DIGEST_LENGTH); |  | ||||||
|             objectEncryptionKey.resize(objectEncryptionKeySize); |  | ||||||
|  |  | ||||||
|             decryptedData.resize(data.size()); |             decryptedData.resize(data.size()); | ||||||
|  |  | ||||||
|             RC4_KEY key = { }; |             RC4_KEY key = { }; | ||||||
| @@ -681,12 +762,7 @@ QByteArray PDFStandardSecurityHandler::decryptUsingFilter(const QByteArray& data | |||||||
|  |  | ||||||
|         case CryptFilterType::AESV2:      // Use file encryption key for AES algorithm |         case CryptFilterType::AESV2:      // Use file encryption key for AES algorithm | ||||||
|         { |         { | ||||||
|             std::vector<uint8_t> inputKeyData = convertByteArrayToVector(m_authorizationData.fileEncryptionKey); |             std::vector<uint8_t> objectEncryptionKey = createAESV2_ObjectEncryptionKey(reference); | ||||||
|             uint32_t objectNumber = qToLittleEndian(static_cast<uint32_t>(reference.objectNumber)); |  | ||||||
|             uint32_t generation = qToLittleEndian(static_cast<uint32_t>(reference.generation)); |  | ||||||
|             inputKeyData.insert(inputKeyData.cend(), { uint8_t(objectNumber & 0xFF), uint8_t((objectNumber >> 8) & 0xFF), uint8_t((objectNumber >> 16) & 0xFF), uint8_t(generation & 0xFF), uint8_t((generation >> 8) & 0xFF), 0x73, 0x41, 0x6C, 0x54 }); |  | ||||||
|             std::vector<uint8_t> objectEncryptionKey(MD5_DIGEST_LENGTH, uint8_t(0)); |  | ||||||
|             MD5(inputKeyData.data(), inputKeyData.size(), objectEncryptionKey.data()); |  | ||||||
|  |  | ||||||
|             // For AES algorithm, always use 16 bytes key (128 bit encryption mode) |             // For AES algorithm, always use 16 bytes key (128 bit encryption mode) | ||||||
|  |  | ||||||
| @@ -698,7 +774,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_BLOCK_SIZE); |                 decryptedData = decryptedData.left(data.length() - aes_data.paddingRemainder); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             break; |             break; | ||||||
| @@ -715,7 +791,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_BLOCK_SIZE); |                 decryptedData = decryptedData.left(data.length() - aes_data.paddingRemainder); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             break; |             break; | ||||||
| @@ -731,7 +807,135 @@ QByteArray PDFStandardSecurityHandler::decryptUsingFilter(const QByteArray& data | |||||||
|     return decryptedData; |     return decryptedData; | ||||||
| } | } | ||||||
|  |  | ||||||
| QByteArray PDFStandardSecurityHandler::decrypt(const QByteArray& data, PDFObjectReference reference, PDFSecurityHandler::EncryptionScope encryptionScope) const | QByteArray PDFStandardSecurityHandler::encryptUsingFilter(const QByteArray& data, CryptFilter filter, PDFObjectReference reference) const | ||||||
|  | { | ||||||
|  |     QByteArray encryptedData; | ||||||
|  |  | ||||||
|  |     Q_ASSERT(m_authorizationData.isAuthorized()); | ||||||
|  |  | ||||||
|  |     struct AES_data | ||||||
|  |     { | ||||||
|  |         QByteArray initializationVector; | ||||||
|  |         QByteArray paddedData; | ||||||
|  |         int paddingRemainder = 0; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     auto prepareAES_data = [](const QByteArray& data) | ||||||
|  |     { | ||||||
|  |         AES_data result; | ||||||
|  |  | ||||||
|  |         QRandomGenerator randomNumberGenerator = QRandomGenerator::securelySeeded(); | ||||||
|  |  | ||||||
|  |         result.initializationVector.resize(AES_BLOCK_SIZE); | ||||||
|  |         for (int i = 0; i < AES_BLOCK_SIZE; ++i) | ||||||
|  |         { | ||||||
|  |             result.initializationVector[i] = uint8_t(randomNumberGenerator.generate()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         result.paddedData = data; | ||||||
|  |  | ||||||
|  |         // Add padding remainder according to the specification | ||||||
|  |         int size = data.size(); | ||||||
|  |         result.paddingRemainder = AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE); | ||||||
|  |  | ||||||
|  |         for (int i = 0; i < result.paddingRemainder; ++i) | ||||||
|  |         { | ||||||
|  |             result.paddedData.push_back(result.paddingRemainder); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return result; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     switch (filter.type) | ||||||
|  |     { | ||||||
|  |         case CryptFilterType::None:       // The application shall encrypt the data using the security handler | ||||||
|  |         { | ||||||
|  |             // This shouldn't occur, because in case the used filter has None value, then default filter | ||||||
|  |             // is used and default filter can't have this value. | ||||||
|  |             Q_ASSERT(false); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case CryptFilterType::V2:         // Use file encryption key for RC4 algorithm | ||||||
|  |         { | ||||||
|  |             // This algorithm is same as the encrypt algorithm, because RC4 cipher is symmetrical | ||||||
|  |             std::vector<uint8_t> objectEncryptionKey = createV2_ObjectEncryptionKey(reference, filter); | ||||||
|  |             encryptedData.resize(data.size()); | ||||||
|  |  | ||||||
|  |             RC4_KEY key = { }; | ||||||
|  |             RC4_set_key(&key, static_cast<int>(objectEncryptionKey.size()), objectEncryptionKey.data()); | ||||||
|  |             RC4(&key, data.size(), convertByteArrayToUcharPtr(data), convertByteArrayToUcharPtr(encryptedData)); | ||||||
|  |  | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case CryptFilterType::AESV2:      // Use file encryption key for AES algorithm | ||||||
|  |         { | ||||||
|  |             std::vector<uint8_t> objectEncryptionKey = createAESV2_ObjectEncryptionKey(reference); | ||||||
|  |  | ||||||
|  |             // For AES algorithm, always use 16 bytes key (128 bit encryption mode) | ||||||
|  |  | ||||||
|  |             AES_KEY key = { }; | ||||||
|  |             AES_set_encrypt_key(objectEncryptionKey.data(), static_cast<int>(objectEncryptionKey.size()) * 8, &key); | ||||||
|  |  | ||||||
|  |             AES_data aes_data = prepareAES_data(data); | ||||||
|  |             if (!aes_data.paddedData.isEmpty()) | ||||||
|  |             { | ||||||
|  |                 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); | ||||||
|  |                 encryptedData = encryptedData.left(data.length() - aes_data.paddingRemainder); | ||||||
|  |                 encryptedData.prepend(aes_data.initializationVector); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case CryptFilterType::AESV3:      // Use file encryption key for AES 256 bit algorithm | ||||||
|  |         { | ||||||
|  |             Q_ASSERT(m_authorizationData.fileEncryptionKey.size() == 32); | ||||||
|  |             AES_KEY key = { }; | ||||||
|  |             AES_set_encrypt_key(convertByteArrayToUcharPtr(m_authorizationData.fileEncryptionKey), static_cast<int>(m_authorizationData.fileEncryptionKey.size()) * 8, &key); | ||||||
|  |  | ||||||
|  |             AES_data aes_data = prepareAES_data(data); | ||||||
|  |             if (!aes_data.paddedData.isEmpty()) | ||||||
|  |             { | ||||||
|  |                 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); | ||||||
|  |                 encryptedData = encryptedData.left(data.length() - aes_data.paddingRemainder); | ||||||
|  |                 encryptedData.prepend(aes_data.initializationVector); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case CryptFilterType::Identity:   // Don't decrypt anything, use identity function | ||||||
|  |         { | ||||||
|  |             encryptedData = data; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return encryptedData; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QByteArray PDFStandardSecurityHandler::decrypt(const QByteArray& data, PDFObjectReference reference, EncryptionScope encryptionScope) const | ||||||
|  | { | ||||||
|  |     CryptFilter filter = getCryptFilter(encryptionScope); | ||||||
|  |     return decryptUsingFilter(data, filter, reference); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QByteArray PDFStandardSecurityHandler::decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const | ||||||
|  | { | ||||||
|  |     auto it = m_cryptFilters.find(filterName); | ||||||
|  |     if (it == m_cryptFilters.cend()) | ||||||
|  |     { | ||||||
|  |         throw PDFException(PDFTranslationContext::tr("Crypt filter '%1' not found.").arg(QString::fromLatin1(filterName))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return decryptUsingFilter(data, it->second, reference); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CryptFilter PDFStandardSecurityHandler::getCryptFilter(EncryptionScope encryptionScope) const | ||||||
| { | { | ||||||
|     CryptFilter filter = m_filterDefault; |     CryptFilter filter = m_filterDefault; | ||||||
|  |  | ||||||
| @@ -768,10 +972,16 @@ QByteArray PDFStandardSecurityHandler::decrypt(const QByteArray& data, PDFObject | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return decryptUsingFilter(data, filter, reference); |     return filter; | ||||||
| } | } | ||||||
|  |  | ||||||
| QByteArray PDFStandardSecurityHandler::decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const | QByteArray PDFStandardSecurityHandler::encrypt(const QByteArray& data, PDFObjectReference reference, EncryptionScope encryptionScope) const | ||||||
|  | { | ||||||
|  |     CryptFilter filter = getCryptFilter(encryptionScope); | ||||||
|  |     return encryptUsingFilter(data, filter, reference); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QByteArray PDFStandardSecurityHandler::encryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const | ||||||
| { | { | ||||||
|     auto it = m_cryptFilters.find(filterName); |     auto it = m_cryptFilters.find(filterName); | ||||||
|     if (it == m_cryptFilters.cend()) |     if (it == m_cryptFilters.cend()) | ||||||
| @@ -779,7 +989,7 @@ QByteArray PDFStandardSecurityHandler::decryptByFilter(const QByteArray& data, c | |||||||
|         throw PDFException(PDFTranslationContext::tr("Crypt filter '%1' not found.").arg(QString::fromLatin1(filterName))); |         throw PDFException(PDFTranslationContext::tr("Crypt filter '%1' not found.").arg(QString::fromLatin1(filterName))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return decryptUsingFilter(data, it->second, reference); |     return encryptUsingFilter(data, it->second, reference); | ||||||
| } | } | ||||||
|  |  | ||||||
| QByteArray PDFStandardSecurityHandler::createFileEncryptionKey(const QByteArray& password) const | QByteArray PDFStandardSecurityHandler::createFileEncryptionKey(const QByteArray& password) const | ||||||
|   | |||||||
| @@ -127,6 +127,13 @@ public: | |||||||
|     /// \returns Decrypted object |     /// \returns Decrypted object | ||||||
|     PDFObject decryptObject(const PDFObject& object, PDFObjectReference reference) const; |     PDFObject decryptObject(const PDFObject& object, PDFObjectReference reference) const; | ||||||
|  |  | ||||||
|  |     /// Encrypts the PDF object. This function works properly only (and only if) | ||||||
|  |     /// \p authenticate function returns user/owner authorization code. | ||||||
|  |     /// \param object Object to be encrypted | ||||||
|  |     /// \param reference Reference of indirect object (some algorithms require to generate key also from reference) | ||||||
|  |     /// \returns Encrypted object | ||||||
|  |     PDFObject encryptObject(const PDFObject& object, PDFObjectReference reference) const; | ||||||
|  |  | ||||||
|     /// Decrypts the PDF object data. This function works properly only (and only if) |     /// Decrypts the PDF object data. This function works properly only (and only if) | ||||||
|     /// \p authenticate function returns user/owner authorization code. |     /// \p authenticate function returns user/owner authorization code. | ||||||
|     /// \param data Data to be decrypted |     /// \param data Data to be decrypted | ||||||
| @@ -141,6 +148,20 @@ public: | |||||||
|     /// \param reference Reference object |     /// \param reference Reference object | ||||||
|     virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const = 0; |     virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const = 0; | ||||||
|  |  | ||||||
|  |     /// Encrypts the PDF object data. This function works properly only (and only if) | ||||||
|  |     /// \p authenticate function returns user/owner authorization code. | ||||||
|  |     /// \param data Data to be encrypted | ||||||
|  |     /// \param reference Reference of indirect object (some algorithms require to generate key also from reference) | ||||||
|  |     /// \param encryptionScope Scope of the encryption (if it is string/stream/...) | ||||||
|  |     /// \returns Encrypted object data | ||||||
|  |     virtual QByteArray encrypt(const QByteArray& data, PDFObjectReference reference, EncryptionScope encryptionScope) const = 0; | ||||||
|  |  | ||||||
|  |     /// Encrypts data using specified filter. Throws exception, if filter is not found. | ||||||
|  |     /// \param data Data to be encrypted | ||||||
|  |     /// \param filterName Filter name to be used to encrypt the data | ||||||
|  |     /// \param reference Reference object | ||||||
|  |     virtual QByteArray encryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const = 0; | ||||||
|  |  | ||||||
|     /// Returns true, if given permission is allowed in the current authorization context. |     /// Returns true, if given permission is allowed in the current authorization context. | ||||||
|     /// If owner is authorized, then this function allways returns true. |     /// If owner is authorized, then this function allways returns true. | ||||||
|     virtual bool isAllowed(Permission permission) const = 0; |     virtual bool isAllowed(Permission permission) const = 0; | ||||||
| @@ -148,6 +169,10 @@ public: | |||||||
|     /// Returns true, if metadata are encrypted |     /// Returns true, if metadata are encrypted | ||||||
|     virtual bool isMetadataEncrypted() const = 0; |     virtual bool isMetadataEncrypted() const = 0; | ||||||
|  |  | ||||||
|  |     /// Returns true, if encryption is allowed (and document | ||||||
|  |     /// can be encrypted, if it was decrypted) | ||||||
|  |     virtual bool isEncryptionAllowed() const = 0; | ||||||
|  |  | ||||||
|     /// Returns result of authorization process |     /// Returns result of authorization process | ||||||
|     virtual AuthorizationResult getAuthorizationResult() const = 0; |     virtual AuthorizationResult getAuthorizationResult() const = 0; | ||||||
|  |  | ||||||
| @@ -192,8 +217,11 @@ public: | |||||||
|     virtual AuthorizationResult authenticate(const std::function<QString(bool*)>&, bool) override { return AuthorizationResult::OwnerAuthorized; } |     virtual AuthorizationResult authenticate(const std::function<QString(bool*)>&, bool) override { return AuthorizationResult::OwnerAuthorized; } | ||||||
|     virtual QByteArray decrypt(const QByteArray& data, PDFObjectReference, EncryptionScope) const override { return data; } |     virtual QByteArray decrypt(const QByteArray& data, PDFObjectReference, EncryptionScope) const override { return data; } | ||||||
|     virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray&, PDFObjectReference) const override { return data; } |     virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray&, PDFObjectReference) const override { return data; } | ||||||
|  |     virtual QByteArray encrypt(const QByteArray& data, PDFObjectReference, EncryptionScope) const override { return data; } | ||||||
|  |     virtual QByteArray encryptByFilter(const QByteArray& data, const QByteArray&, PDFObjectReference) const override { return data; } | ||||||
|     virtual bool isMetadataEncrypted() const override { return true; } |     virtual bool isMetadataEncrypted() const override { return true; } | ||||||
|     virtual bool isAllowed(Permission) const override { return true; } |     virtual bool isAllowed(Permission) const override { return true; } | ||||||
|  |     virtual bool isEncryptionAllowed() const override { return true; } | ||||||
|     virtual AuthorizationResult getAuthorizationResult() const override { return AuthorizationResult::NoAuthorizationRequired; } |     virtual AuthorizationResult getAuthorizationResult() const override { return AuthorizationResult::NoAuthorizationRequired; } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -206,8 +234,11 @@ public: | |||||||
|     virtual AuthorizationResult authenticate(const std::function<QString(bool*)>& getPasswordCallback, bool authorizeOwnerOnly) override; |     virtual AuthorizationResult authenticate(const std::function<QString(bool*)>& getPasswordCallback, bool authorizeOwnerOnly) override; | ||||||
|     virtual QByteArray decrypt(const QByteArray& data, PDFObjectReference reference, EncryptionScope encryptionScope) const override; |     virtual QByteArray decrypt(const QByteArray& data, PDFObjectReference reference, EncryptionScope encryptionScope) const override; | ||||||
|     virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const override; |     virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const override; | ||||||
|  |     virtual QByteArray encrypt(const QByteArray& data, PDFObjectReference reference, EncryptionScope encryptionScope) const override; | ||||||
|  |     virtual QByteArray encryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const override; | ||||||
|     virtual bool isMetadataEncrypted() const override { return m_encryptMetadata; } |     virtual bool isMetadataEncrypted() const override { return m_encryptMetadata; } | ||||||
|     virtual bool isAllowed(Permission permission) const override { return m_authorizationData.authorizationResult == AuthorizationResult::OwnerAuthorized || (m_permissions & static_cast<uint32_t>(permission)); } |     virtual bool isAllowed(Permission permission) const override { return m_authorizationData.authorizationResult == AuthorizationResult::OwnerAuthorized || (m_permissions & static_cast<uint32_t>(permission)); } | ||||||
|  |     virtual bool isEncryptionAllowed() const override { return m_authorizationData.isAuthorized(); } | ||||||
|     virtual AuthorizationResult getAuthorizationResult() const override { return m_authorizationData.authorizationResult; } |     virtual AuthorizationResult getAuthorizationResult() const override { return m_authorizationData.authorizationResult; } | ||||||
|  |  | ||||||
|     struct AuthorizationData |     struct AuthorizationData | ||||||
| @@ -267,6 +298,17 @@ private: | |||||||
|     /// \returns Decrypted data |     /// \returns Decrypted data | ||||||
|     QByteArray decryptUsingFilter(const QByteArray& data, CryptFilter filter, PDFObjectReference reference) const; |     QByteArray decryptUsingFilter(const QByteArray& data, CryptFilter filter, PDFObjectReference reference) const; | ||||||
|  |  | ||||||
|  |     /// Encrypts data using specified filter. This function can be called only, if authorization was successfull. | ||||||
|  |     /// \param data Data to be encrypted | ||||||
|  |     /// \param filter Filter to be used for encryption | ||||||
|  |     /// \param reference Object reference for key generation | ||||||
|  |     /// \returns Encrypted data | ||||||
|  |     QByteArray encryptUsingFilter(const QByteArray& data, CryptFilter filter, PDFObjectReference reference) const; | ||||||
|  |  | ||||||
|  |     std::vector<uint8_t> createV2_ObjectEncryptionKey(PDFObjectReference reference, CryptFilter filter) const; | ||||||
|  |     std::vector<uint8_t> createAESV2_ObjectEncryptionKey(PDFObjectReference reference) const; | ||||||
|  |     CryptFilter getCryptFilter(EncryptionScope encryptionScope) const; | ||||||
|  |  | ||||||
|     /// Returns true, if character with unicode code is non-ascii space character |     /// Returns true, if character with unicode code is non-ascii space character | ||||||
|     /// according the RFC 3454, section C.1.2 |     /// according the RFC 3454, section C.1.2 | ||||||
|     /// \param unicode Unicode code to be tested |     /// \param unicode Unicode code to be tested | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user