mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Encryption - RC4
This commit is contained in:
@ -500,6 +500,7 @@ public:
|
|||||||
Reset = 0x0001, ///< Whole document content is changed (for example, new document is being set)
|
Reset = 0x0001, ///< Whole document content is changed (for example, new document is being set)
|
||||||
Annotation = 0x0002, ///< Annotations changed
|
Annotation = 0x0002, ///< Annotations changed
|
||||||
FormField = 0x0004, ///< Form field content changed
|
FormField = 0x0004, ///< Form field content changed
|
||||||
|
Authorization = 0x0008, ///< Authorization has changed (for example, old document is granted user access, but for new, owner access)
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_FLAGS(ModificationFlags, ModificationFlag)
|
Q_DECLARE_FLAGS(ModificationFlags, ModificationFlag)
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "pdfencoding.h"
|
#include "pdfencoding.h"
|
||||||
#include "pdfvisitor.h"
|
#include "pdfvisitor.h"
|
||||||
#include "pdfutils.h"
|
#include "pdfutils.h"
|
||||||
|
#include "pdfdocumentbuilder.h"
|
||||||
|
|
||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
|
|
||||||
@ -508,6 +509,131 @@ PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObj
|
|||||||
return PDFSecurityHandlerPointer(new PDFStandardSecurityHandler(qMove(handler)));
|
return PDFSecurityHandlerPointer(new PDFStandardSecurityHandler(qMove(handler)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFSecurityHandler::fillEncryptionDictionary(PDFObjectFactory& factory)
|
||||||
|
{
|
||||||
|
factory.beginDictionaryItem("V");
|
||||||
|
factory << PDFInteger(m_V);
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
if (m_V == 2 || m_V == 3)
|
||||||
|
{
|
||||||
|
factory.beginDictionaryItem("Length");
|
||||||
|
factory << PDFInteger(m_keyLength);
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_V == 4 || m_V == 5)
|
||||||
|
{
|
||||||
|
factory.beginDictionaryItem("CF");
|
||||||
|
|
||||||
|
factory.beginDictionary();
|
||||||
|
|
||||||
|
QByteArray stmfName = "Identity";
|
||||||
|
QByteArray strfName = stmfName;
|
||||||
|
QByteArray effName = stmfName;
|
||||||
|
|
||||||
|
for (const auto& cryptFilter : m_cryptFilters)
|
||||||
|
{
|
||||||
|
factory.beginDictionaryItem(cryptFilter.first);
|
||||||
|
|
||||||
|
factory.beginDictionary();
|
||||||
|
factory.beginDictionaryItem("CFM");
|
||||||
|
|
||||||
|
if (cryptFilter.second == m_filterStrings)
|
||||||
|
{
|
||||||
|
strfName = cryptFilter.first;
|
||||||
|
}
|
||||||
|
if (cryptFilter.second == m_filterStreams)
|
||||||
|
{
|
||||||
|
stmfName = cryptFilter.first;
|
||||||
|
}
|
||||||
|
if (cryptFilter.second == m_filterEmbeddedFiles)
|
||||||
|
{
|
||||||
|
effName = cryptFilter.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cryptFilter.second.type)
|
||||||
|
{
|
||||||
|
case CryptFilterType::None:
|
||||||
|
// The application shall decrypt the data using the security handler
|
||||||
|
factory << WrapName("None");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CryptFilterType::V2:
|
||||||
|
// Use file encryption key for RC4 algorithm
|
||||||
|
factory << WrapName("V2");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CryptFilterType::AESV2:
|
||||||
|
// Use file encryption key for AES algorithm
|
||||||
|
factory << WrapName("AESV2");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CryptFilterType::AESV3:
|
||||||
|
// Use file encryption key for AES 256 bit algorithm
|
||||||
|
factory << WrapName("AESV3");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CryptFilterType::Identity:
|
||||||
|
// Don't decrypt anything, use identity function
|
||||||
|
factory << WrapName("Identity");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
factory << WrapName("None");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
factory.beginDictionaryItem("AuthEvent");
|
||||||
|
|
||||||
|
switch (cryptFilter.second.authEvent)
|
||||||
|
{
|
||||||
|
case AuthEvent::DocOpen:
|
||||||
|
factory << WrapName("DocOpen");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AuthEvent::EFOpen:
|
||||||
|
factory << WrapName("EFOpen");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
factory.beginDictionaryItem("Length");
|
||||||
|
factory << cryptFilter.second.keyLength;
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
factory.endDictionary();
|
||||||
|
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
factory.endDictionary();
|
||||||
|
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
// Store StmF, StrF, EFF
|
||||||
|
factory.beginDictionaryItem("StmF");
|
||||||
|
factory << stmfName;
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
factory.beginDictionaryItem("StrF");
|
||||||
|
factory << strfName;
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
factory.beginDictionaryItem("EFF");
|
||||||
|
factory << effName;
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PDFSecurityHandler* PDFStandardSecurityHandler::clone() const
|
PDFSecurityHandler* PDFStandardSecurityHandler::clone() const
|
||||||
{
|
{
|
||||||
return new PDFStandardSecurityHandler(*this);
|
return new PDFStandardSecurityHandler(*this);
|
||||||
@ -1009,6 +1135,62 @@ QByteArray PDFStandardSecurityHandler::encryptByFilter(const QByteArray& data, c
|
|||||||
return encryptUsingFilter(data, it->second, reference);
|
return encryptUsingFilter(data, it->second, reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFObject PDFStandardSecurityHandler::createEncryptionDictionaryObject() const
|
||||||
|
{
|
||||||
|
PDFObjectFactory factory;
|
||||||
|
|
||||||
|
factory.beginDictionary();
|
||||||
|
|
||||||
|
factory.beginDictionaryItem("Filter");
|
||||||
|
factory << WrapName("Standard");
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
factory.beginDictionaryItem("R");
|
||||||
|
factory << PDFInteger(m_R);
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
factory.beginDictionaryItem("O");
|
||||||
|
factory << m_O;
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
factory.beginDictionaryItem("U");
|
||||||
|
factory << m_U;
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
if (m_R == 6)
|
||||||
|
{
|
||||||
|
factory.beginDictionaryItem("OE");
|
||||||
|
factory << m_OE;
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
factory.beginDictionaryItem("UE");
|
||||||
|
factory << m_UE;
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
factory.beginDictionaryItem("P");
|
||||||
|
factory << PDFInteger(m_permissions);
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
|
||||||
|
if (m_R == 6)
|
||||||
|
{
|
||||||
|
factory.beginDictionaryItem("Perms");
|
||||||
|
factory << m_Perms;
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_V == 4 || m_V == 5)
|
||||||
|
{
|
||||||
|
factory.beginDictionaryItem("EncryptMetadata");
|
||||||
|
factory << m_encryptMetadata;
|
||||||
|
factory.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
factory.endDictionary();
|
||||||
|
|
||||||
|
return factory.takeObject();
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray PDFStandardSecurityHandler::createFileEncryptionKey(const QByteArray& password) const
|
QByteArray PDFStandardSecurityHandler::createFileEncryptionKey(const QByteArray& password) const
|
||||||
{
|
{
|
||||||
QByteArray result;
|
QByteArray result;
|
||||||
@ -1127,6 +1309,13 @@ QByteArray PDFStandardSecurityHandler::createEntryValueU_r234(const QByteArray&
|
|||||||
// want to compare byte arrays entirely (otherwise we must compare only 16 bytes to authenticate
|
// want to compare byte arrays entirely (otherwise we must compare only 16 bytes to authenticate
|
||||||
// user password).
|
// user password).
|
||||||
result = m_U;
|
result = m_U;
|
||||||
|
|
||||||
|
if (result.size() != 32)
|
||||||
|
{
|
||||||
|
// In case of error, we resize it to correct size. We can't assume, that m_U has correct length.
|
||||||
|
result.resize(32);
|
||||||
|
}
|
||||||
|
|
||||||
std::copy_n(encryptedHash.begin(), encryptedHash.size(), result.begin());
|
std::copy_n(encryptedHash.begin(), encryptedHash.size(), result.begin());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1491,9 +1680,149 @@ bool PDFStandardSecurityHandler::isUnicodeMappedToNothing(ushort unicode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const PDFSecurityHandlerFactory::SecuritySettings& settings)
|
PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const SecuritySettings& settings)
|
||||||
{
|
{
|
||||||
return nullptr;
|
if (settings.algorithm == Algorithm::None)
|
||||||
|
{
|
||||||
|
return PDFSecurityHandlerPointer(new PDFNoneSecurityHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jakub Melka: create standard security handler, with given settings
|
||||||
|
PDFStandardSecurityHandler* handler = new PDFStandardSecurityHandler();
|
||||||
|
|
||||||
|
const bool isEncryptingEmbeddedFilesOnly = settings.encryptContents == EncryptContents::EmbeddedFiles;
|
||||||
|
|
||||||
|
switch (settings.algorithm)
|
||||||
|
{
|
||||||
|
case RC4:
|
||||||
|
{
|
||||||
|
handler->m_V = 4;
|
||||||
|
handler->m_keyLength = 128;
|
||||||
|
|
||||||
|
CryptFilter defaultFilter;
|
||||||
|
defaultFilter.type = CryptFilterType::V2;
|
||||||
|
defaultFilter.authEvent = !isEncryptingEmbeddedFilesOnly ? AuthEvent::DocOpen : AuthEvent::EFOpen;
|
||||||
|
defaultFilter.keyLength = handler->m_keyLength / 8;
|
||||||
|
handler->m_filterDefault = defaultFilter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AES_128:
|
||||||
|
{
|
||||||
|
handler->m_V = 4;
|
||||||
|
handler->m_keyLength = 128;
|
||||||
|
|
||||||
|
CryptFilter defaultFilter;
|
||||||
|
defaultFilter.type = CryptFilterType::AESV2;
|
||||||
|
defaultFilter.authEvent = !isEncryptingEmbeddedFilesOnly ? AuthEvent::DocOpen : AuthEvent::EFOpen;
|
||||||
|
defaultFilter.keyLength = handler->m_keyLength / 8;
|
||||||
|
handler->m_filterDefault = defaultFilter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AES_256:
|
||||||
|
{
|
||||||
|
handler->m_V = 5;
|
||||||
|
handler->m_keyLength = 256;
|
||||||
|
|
||||||
|
CryptFilter defaultFilter;
|
||||||
|
defaultFilter.type = CryptFilterType::AESV3;
|
||||||
|
defaultFilter.authEvent = !isEncryptingEmbeddedFilesOnly ? AuthEvent::DocOpen : AuthEvent::EFOpen;
|
||||||
|
defaultFilter.keyLength = handler->m_keyLength / 8;
|
||||||
|
handler->m_filterDefault = defaultFilter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptFilter identityFilter;
|
||||||
|
identityFilter.type = CryptFilterType::Identity;
|
||||||
|
|
||||||
|
switch (settings.encryptContents)
|
||||||
|
{
|
||||||
|
case All:
|
||||||
|
handler->m_filterStrings = handler->m_filterDefault;
|
||||||
|
handler->m_filterStreams = handler->m_filterDefault;
|
||||||
|
handler->m_filterEmbeddedFiles = handler->m_filterDefault;
|
||||||
|
handler->m_encryptMetadata = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AllExceptMetadata:
|
||||||
|
handler->m_filterStrings = handler->m_filterDefault;
|
||||||
|
handler->m_filterStreams = handler->m_filterDefault;
|
||||||
|
handler->m_filterEmbeddedFiles = handler->m_filterDefault;
|
||||||
|
handler->m_encryptMetadata = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EmbeddedFiles:
|
||||||
|
handler->m_filterStrings = identityFilter;
|
||||||
|
handler->m_filterStreams = identityFilter;
|
||||||
|
handler->m_filterEmbeddedFiles = handler->m_filterDefault;
|
||||||
|
handler->m_encryptMetadata = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->m_cryptFilters["DefaultCF"] = handler->m_filterDefault;
|
||||||
|
handler->m_R = getRevisionFromAlgorithm(settings.algorithm);
|
||||||
|
handler->m_permissions = settings.permissions;
|
||||||
|
|
||||||
|
QByteArray adjustedOwnerPassword = handler->adjustPassword(settings.ownerPassword, handler->m_R);
|
||||||
|
QByteArray adjustedUserPassword = handler->adjustPassword(settings.userPassword, handler->m_R);
|
||||||
|
|
||||||
|
// Generate encryption entries
|
||||||
|
switch (handler->m_R)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
// Trick for computing "O" entry for revisions 2,3,4: in O entry, there is stored
|
||||||
|
// user password encrypted by owner password. Because RC4 cipher is symmetric, we
|
||||||
|
// can store user password in "O" entry and then use standard function to retrieve
|
||||||
|
// user password, which in fact will be encrypted user password.
|
||||||
|
|
||||||
|
std::array<uint8_t, 32> paddedUserPasswordArray = handler->createPaddedPassword32(adjustedUserPassword);
|
||||||
|
QByteArray paddedUserPassword;
|
||||||
|
paddedUserPassword.resize(int(paddedUserPasswordArray.size()));
|
||||||
|
std::copy(paddedUserPasswordArray.cbegin(), paddedUserPasswordArray.cend(), paddedUserPassword.data());
|
||||||
|
handler->m_O = paddedUserPassword;
|
||||||
|
QByteArray entryO = handler->createUserPasswordFromOwnerPassword(adjustedOwnerPassword);
|
||||||
|
handler->m_O = entryO;
|
||||||
|
Q_ASSERT(handler->createUserPasswordFromOwnerPassword(adjustedOwnerPassword) == paddedUserPassword);
|
||||||
|
|
||||||
|
handler->m_U.resize(32);
|
||||||
|
QRandomGenerator randomNumberGenerator = QRandomGenerator::securelySeeded();
|
||||||
|
for (int i = 0; i < handler->m_U.size(); ++i)
|
||||||
|
{
|
||||||
|
handler->m_U[i] = char(randomNumberGenerator.generate());
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray fileEncryptionKey = handler->createFileEncryptionKey(paddedUserPassword);
|
||||||
|
QByteArray U = handler->createEntryValueU_r234(fileEncryptionKey);
|
||||||
|
handler->m_U = U;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Dodelat R6
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->authenticate([&settings](bool* b) { *b = false; return settings.ownerPassword; }, true);
|
||||||
|
Q_ASSERT(handler->getAuthorizationResult() == PDFSecurityHandler::AuthorizationResult::OwnerAuthorized);
|
||||||
|
return PDFSecurityHandlerPointer(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PDFSecurityHandlerFactory::getPasswordOptimalEntropy()
|
int PDFSecurityHandlerFactory::getPasswordOptimalEntropy()
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
class PDFObjectFactory;
|
||||||
|
|
||||||
enum class EncryptionMode
|
enum class EncryptionMode
|
||||||
{
|
{
|
||||||
@ -61,6 +62,9 @@ enum class CryptFilterApplication
|
|||||||
|
|
||||||
struct CryptFilter
|
struct CryptFilter
|
||||||
{
|
{
|
||||||
|
bool operator ==(const CryptFilter&) const = default;
|
||||||
|
bool operator !=(const CryptFilter&) const = default;
|
||||||
|
|
||||||
CryptFilterType type = CryptFilterType::None;
|
CryptFilterType type = CryptFilterType::None;
|
||||||
AuthEvent authEvent = AuthEvent::DocOpen;
|
AuthEvent authEvent = AuthEvent::DocOpen;
|
||||||
int keyLength = 0; ///< Key length in bytes
|
int keyLength = 0; ///< Key length in bytes
|
||||||
@ -179,6 +183,9 @@ public:
|
|||||||
/// Returns result of authorization process
|
/// Returns result of authorization process
|
||||||
virtual AuthorizationResult getAuthorizationResult() const = 0;
|
virtual AuthorizationResult getAuthorizationResult() const = 0;
|
||||||
|
|
||||||
|
/// Creates encryption dictionary object
|
||||||
|
virtual PDFObject createEncryptionDictionaryObject() const = 0;
|
||||||
|
|
||||||
/// Returns version of the encryption
|
/// Returns version of the encryption
|
||||||
int getVersion() const { return m_V; }
|
int getVersion() const { return m_V; }
|
||||||
|
|
||||||
@ -189,6 +196,11 @@ public:
|
|||||||
static PDFSecurityHandlerPointer createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id);
|
static PDFSecurityHandlerPointer createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
/// Fills encryption dictionary with basic data
|
||||||
|
/// \param factory Factory
|
||||||
|
void fillEncryptionDictionary(PDFObjectFactory& factory);
|
||||||
|
|
||||||
/// Version of the encryption, shall be a number from 1 to 5, according the
|
/// Version of the encryption, shall be a number from 1 to 5, according the
|
||||||
/// PDF specification. Other values are invalid.
|
/// PDF specification. Other values are invalid.
|
||||||
int m_V = 0;
|
int m_V = 0;
|
||||||
@ -227,6 +239,7 @@ public:
|
|||||||
virtual bool isAllowed(Permission) const override { return true; }
|
virtual bool isAllowed(Permission) const override { return true; }
|
||||||
virtual bool isEncryptionAllowed() 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; }
|
||||||
|
virtual PDFObject createEncryptionDictionaryObject() const override { return PDFObject(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Specifies the security using standard security handler (see PDF specification
|
/// Specifies the security using standard security handler (see PDF specification
|
||||||
@ -245,6 +258,7 @@ public:
|
|||||||
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 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; }
|
||||||
|
virtual PDFObject createEncryptionDictionaryObject() const override;
|
||||||
|
|
||||||
struct AuthorizationData
|
struct AuthorizationData
|
||||||
{
|
{
|
||||||
@ -258,6 +272,7 @@ public:
|
|||||||
static QByteArray adjustPassword(const QString& password, int revision);
|
static QByteArray adjustPassword(const QString& password, int revision);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class PDFSecurityHandlerFactory;
|
||||||
friend PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id);
|
friend PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id);
|
||||||
|
|
||||||
struct UserOwnerData_r6
|
struct UserOwnerData_r6
|
||||||
|
@ -128,6 +128,16 @@ void PDFEncryptionSettingsDialog::updateUi()
|
|||||||
ui->userPasswordEdit->setEnabled(ui->userPasswordEnableCheckBox->isChecked());
|
ui->userPasswordEdit->setEnabled(ui->userPasswordEnableCheckBox->isChecked());
|
||||||
ui->ownerPasswordEdit->setEnabled(ui->ownerPasswordEnableCheckBox->isChecked());
|
ui->ownerPasswordEdit->setEnabled(ui->ownerPasswordEnableCheckBox->isChecked());
|
||||||
|
|
||||||
|
if (!ui->userPasswordEdit->isEnabled())
|
||||||
|
{
|
||||||
|
ui->userPasswordEdit->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ui->ownerPasswordEdit->isEnabled())
|
||||||
|
{
|
||||||
|
ui->ownerPasswordEdit->clear();
|
||||||
|
}
|
||||||
|
|
||||||
ui->userPasswordStrengthHintWidget->setEnabled(ui->userPasswordEnableCheckBox->isChecked());
|
ui->userPasswordStrengthHintWidget->setEnabled(ui->userPasswordEnableCheckBox->isChecked());
|
||||||
ui->ownerPasswordStrengthHintWidget->setEnabled(ui->ownerPasswordEnableCheckBox->isChecked());
|
ui->ownerPasswordStrengthHintWidget->setEnabled(ui->ownerPasswordEnableCheckBox->isChecked());
|
||||||
|
|
||||||
@ -151,4 +161,37 @@ void PDFEncryptionSettingsDialog::updatePasswordScore()
|
|||||||
ui->ownerPasswordStrengthHintWidget->setCurrentValue(ownerPasswordScore);
|
ui->ownerPasswordStrengthHintWidget->setCurrentValue(ownerPasswordScore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFEncryptionSettingsDialog::accept()
|
||||||
|
{
|
||||||
|
pdf::PDFSecurityHandlerFactory::SecuritySettings settings;
|
||||||
|
pdf::PDFSecurityHandlerFactory::EncryptContents encryptContents = pdf::PDFSecurityHandlerFactory::All;
|
||||||
|
|
||||||
|
if (ui->encryptAllExceptMetadataRadioButton->isChecked())
|
||||||
|
{
|
||||||
|
encryptContents = pdf::PDFSecurityHandlerFactory::AllExceptMetadata;
|
||||||
|
}
|
||||||
|
else if (ui->encryptFileAttachmentsOnlyRadioButton->isChecked())
|
||||||
|
{
|
||||||
|
encryptContents = pdf::PDFSecurityHandlerFactory::EmbeddedFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.algorithm = static_cast<const pdf::PDFSecurityHandlerFactory::Algorithm>(ui->algorithmComboBox->currentData().toInt());
|
||||||
|
settings.encryptContents = encryptContents;
|
||||||
|
settings.userPassword = ui->userPasswordEdit->text();
|
||||||
|
settings.ownerPassword = ui->ownerPasswordEdit->text();
|
||||||
|
settings.permissions = 0;
|
||||||
|
|
||||||
|
for (auto item : m_checkBoxToPermission)
|
||||||
|
{
|
||||||
|
if (item.first->isChecked())
|
||||||
|
{
|
||||||
|
settings.permissions += uint32_t(item.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_updatedSecurityHandler = pdf::PDFSecurityHandlerFactory::createSecurityHandler(settings);
|
||||||
|
|
||||||
|
QDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdfviewer
|
} // namespace pdfviewer
|
||||||
|
@ -41,6 +41,9 @@ public:
|
|||||||
explicit PDFEncryptionSettingsDialog(QWidget* parent);
|
explicit PDFEncryptionSettingsDialog(QWidget* parent);
|
||||||
virtual ~PDFEncryptionSettingsDialog() override;
|
virtual ~PDFEncryptionSettingsDialog() override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void accept() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::PDFEncryptionSettingsDialog* ui;
|
Ui::PDFEncryptionSettingsDialog* ui;
|
||||||
|
|
||||||
@ -49,6 +52,7 @@ private:
|
|||||||
|
|
||||||
bool m_isUpdatingUi;
|
bool m_isUpdatingUi;
|
||||||
std::map<QCheckBox*, pdf::PDFSecurityHandler::Permission> m_checkBoxToPermission;
|
std::map<QCheckBox*, pdf::PDFSecurityHandler::Permission> m_checkBoxToPermission;
|
||||||
|
pdf::PDFSecurityHandlerPointer m_updatedSecurityHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdfviewer
|
} // namespace pdfviewer
|
||||||
|
@ -1163,7 +1163,7 @@ void PDFProgramController::onActionEncryptionTriggered()
|
|||||||
storage.setSecurityHandler(qMove(clonedSecurityHandler));
|
storage.setSecurityHandler(qMove(clonedSecurityHandler));
|
||||||
|
|
||||||
pdf::PDFDocumentPointer pointer(new pdf::PDFDocument(qMove(storage), m_pdfDocument->getInfo()->version));
|
pdf::PDFDocumentPointer pointer(new pdf::PDFDocument(qMove(storage), m_pdfDocument->getInfo()->version));
|
||||||
pdf::PDFModifiedDocument document(qMove(pointer), m_optionalContentActivity, pdf::PDFModifiedDocument::Reset);
|
pdf::PDFModifiedDocument document(qMove(pointer), m_optionalContentActivity, pdf::PDFModifiedDocument::Authorization);
|
||||||
onDocumentModified(qMove(document));
|
onDocumentModified(qMove(document));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user