mirror of https://github.com/JakubMelka/PDF4QT.git
Public key encryption: authorization, create file encryption key
This commit is contained in:
parent
c20959c190
commit
44fc1e021c
|
@ -10,7 +10,6 @@ Section 6: OK
|
||||||
|
|
||||||
Section 7: Issues
|
Section 7: Issues
|
||||||
- 7.4.7 JBIG2 decoder ammendments 1 and 2 not implemented
|
- 7.4.7 JBIG2 decoder ammendments 1 and 2 not implemented
|
||||||
- 7.6.5 Public-key security handlers not implemented
|
|
||||||
- 7.6.7 Unencrypted wrapper document not implemented
|
- 7.6.7 Unencrypted wrapper document not implemented
|
||||||
- 7.10.2 Only linear interpolation for sampled function is performed
|
- 7.10.2 Only linear interpolation for sampled function is performed
|
||||||
|
|
||||||
|
@ -71,7 +70,7 @@ Section 12: Issues
|
||||||
to PDF specification, but all unicode characters can be used.
|
to PDF specification, but all unicode characters can be used.
|
||||||
- 12.7.5.5 Signature field locking not implemented and signature
|
- 12.7.5.5 Signature field locking not implemented and signature
|
||||||
seed dictionary is ignored
|
seed dictionary is ignored
|
||||||
- 12.7.6.2 Sumbit form action not implemented in viewer
|
- 12.7.6.2 Submit form action not implemented in viewer
|
||||||
- 12.7.6.4 Import data action not implemented in viewer
|
- 12.7.6.4 Import data action not implemented in viewer
|
||||||
- 12.7.8 Form data format not implemented
|
- 12.7.8 Form data format not implemented
|
||||||
- 12.8 Modification detection using UR3/DocMDP method is not
|
- 12.8 Modification detection using UR3/DocMDP method is not
|
||||||
|
|
|
@ -140,7 +140,8 @@ QFileInfoList PDFCertificateManager::getCertificates()
|
||||||
|
|
||||||
QString PDFCertificateManager::getCertificateDirectory()
|
QString PDFCertificateManager::getCertificateDirectory()
|
||||||
{
|
{
|
||||||
QDir directory(QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).front() + "/certificates/");
|
QString standardDataLocation = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).front();
|
||||||
|
QDir directory(standardDataLocation + "/certificates/");
|
||||||
return directory.absolutePath();
|
return directory.absolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2019-2022 Jakub Melka
|
// Copyright (C) 2019-2022 Jakub Melka
|
||||||
//
|
//
|
||||||
// This file is part of PDF4QT.
|
// This file is part of PDF4QT.
|
||||||
//
|
//
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
#include "pdfutils.h"
|
#include "pdfutils.h"
|
||||||
#include "pdfdocumentbuilder.h"
|
#include "pdfdocumentbuilder.h"
|
||||||
#include "pdfdbgheap.h"
|
#include "pdfdbgheap.h"
|
||||||
|
#include "pdfcertificatemanager.h"
|
||||||
|
|
||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
|
|
||||||
|
@ -29,12 +30,18 @@
|
||||||
#include <openssl/md5.h>
|
#include <openssl/md5.h>
|
||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/pkcs7.h>
|
||||||
|
#include <openssl/pkcs12.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using openssl_ptr = std::unique_ptr<T, void(*)(T*)>;
|
||||||
|
|
||||||
// Padding password
|
// Padding password
|
||||||
static constexpr std::array<uint8_t, 32> PDFPasswordPadding = {
|
static constexpr std::array<uint8_t, 32> PDFPasswordPadding = {
|
||||||
0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
|
0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
|
||||||
|
@ -444,6 +451,15 @@ PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObj
|
||||||
{
|
{
|
||||||
auto typedHandler = qSharedPointerDynamicCast<PDFPublicKeySecurityHandler>(handler);
|
auto typedHandler = qSharedPointerDynamicCast<PDFPublicKeySecurityHandler>(handler);
|
||||||
typedHandler->m_filterDefault.recipients = parseRecipients(dictionary);
|
typedHandler->m_filterDefault.recipients = parseRecipients(dictionary);
|
||||||
|
|
||||||
|
if (typedHandler->m_filterDefault.recipients.isEmpty())
|
||||||
|
{
|
||||||
|
auto it = typedHandler->m_cryptFilters.find("DefaultCryptFilter");
|
||||||
|
if (it != typedHandler->m_cryptFilters.end())
|
||||||
|
{
|
||||||
|
typedHandler->m_filterDefault = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1047,6 +1063,118 @@ QByteArray PDFStandardOrPublicSecurityHandler::encryptByFilter(const QByteArray&
|
||||||
return encryptUsingFilter(data, it->second, reference);
|
return encryptUsingFilter(data, it->second, reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PDFStandardOrPublicSecurityHandler::isUnicodeNonAsciiSpaceCharacter(ushort unicode)
|
||||||
|
{
|
||||||
|
switch (unicode)
|
||||||
|
{
|
||||||
|
case 0x00A0:
|
||||||
|
case 0x1680:
|
||||||
|
case 0x2000:
|
||||||
|
case 0x2001:
|
||||||
|
case 0x2002:
|
||||||
|
case 0x2003:
|
||||||
|
case 0x2004:
|
||||||
|
case 0x2005:
|
||||||
|
case 0x2006:
|
||||||
|
case 0x2007:
|
||||||
|
case 0x2008:
|
||||||
|
case 0x2009:
|
||||||
|
case 0x200A:
|
||||||
|
case 0x200B:
|
||||||
|
case 0x202F:
|
||||||
|
case 0x205F:
|
||||||
|
case 0x3000:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PDFStandardOrPublicSecurityHandler::isUnicodeMappedToNothing(ushort unicode)
|
||||||
|
{
|
||||||
|
switch (unicode)
|
||||||
|
{
|
||||||
|
case 0x00AD:
|
||||||
|
case 0x034F:
|
||||||
|
case 0x1806:
|
||||||
|
case 0x180B:
|
||||||
|
case 0x180C:
|
||||||
|
case 0x180D:
|
||||||
|
case 0x200B:
|
||||||
|
case 0x200C:
|
||||||
|
case 0x200D:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray PDFStandardOrPublicSecurityHandler::adjustPassword(const QString& password, int revision)
|
||||||
|
{
|
||||||
|
QByteArray result;
|
||||||
|
|
||||||
|
switch (revision)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
// According to the PDF specification, convert string to PDFDocEncoding encoding
|
||||||
|
result = PDFEncoding::convertToEncoding(password, PDFEncoding::Encoding::PDFDoc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
{
|
||||||
|
// According to the PDF specification, use SASLprep profile for stringprep RFC 4013, please see these websites:
|
||||||
|
// - RFC 4013: https://tools.ietf.org/html/rfc4013 (SASLprep profile for stringprep algorithm)
|
||||||
|
// - RFC 3454: https://tools.ietf.org/html/rfc3454 (stringprep algorithm - preparation of internationalized strings)
|
||||||
|
//
|
||||||
|
// Note: we don't do checks according the RFC 4013, just use the mapping and normalize string in KC
|
||||||
|
|
||||||
|
QString preparedPassword;
|
||||||
|
preparedPassword.reserve(password.size());
|
||||||
|
|
||||||
|
// RFC 4013 Section 2.1, use mapping
|
||||||
|
|
||||||
|
for (const QChar character : password)
|
||||||
|
{
|
||||||
|
if (isUnicodeMappedToNothing(character.unicode()))
|
||||||
|
{
|
||||||
|
// Mapped to nothing
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isUnicodeNonAsciiSpaceCharacter(character.unicode()))
|
||||||
|
{
|
||||||
|
// Map to space character
|
||||||
|
preparedPassword += QChar(QChar::Space);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
preparedPassword += character;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RFC 4013, Section 2.2, normalization to KC
|
||||||
|
preparedPassword = preparedPassword.normalized(QString::NormalizationForm_KC);
|
||||||
|
|
||||||
|
// We don't do other checks. We will transform password to the UTF-8 encoding
|
||||||
|
// and according the PDF specification, we take only first 127 characters.
|
||||||
|
result = preparedPassword.toUtf8().left(127);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = password.toLatin1();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
PDFSecurityHandler* PDFStandardSecurityHandler::clone() const
|
PDFSecurityHandler* PDFStandardSecurityHandler::clone() const
|
||||||
{
|
{
|
||||||
return new PDFStandardSecurityHandler(*this);
|
return new PDFStandardSecurityHandler(*this);
|
||||||
|
@ -1653,117 +1781,6 @@ PDFStandardSecurityHandler::UserOwnerData_r6 PDFStandardSecurityHandler::parsePa
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray PDFStandardSecurityHandler::adjustPassword(const QString& password, int revision)
|
|
||||||
{
|
|
||||||
QByteArray result;
|
|
||||||
|
|
||||||
switch (revision)
|
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
{
|
|
||||||
// According to the PDF specification, convert string to PDFDocEncoding encoding
|
|
||||||
result = PDFEncoding::convertToEncoding(password, PDFEncoding::Encoding::PDFDoc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
case 6:
|
|
||||||
{
|
|
||||||
// According to the PDF specification, use SASLprep profile for stringprep RFC 4013, please see these websites:
|
|
||||||
// - RFC 4013: https://tools.ietf.org/html/rfc4013 (SASLprep profile for stringprep algorithm)
|
|
||||||
// - RFC 3454: https://tools.ietf.org/html/rfc3454 (stringprep algorithm - preparation of internationalized strings)
|
|
||||||
//
|
|
||||||
// Note: we don't do checks according the RFC 4013, just use the mapping and normalize string in KC
|
|
||||||
|
|
||||||
QString preparedPassword;
|
|
||||||
preparedPassword.reserve(password.size());
|
|
||||||
|
|
||||||
// RFC 4013 Section 2.1, use mapping
|
|
||||||
|
|
||||||
for (const QChar character : password)
|
|
||||||
{
|
|
||||||
if (isUnicodeMappedToNothing(character.unicode()))
|
|
||||||
{
|
|
||||||
// Mapped to nothing
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isUnicodeNonAsciiSpaceCharacter(character.unicode()))
|
|
||||||
{
|
|
||||||
// Map to space character
|
|
||||||
preparedPassword += QChar(QChar::Space);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
preparedPassword += character;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 4013, Section 2.2, normalization to KC
|
|
||||||
preparedPassword = preparedPassword.normalized(QString::NormalizationForm_KC);
|
|
||||||
|
|
||||||
// We don't do other checks. We will transform password to the UTF-8 encoding
|
|
||||||
// and according the PDF specification, we take only first 127 characters.
|
|
||||||
result = preparedPassword.toUtf8().left(127);
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PDFStandardSecurityHandler::isUnicodeNonAsciiSpaceCharacter(ushort unicode)
|
|
||||||
{
|
|
||||||
switch (unicode)
|
|
||||||
{
|
|
||||||
case 0x00A0:
|
|
||||||
case 0x1680:
|
|
||||||
case 0x2000:
|
|
||||||
case 0x2001:
|
|
||||||
case 0x2002:
|
|
||||||
case 0x2003:
|
|
||||||
case 0x2004:
|
|
||||||
case 0x2005:
|
|
||||||
case 0x2006:
|
|
||||||
case 0x2007:
|
|
||||||
case 0x2008:
|
|
||||||
case 0x2009:
|
|
||||||
case 0x200A:
|
|
||||||
case 0x200B:
|
|
||||||
case 0x202F:
|
|
||||||
case 0x205F:
|
|
||||||
case 0x3000:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PDFStandardSecurityHandler::isUnicodeMappedToNothing(ushort unicode)
|
|
||||||
{
|
|
||||||
switch (unicode)
|
|
||||||
{
|
|
||||||
case 0x00AD:
|
|
||||||
case 0x034F:
|
|
||||||
case 0x1806:
|
|
||||||
case 0x180B:
|
|
||||||
case 0x180C:
|
|
||||||
case 0x180D:
|
|
||||||
case 0x200B:
|
|
||||||
case 0x200C:
|
|
||||||
case 0x200D:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const SecuritySettings& settings)
|
PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const SecuritySettings& settings)
|
||||||
{
|
{
|
||||||
if (settings.algorithm == Algorithm::None)
|
if (settings.algorithm == Algorithm::None)
|
||||||
|
@ -2125,7 +2142,159 @@ PDFSecurityHandler* PDFPublicKeySecurityHandler::clone() const
|
||||||
|
|
||||||
PDFSecurityHandler::AuthorizationResult PDFPublicKeySecurityHandler::authenticate(const std::function<QString (bool*)>& getPasswordCallback, bool authorizeOwnerOnly)
|
PDFSecurityHandler::AuthorizationResult PDFPublicKeySecurityHandler::authenticate(const std::function<QString (bool*)>& getPasswordCallback, bool authorizeOwnerOnly)
|
||||||
{
|
{
|
||||||
return AuthorizationResult::Failed;
|
// Clear the authorization data
|
||||||
|
m_authorizationData = AuthorizationData();
|
||||||
|
|
||||||
|
if (authorizeOwnerOnly)
|
||||||
|
{
|
||||||
|
return AuthorizationResult::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_keyLength)
|
||||||
|
{
|
||||||
|
case 128:
|
||||||
|
case 256:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return AuthorizationResult::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool passwordObtained = true;
|
||||||
|
constexpr int revision = 0;
|
||||||
|
QByteArray password = adjustPassword(getPasswordCallback(&passwordObtained), revision);
|
||||||
|
|
||||||
|
QFileInfoList certificates = PDFCertificateManager::getCertificates();
|
||||||
|
if (certificates.isEmpty())
|
||||||
|
{
|
||||||
|
return AuthorizationResult::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<openssl_ptr<PKCS7>> recipients;
|
||||||
|
|
||||||
|
for (const QByteArray& recipient : m_filterDefault.recipients)
|
||||||
|
{
|
||||||
|
const unsigned char* data = convertByteArrayToUcharPtr(recipient);
|
||||||
|
if (PKCS7* pkcs7 = d2i_PKCS7(nullptr, &data, recipient.size()))
|
||||||
|
{
|
||||||
|
recipients.emplace_back(pkcs7, PKCS7_free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (passwordObtained)
|
||||||
|
{
|
||||||
|
// We will iterate trough all certificates
|
||||||
|
for (const QFileInfo& certificateFileInfo : certificates)
|
||||||
|
{
|
||||||
|
if (!PDFCertificateManager::isCertificateValid(certificateFileInfo.absoluteFilePath(), password))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(certificateFileInfo.absoluteFilePath());
|
||||||
|
if (file.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
QByteArray data = file.readAll();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
openssl_ptr<BIO> pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
|
BIO_write(pksBuffer.get(), data.constData(), data.length());
|
||||||
|
|
||||||
|
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free);
|
||||||
|
if (pkcs12)
|
||||||
|
{
|
||||||
|
const char* passwordPointer = nullptr;
|
||||||
|
if (!password.isEmpty())
|
||||||
|
{
|
||||||
|
passwordPointer = password.constData();
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_PKEY* keyPtr = nullptr;
|
||||||
|
X509* certificatePtr = nullptr;
|
||||||
|
STACK_OF(X509)* certificatesPtr = nullptr;
|
||||||
|
|
||||||
|
// Parse PKCS12 with password
|
||||||
|
bool isParsed = PKCS12_parse(pkcs12.get(), passwordPointer, &keyPtr, &certificatePtr, &certificatesPtr) == 1;
|
||||||
|
|
||||||
|
if (!isParsed)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
openssl_ptr<EVP_PKEY> key(keyPtr, EVP_PKEY_free);
|
||||||
|
openssl_ptr<X509> certificate(certificatePtr, X509_free);
|
||||||
|
openssl_ptr<STACK_OF(X509)> certificates(certificatesPtr, sk_X509_free);
|
||||||
|
|
||||||
|
for (const auto& recipientItem : recipients)
|
||||||
|
{
|
||||||
|
PKCS7* pkcs7 = recipientItem.get();
|
||||||
|
|
||||||
|
openssl_ptr<BIO> dataBuffer(BIO_new(BIO_s_mem()), BIO_free_all);
|
||||||
|
if (PKCS7_decrypt(pkcs7, keyPtr, certificatePtr, dataBuffer.get(), 0) == 1)
|
||||||
|
{
|
||||||
|
BUF_MEM* memoryBuffer = nullptr;
|
||||||
|
BIO_get_mem_ptr(dataBuffer.get(), &memoryBuffer);
|
||||||
|
|
||||||
|
// Acc. to chapter 7.6.5.3 - decrypted data
|
||||||
|
QByteArray decryptedData(memoryBuffer->data, int(memoryBuffer->length));
|
||||||
|
|
||||||
|
// Calculate file encryption key
|
||||||
|
EVP_MD_CTX* context = EVP_MD_CTX_new();
|
||||||
|
Q_ASSERT(context);
|
||||||
|
|
||||||
|
switch (m_keyLength)
|
||||||
|
{
|
||||||
|
case 128:
|
||||||
|
EVP_DigestInit(context, EVP_sha1());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 256:
|
||||||
|
EVP_DigestInit(context, EVP_sha256());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
EVP_DigestInit(context, EVP_sha256());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray seed = decryptedData.left(20);
|
||||||
|
|
||||||
|
// 7.6.5.3 a)
|
||||||
|
EVP_DigestUpdate(context, seed.constData(), seed.size());
|
||||||
|
|
||||||
|
// 7.6.5.3 b)
|
||||||
|
for (const QByteArray& recipient : m_filterDefault.recipients)
|
||||||
|
{
|
||||||
|
EVP_DigestUpdate(context, recipient.constData(), recipient.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7.6.5.3 c)
|
||||||
|
if (!isMetadataEncrypted())
|
||||||
|
{
|
||||||
|
constexpr uint32_t value = 0xFFFFFFFF;
|
||||||
|
EVP_DigestUpdate(context, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int size = EVP_MD_size(EVP_MD_CTX_md(context));
|
||||||
|
QByteArray digestBuffer(size, char());
|
||||||
|
|
||||||
|
EVP_DigestFinal_ex(context, convertByteArrayToUcharPtr(digestBuffer), &size);
|
||||||
|
EVP_MD_CTX_free(context);
|
||||||
|
|
||||||
|
m_authorizationData.fileEncryptionKey = digestBuffer.left(m_keyLength / 8);
|
||||||
|
m_authorizationData.authorizationResult = AuthorizationResult::UserAuthorized;
|
||||||
|
return AuthorizationResult::UserAuthorized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
password = adjustPassword(getPasswordCallback(&passwordObtained), revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AuthorizationResult::Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PDFPublicKeySecurityHandler::isMetadataEncrypted() const
|
bool PDFPublicKeySecurityHandler::isMetadataEncrypted() const
|
||||||
|
|
|
@ -264,6 +264,9 @@ public:
|
||||||
virtual AuthorizationResult getAuthorizationResult() const override { return m_authorizationData.authorizationResult; }
|
virtual AuthorizationResult getAuthorizationResult() const override { return m_authorizationData.authorizationResult; }
|
||||||
virtual bool isEncryptionAllowed() const override { return m_authorizationData.isAuthorized(); }
|
virtual bool isEncryptionAllowed() const override { return m_authorizationData.isAuthorized(); }
|
||||||
|
|
||||||
|
/// Adjusts the password according to the PDF specification
|
||||||
|
static QByteArray adjustPassword(const QString& password, int revision);
|
||||||
|
|
||||||
struct AuthorizationData
|
struct AuthorizationData
|
||||||
{
|
{
|
||||||
bool isAuthorized() const { return authorizationResult == AuthorizationResult::UserAuthorized || authorizationResult == AuthorizationResult::OwnerAuthorized; }
|
bool isAuthorized() const { return authorizationResult == AuthorizationResult::UserAuthorized || authorizationResult == AuthorizationResult::OwnerAuthorized; }
|
||||||
|
@ -287,6 +290,16 @@ protected:
|
||||||
/// \returns Encrypted data
|
/// \returns Encrypted data
|
||||||
QByteArray encryptUsingFilter(const QByteArray& data, CryptFilter filter, PDFObjectReference reference) const;
|
QByteArray encryptUsingFilter(const QByteArray& data, CryptFilter filter, PDFObjectReference reference) const;
|
||||||
|
|
||||||
|
/// Returns true, if character with unicode code is non-ascii space character
|
||||||
|
/// according the RFC 3454, section C.1.2
|
||||||
|
/// \param unicode Unicode code to be tested
|
||||||
|
static bool isUnicodeNonAsciiSpaceCharacter(ushort unicode);
|
||||||
|
|
||||||
|
/// Returns true, if character with unicode code is mapped to nothing,
|
||||||
|
/// according the RFC 3454, section B.1
|
||||||
|
/// \param unicode Unicode code to be tested
|
||||||
|
static bool isUnicodeMappedToNothing(ushort unicode);
|
||||||
|
|
||||||
std::vector<uint8_t> createV2_ObjectEncryptionKey(PDFObjectReference reference, CryptFilter filter) const;
|
std::vector<uint8_t> createV2_ObjectEncryptionKey(PDFObjectReference reference, CryptFilter filter) const;
|
||||||
std::vector<uint8_t> createAESV2_ObjectEncryptionKey(PDFObjectReference reference) const;
|
std::vector<uint8_t> createAESV2_ObjectEncryptionKey(PDFObjectReference reference) const;
|
||||||
CryptFilter getCryptFilter(EncryptionScope encryptionScope) const;
|
CryptFilter getCryptFilter(EncryptionScope encryptionScope) const;
|
||||||
|
@ -307,9 +320,6 @@ 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 PDFObject createEncryptionDictionaryObject() const override;
|
virtual PDFObject createEncryptionDictionaryObject() const override;
|
||||||
|
|
||||||
/// Adjusts the password according to the PDF specification
|
|
||||||
static QByteArray adjustPassword(const QString& password, int revision);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class PDFSecurityHandler;
|
friend class PDFSecurityHandler;
|
||||||
friend class PDFSecurityHandlerFactory;
|
friend class PDFSecurityHandlerFactory;
|
||||||
|
@ -351,16 +361,6 @@ private:
|
||||||
/// Parses parts of the user/owner data (U/O values of the encryption dictionary)
|
/// Parses parts of the user/owner data (U/O values of the encryption dictionary)
|
||||||
UserOwnerData_r6 parseParts(const QByteArray& data) const;
|
UserOwnerData_r6 parseParts(const QByteArray& data) const;
|
||||||
|
|
||||||
/// Returns true, if character with unicode code is non-ascii space character
|
|
||||||
/// according the RFC 3454, section C.1.2
|
|
||||||
/// \param unicode Unicode code to be tested
|
|
||||||
static bool isUnicodeNonAsciiSpaceCharacter(ushort unicode);
|
|
||||||
|
|
||||||
/// Returns true, if character with unicode code is mapped to nothing,
|
|
||||||
/// according the RFC 3454, section B.1
|
|
||||||
/// \param unicode Unicode code to be tested
|
|
||||||
static bool isUnicodeMappedToNothing(ushort unicode);
|
|
||||||
|
|
||||||
/// Revision number of standard security number
|
/// Revision number of standard security number
|
||||||
int m_R = 0;
|
int m_R = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue