mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-02-24 23:47:49 +01:00
Public key encryption: initiate new security handler
This commit is contained in:
parent
6ff29d5d38
commit
ac039a1539
@ -1823,9 +1823,26 @@ PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const
|
|||||||
return PDFSecurityHandlerPointer(new PDFNoneSecurityHandler);
|
return PDFSecurityHandlerPointer(new PDFNoneSecurityHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jakub Melka: create standard security handler, with given settings
|
// Jakub Melka: create standard security or public key handler, with given settings
|
||||||
PDFStandardSecurityHandler* handler = new PDFStandardSecurityHandler();
|
PDFStandardSecurityHandler* standardHandler = nullptr;
|
||||||
handler->m_ID = settings.id;
|
PDFPublicKeySecurityHandler* publicKeyHandler = nullptr;
|
||||||
|
PDFStandardOrPublicSecurityHandler* handler = nullptr;
|
||||||
|
|
||||||
|
if (settings.algorithm != Algorithm::Certificate)
|
||||||
|
{
|
||||||
|
standardHandler = new PDFStandardSecurityHandler();
|
||||||
|
handler = standardHandler;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
publicKeyHandler = new PDFPublicKeySecurityHandler();
|
||||||
|
handler = publicKeyHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (standardHandler)
|
||||||
|
{
|
||||||
|
standardHandler->m_ID = settings.id;
|
||||||
|
}
|
||||||
|
|
||||||
const bool isEncryptingEmbeddedFilesOnly = settings.encryptContents == EncryptContents::EmbeddedFiles;
|
const bool isEncryptingEmbeddedFilesOnly = settings.encryptContents == EncryptContents::EmbeddedFiles;
|
||||||
|
|
||||||
@ -1858,6 +1875,7 @@ PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const
|
|||||||
}
|
}
|
||||||
|
|
||||||
case AES_256:
|
case AES_256:
|
||||||
|
case Certificate:
|
||||||
{
|
{
|
||||||
handler->m_V = 5;
|
handler->m_V = 5;
|
||||||
handler->m_keyLength = 256;
|
handler->m_keyLength = 256;
|
||||||
@ -1878,27 +1896,122 @@ PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const
|
|||||||
CryptFilter identityFilter;
|
CryptFilter identityFilter;
|
||||||
identityFilter.type = CryptFilterType::Identity;
|
identityFilter.type = CryptFilterType::Identity;
|
||||||
|
|
||||||
|
if (standardHandler)
|
||||||
|
{
|
||||||
|
standardHandler->m_encryptMetadata = settings.encryptContents == All;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publicKeyHandler)
|
||||||
|
{
|
||||||
|
publicKeyHandler->m_filterDefault.encryptMetadata = settings.encryptContents == All;
|
||||||
|
publicKeyHandler->m_pkcs7Type = PDFPublicKeySecurityHandler::PKCS7_Type::PKCS7_S5;
|
||||||
|
publicKeyHandler->m_permissions = 0;
|
||||||
|
|
||||||
|
if (settings.permissions & uint32_t(PDFSecurityHandler::Permission::PrintLowResolution))
|
||||||
|
{
|
||||||
|
publicKeyHandler->m_permissions = publicKeyHandler->m_permissions | PDFPublicKeySecurityHandler::PKSH_PrintLowResolution;
|
||||||
|
}
|
||||||
|
if (settings.permissions & uint32_t(PDFSecurityHandler::Permission::Modify))
|
||||||
|
{
|
||||||
|
publicKeyHandler->m_permissions = publicKeyHandler->m_permissions | PDFPublicKeySecurityHandler::PKSH_Modify;
|
||||||
|
}
|
||||||
|
if (settings.permissions & uint32_t(PDFSecurityHandler::Permission::CopyContent))
|
||||||
|
{
|
||||||
|
publicKeyHandler->m_permissions = publicKeyHandler->m_permissions | PDFPublicKeySecurityHandler::PKSH_CopyContent;
|
||||||
|
}
|
||||||
|
if (settings.permissions & uint32_t(PDFSecurityHandler::Permission::ModifyInteractiveItems))
|
||||||
|
{
|
||||||
|
publicKeyHandler->m_permissions = publicKeyHandler->m_permissions | PDFPublicKeySecurityHandler::PKSH_ModifyAnnotationsFillFormFields;
|
||||||
|
}
|
||||||
|
if (settings.permissions & uint32_t(PDFSecurityHandler::Permission::ModifyFormFields))
|
||||||
|
{
|
||||||
|
publicKeyHandler->m_permissions = publicKeyHandler->m_permissions | PDFPublicKeySecurityHandler::PKSH_FillFormFields;
|
||||||
|
}
|
||||||
|
if (settings.permissions & uint32_t(PDFSecurityHandler::Permission::Assemble))
|
||||||
|
{
|
||||||
|
publicKeyHandler->m_permissions = publicKeyHandler->m_permissions | PDFPublicKeySecurityHandler::PKSH_Assemble;
|
||||||
|
}
|
||||||
|
if (settings.permissions & uint32_t(PDFSecurityHandler::Permission::PrintHighResolution))
|
||||||
|
{
|
||||||
|
publicKeyHandler->m_permissions = publicKeyHandler->m_permissions | PDFPublicKeySecurityHandler::PKSH_PrintHighResolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(settings.certificateFileName);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
QByteArray password = PDFStandardOrPublicSecurityHandler::adjustPassword(settings.userPassword, 0);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
openssl_ptr<BIO> dataToBeSigned(BIO_new(BIO_s_mem()), BIO_free_all);
|
||||||
|
|
||||||
|
uint32_t permissions = qToLittleEndian(publicKeyHandler->m_permissions);
|
||||||
|
QRandomGenerator generator = QRandomGenerator::securelySeeded();
|
||||||
|
QByteArray randomKey = generateRandomByteArray(generator, 20);
|
||||||
|
BIO_write(dataToBeSigned.get(), randomKey.data(), randomKey.length());
|
||||||
|
BIO_write(dataToBeSigned.get(), &permissions, sizeof(permissions));
|
||||||
|
|
||||||
|
openssl_ptr<PKCS7> pkcs7(PKCS7_sign(certificate.get(), key.get(), certificates.get(), dataToBeSigned.get(), PKCS7_BINARY), PKCS7_free);
|
||||||
|
if (pkcs7)
|
||||||
|
{
|
||||||
|
openssl_ptr<BIO> storedData(BIO_new(BIO_s_mem()), BIO_free_all);
|
||||||
|
|
||||||
|
if (i2d_PKCS7_bio(storedData.get(), pkcs7.get()))
|
||||||
|
{
|
||||||
|
BUF_MEM* memoryBuffer = nullptr;
|
||||||
|
BIO_get_mem_ptr(storedData.get(), &memoryBuffer);
|
||||||
|
|
||||||
|
QByteArray recipient(memoryBuffer->data, int(memoryBuffer->length));
|
||||||
|
publicKeyHandler->m_filterDefault.recipients << recipient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (settings.encryptContents)
|
switch (settings.encryptContents)
|
||||||
{
|
{
|
||||||
case All:
|
case All:
|
||||||
handler->m_filterStrings = handler->m_filterDefault;
|
handler->m_filterStrings = handler->m_filterDefault;
|
||||||
handler->m_filterStreams = handler->m_filterDefault;
|
handler->m_filterStreams = handler->m_filterDefault;
|
||||||
handler->m_filterEmbeddedFiles = handler->m_filterDefault;
|
handler->m_filterEmbeddedFiles = handler->m_filterDefault;
|
||||||
handler->m_encryptMetadata = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AllExceptMetadata:
|
case AllExceptMetadata:
|
||||||
handler->m_filterStrings = handler->m_filterDefault;
|
handler->m_filterStrings = handler->m_filterDefault;
|
||||||
handler->m_filterStreams = handler->m_filterDefault;
|
handler->m_filterStreams = handler->m_filterDefault;
|
||||||
handler->m_filterEmbeddedFiles = handler->m_filterDefault;
|
handler->m_filterEmbeddedFiles = handler->m_filterDefault;
|
||||||
handler->m_encryptMetadata = false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EmbeddedFiles:
|
case EmbeddedFiles:
|
||||||
handler->m_filterStrings = identityFilter;
|
handler->m_filterStrings = identityFilter;
|
||||||
handler->m_filterStreams = identityFilter;
|
handler->m_filterStreams = identityFilter;
|
||||||
handler->m_filterEmbeddedFiles = handler->m_filterDefault;
|
handler->m_filterEmbeddedFiles = handler->m_filterDefault;
|
||||||
handler->m_encryptMetadata = false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1906,135 +2019,148 @@ PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handler->m_filterDefault.encryptMetadata = settings.encryptContents == All;
|
||||||
handler->m_cryptFilters["StdCF"] = handler->m_filterDefault;
|
handler->m_cryptFilters["StdCF"] = handler->m_filterDefault;
|
||||||
handler->m_R = getRevisionFromAlgorithm(settings.algorithm);
|
|
||||||
handler->m_permissions = settings.permissions | 0xFFFFF000;
|
|
||||||
|
|
||||||
QByteArray adjustedOwnerPassword = handler->adjustPassword(settings.ownerPassword, handler->m_R);
|
if (standardHandler)
|
||||||
QByteArray adjustedUserPassword = handler->adjustPassword(settings.userPassword, handler->m_R);
|
|
||||||
|
|
||||||
// Generate encryption entries
|
|
||||||
switch (handler->m_R)
|
|
||||||
{
|
{
|
||||||
case 2:
|
standardHandler->m_R = getRevisionFromAlgorithm(settings.algorithm);
|
||||||
case 3:
|
standardHandler->m_permissions = settings.permissions | 0xFFFFF000;
|
||||||
case 4:
|
|
||||||
|
QByteArray adjustedOwnerPassword = handler->adjustPassword(settings.ownerPassword, standardHandler->m_R);
|
||||||
|
QByteArray adjustedUserPassword = handler->adjustPassword(settings.userPassword, standardHandler->m_R);
|
||||||
|
|
||||||
|
// Generate encryption entries
|
||||||
|
switch (standardHandler->m_R)
|
||||||
{
|
{
|
||||||
// Trick for computing "O" entry for revisions 2,3,4: in O entry, there is stored
|
case 2:
|
||||||
// user password encrypted by owner password. Because RC4 cipher is symmetric, we
|
case 3:
|
||||||
// can store user password in "O" entry and then use standard function to retrieve
|
case 4:
|
||||||
// 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());
|
// 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 = standardHandler->createPaddedPassword32(adjustedUserPassword);
|
||||||
|
QByteArray paddedUserPassword;
|
||||||
|
paddedUserPassword.resize(int(paddedUserPasswordArray.size()));
|
||||||
|
std::copy(paddedUserPasswordArray.cbegin(), paddedUserPasswordArray.cend(), paddedUserPassword.data());
|
||||||
|
standardHandler->m_O = paddedUserPassword;
|
||||||
|
QByteArray entryO = standardHandler->createUserPasswordFromOwnerPassword(adjustedOwnerPassword);
|
||||||
|
standardHandler->m_O = entryO;
|
||||||
|
Q_ASSERT(standardHandler->createUserPasswordFromOwnerPassword(adjustedOwnerPassword) == paddedUserPassword);
|
||||||
|
|
||||||
|
standardHandler->m_U.resize(32);
|
||||||
|
QRandomGenerator randomNumberGenerator = QRandomGenerator::securelySeeded();
|
||||||
|
for (int i = 0; i < standardHandler->m_U.size(); ++i)
|
||||||
|
{
|
||||||
|
standardHandler->m_U[i] = char(randomNumberGenerator.generate());
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray fileEncryptionKey = standardHandler->createFileEncryptionKey(paddedUserPassword);
|
||||||
|
QByteArray U = standardHandler->createEntryValueU_r234(fileEncryptionKey);
|
||||||
|
standardHandler->m_U = U;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray fileEncryptionKey = handler->createFileEncryptionKey(paddedUserPassword);
|
case 6:
|
||||||
QByteArray U = handler->createEntryValueU_r234(fileEncryptionKey);
|
{
|
||||||
handler->m_U = U;
|
PDFStandardSecurityHandler::UserOwnerData_r6 userData;
|
||||||
|
PDFStandardSecurityHandler::UserOwnerData_r6 ownerData;
|
||||||
|
|
||||||
break;
|
QRandomGenerator randomNumberGenerator = QRandomGenerator::securelySeeded();
|
||||||
}
|
|
||||||
|
|
||||||
case 6:
|
// Generate file encryption key
|
||||||
{
|
handler->m_authorizationData.fileEncryptionKey = generateRandomByteArray(randomNumberGenerator, 32);
|
||||||
PDFStandardSecurityHandler::UserOwnerData_r6 userData;
|
handler->m_authorizationData.authorizationResult = PDFSecurityHandler::AuthorizationResult::OwnerAuthorized;
|
||||||
PDFStandardSecurityHandler::UserOwnerData_r6 ownerData;
|
|
||||||
|
|
||||||
QRandomGenerator randomNumberGenerator = QRandomGenerator::securelySeeded();
|
// Compute m_U entry
|
||||||
|
userData.keySalt = generateRandomByteArray(randomNumberGenerator, 8);
|
||||||
|
userData.validationSalt = generateRandomByteArray(randomNumberGenerator, 8);
|
||||||
|
userData.hash = standardHandler->createHash_r6(adjustedUserPassword + userData.validationSalt, adjustedUserPassword, false);
|
||||||
|
standardHandler->m_U = userData.hash + userData.validationSalt + userData.keySalt;
|
||||||
|
|
||||||
// Generate file encryption key
|
// Compute m_UE entry
|
||||||
handler->m_authorizationData.fileEncryptionKey = generateRandomByteArray(randomNumberGenerator, 32);
|
QByteArray userFileEncryptionKeyInputData = adjustedUserPassword + userData.keySalt;
|
||||||
handler->m_authorizationData.authorizationResult = PDFSecurityHandler::AuthorizationResult::OwnerAuthorized;
|
QByteArray userFileEncryptionKey = standardHandler->createHash_r6(userFileEncryptionKeyInputData, adjustedUserPassword, false);
|
||||||
|
|
||||||
// Compute m_U entry
|
Q_ASSERT(userFileEncryptionKey.size() == 32);
|
||||||
userData.keySalt = generateRandomByteArray(randomNumberGenerator, 8);
|
AES_KEY userKey = { };
|
||||||
userData.validationSalt = generateRandomByteArray(randomNumberGenerator, 8);
|
AES_set_encrypt_key(convertByteArrayToUcharPtr(userFileEncryptionKey), userFileEncryptionKey.size() * 8, &userKey);
|
||||||
userData.hash = handler->createHash_r6(adjustedUserPassword + userData.validationSalt, adjustedUserPassword, false);
|
unsigned char aesUserInitializationVector[AES_BLOCK_SIZE] = { };
|
||||||
handler->m_U = userData.hash + userData.validationSalt + userData.keySalt;
|
standardHandler->m_UE.resize(handler->m_authorizationData.fileEncryptionKey.size());
|
||||||
|
unsigned char* userInputBuffer = convertByteArrayToUcharPtr(handler->m_authorizationData.fileEncryptionKey);
|
||||||
|
unsigned char* userTargetBuffer = convertByteArrayToUcharPtr(standardHandler->m_UE);
|
||||||
|
AES_cbc_encrypt(userInputBuffer, userTargetBuffer, standardHandler->m_UE.size(), &userKey, aesUserInitializationVector, AES_ENCRYPT);
|
||||||
|
|
||||||
// Compute m_UE entry
|
// Compute m_O entry
|
||||||
QByteArray userFileEncryptionKeyInputData = adjustedUserPassword + userData.keySalt;
|
ownerData.keySalt = generateRandomByteArray(randomNumberGenerator, 8);
|
||||||
QByteArray userFileEncryptionKey = handler->createHash_r6(userFileEncryptionKeyInputData, adjustedUserPassword, false);
|
ownerData.validationSalt = generateRandomByteArray(randomNumberGenerator, 8);
|
||||||
|
ownerData.hash = standardHandler->createHash_r6(adjustedOwnerPassword + ownerData.validationSalt + standardHandler->m_U, adjustedOwnerPassword, true);
|
||||||
|
standardHandler->m_O = ownerData.hash + ownerData.validationSalt + ownerData.keySalt;
|
||||||
|
|
||||||
Q_ASSERT(userFileEncryptionKey.size() == 32);
|
// Compute m_OE entry
|
||||||
AES_KEY userKey = { };
|
QByteArray ownerFileEncryptionKeyInputData = adjustedOwnerPassword + ownerData.keySalt + standardHandler->m_U;
|
||||||
AES_set_encrypt_key(convertByteArrayToUcharPtr(userFileEncryptionKey), userFileEncryptionKey.size() * 8, &userKey);
|
QByteArray ownerFileEncryptionKey = standardHandler->createHash_r6(ownerFileEncryptionKeyInputData, adjustedOwnerPassword, true);
|
||||||
unsigned char aesUserInitializationVector[AES_BLOCK_SIZE] = { };
|
|
||||||
handler->m_UE.resize(handler->m_authorizationData.fileEncryptionKey.size());
|
|
||||||
unsigned char* userInputBuffer = convertByteArrayToUcharPtr(handler->m_authorizationData.fileEncryptionKey);
|
|
||||||
unsigned char* userTargetBuffer = convertByteArrayToUcharPtr(handler->m_UE);
|
|
||||||
AES_cbc_encrypt(userInputBuffer, userTargetBuffer, handler->m_UE.size(), &userKey, aesUserInitializationVector, AES_ENCRYPT);
|
|
||||||
|
|
||||||
// Compute m_O entry
|
AES_KEY ownerKey = { };
|
||||||
ownerData.keySalt = generateRandomByteArray(randomNumberGenerator, 8);
|
AES_set_encrypt_key(convertByteArrayToUcharPtr(ownerFileEncryptionKey), ownerFileEncryptionKey.size() * 8, &ownerKey);
|
||||||
ownerData.validationSalt = generateRandomByteArray(randomNumberGenerator, 8);
|
unsigned char aesOwnerInitializationVector[AES_BLOCK_SIZE] = { };
|
||||||
ownerData.hash = handler->createHash_r6(adjustedOwnerPassword + ownerData.validationSalt + handler->m_U, adjustedOwnerPassword, true);
|
standardHandler->m_OE.resize(handler->m_authorizationData.fileEncryptionKey.size());
|
||||||
handler->m_O = ownerData.hash + ownerData.validationSalt + ownerData.keySalt;
|
unsigned char* ownerInputBuffer = convertByteArrayToUcharPtr(handler->m_authorizationData.fileEncryptionKey);
|
||||||
|
unsigned char* ownerTargetBuffer = convertByteArrayToUcharPtr(standardHandler->m_OE);
|
||||||
|
AES_cbc_encrypt(ownerInputBuffer, ownerTargetBuffer, standardHandler->m_OE.size(), &ownerKey, aesOwnerInitializationVector, AES_ENCRYPT);
|
||||||
|
|
||||||
// Compute m_OE entry
|
// Perms entry
|
||||||
QByteArray ownerFileEncryptionKeyInputData = adjustedOwnerPassword + ownerData.keySalt + handler->m_U;
|
standardHandler->m_Perms = QByteArray(AES_BLOCK_SIZE, char(0));
|
||||||
QByteArray ownerFileEncryptionKey = handler->createHash_r6(ownerFileEncryptionKeyInputData, adjustedOwnerPassword, true);
|
unsigned char* permsData = convertByteArrayToUcharPtr(standardHandler->m_Perms);
|
||||||
|
permsData[0] = standardHandler->m_permissions & 0xFF;
|
||||||
|
permsData[1] = (standardHandler->m_permissions >> 8) & 0xFF;
|
||||||
|
permsData[2] = (standardHandler->m_permissions >> 16) & 0xFF;
|
||||||
|
permsData[3] = (standardHandler->m_permissions >> 24) & 0xFF;
|
||||||
|
permsData[4] = 0xFF;
|
||||||
|
permsData[5] = 0xFF;
|
||||||
|
permsData[6] = 0xFF;
|
||||||
|
permsData[7] = 0xFF;
|
||||||
|
permsData[8] = standardHandler->m_encryptMetadata ? 'T' : 'F';
|
||||||
|
permsData[9] = 'a';
|
||||||
|
permsData[10] = 'd';
|
||||||
|
permsData[11] = 'b';
|
||||||
|
permsData[12] = randomNumberGenerator.generate() & 0xFF;
|
||||||
|
permsData[13] = randomNumberGenerator.generate() & 0xFF;
|
||||||
|
permsData[14] = randomNumberGenerator.generate() & 0xFF;
|
||||||
|
permsData[15] = randomNumberGenerator.generate() & 0xFF;
|
||||||
|
|
||||||
AES_KEY ownerKey = { };
|
Q_ASSERT(standardHandler->m_Perms.size() == AES_BLOCK_SIZE);
|
||||||
AES_set_encrypt_key(convertByteArrayToUcharPtr(ownerFileEncryptionKey), ownerFileEncryptionKey.size() * 8, &ownerKey);
|
AES_KEY key = { };
|
||||||
unsigned char aesOwnerInitializationVector[AES_BLOCK_SIZE] = { };
|
AES_set_encrypt_key(convertByteArrayToUcharPtr(handler->m_authorizationData.fileEncryptionKey), handler->m_authorizationData.fileEncryptionKey.size() * 8, &key);
|
||||||
handler->m_OE.resize(handler->m_authorizationData.fileEncryptionKey.size());
|
AES_ecb_encrypt(convertByteArrayToUcharPtr(standardHandler->m_Perms), convertByteArrayToUcharPtr(standardHandler->m_Perms), &key, AES_ENCRYPT);
|
||||||
unsigned char* ownerInputBuffer = convertByteArrayToUcharPtr(handler->m_authorizationData.fileEncryptionKey);
|
|
||||||
unsigned char* ownerTargetBuffer = convertByteArrayToUcharPtr(handler->m_OE);
|
|
||||||
AES_cbc_encrypt(ownerInputBuffer, ownerTargetBuffer, handler->m_OE.size(), &ownerKey, aesOwnerInitializationVector, AES_ENCRYPT);
|
|
||||||
|
|
||||||
// Perms entry
|
break;
|
||||||
handler->m_Perms = QByteArray(AES_BLOCK_SIZE, char(0));
|
}
|
||||||
unsigned char* permsData = convertByteArrayToUcharPtr(handler->m_Perms);
|
|
||||||
permsData[0] = handler->m_permissions & 0xFF;
|
|
||||||
permsData[1] = (handler->m_permissions >> 8) & 0xFF;
|
|
||||||
permsData[2] = (handler->m_permissions >> 16) & 0xFF;
|
|
||||||
permsData[3] = (handler->m_permissions >> 24) & 0xFF;
|
|
||||||
permsData[4] = 0xFF;
|
|
||||||
permsData[5] = 0xFF;
|
|
||||||
permsData[6] = 0xFF;
|
|
||||||
permsData[7] = 0xFF;
|
|
||||||
permsData[8] = handler->m_encryptMetadata ? 'T' : 'F';
|
|
||||||
permsData[9] = 'a';
|
|
||||||
permsData[10] = 'd';
|
|
||||||
permsData[11] = 'b';
|
|
||||||
permsData[12] = randomNumberGenerator.generate() & 0xFF;
|
|
||||||
permsData[13] = randomNumberGenerator.generate() & 0xFF;
|
|
||||||
permsData[14] = randomNumberGenerator.generate() & 0xFF;
|
|
||||||
permsData[15] = randomNumberGenerator.generate() & 0xFF;
|
|
||||||
|
|
||||||
Q_ASSERT(handler->m_Perms.size() == AES_BLOCK_SIZE);
|
default:
|
||||||
AES_KEY key = { };
|
{
|
||||||
AES_set_encrypt_key(convertByteArrayToUcharPtr(handler->m_authorizationData.fileEncryptionKey), handler->m_authorizationData.fileEncryptionKey.size() * 8, &key);
|
Q_ASSERT(false);
|
||||||
AES_ecb_encrypt(convertByteArrayToUcharPtr(handler->m_Perms), convertByteArrayToUcharPtr(handler->m_Perms), &key, AES_ENCRYPT);
|
break;
|
||||||
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
Q_ASSERT(false);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFSecurityHandlerPointer handlerPointer(handler);
|
||||||
|
|
||||||
bool firstTry = true;
|
bool firstTry = true;
|
||||||
handler->authenticate([&settings, &firstTry](bool* b) { *b = firstTry; firstTry = false; return settings.ownerPassword; }, true);
|
const bool isPublicKeySecurity = settings.algorithm == Algorithm::Certificate;
|
||||||
Q_ASSERT(handler->getAuthorizationResult() == PDFSecurityHandler::AuthorizationResult::OwnerAuthorized);
|
auto passwordCallback = [isPublicKeySecurity, &settings, &firstTry](bool* b) { *b = firstTry; firstTry = false; return !isPublicKeySecurity ? settings.ownerPassword : settings.userPassword; };
|
||||||
return PDFSecurityHandlerPointer(handler);
|
handler->authenticate(passwordCallback, !isPublicKeySecurity);
|
||||||
|
if (handler->getAuthorizationResult() == PDFSecurityHandler::AuthorizationResult::OwnerAuthorized ||
|
||||||
|
(isPublicKeySecurity && handler->getAuthorizationResult() == PDFSecurityHandler::AuthorizationResult::UserAuthorized))
|
||||||
|
{
|
||||||
|
return handlerPointer;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PDFSecurityHandlerFactory::getPasswordOptimalEntropy()
|
int PDFSecurityHandlerFactory::getPasswordOptimalEntropy()
|
||||||
@ -2104,6 +2230,9 @@ int PDFSecurityHandlerFactory::getRevisionFromAlgorithm(Algorithm algorithm)
|
|||||||
case AES_256:
|
case AES_256:
|
||||||
return 6;
|
return 6;
|
||||||
|
|
||||||
|
case Certificate:
|
||||||
|
return 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
break;
|
break;
|
||||||
@ -2161,6 +2290,17 @@ bool PDFSecurityHandlerFactory::validate(const SecuritySettings& settings, QStri
|
|||||||
case pdf::PDFSecurityHandlerFactory::AES_256:
|
case pdf::PDFSecurityHandlerFactory::AES_256:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case pdf::PDFSecurityHandlerFactory::Certificate:
|
||||||
|
{
|
||||||
|
if (!pdf::PDFCertificateManager::isCertificateValid(settings.certificateFileName, settings.userPassword))
|
||||||
|
{
|
||||||
|
*errorMessage = tr("Invalid certificate or password.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
break;
|
break;
|
||||||
@ -2265,7 +2405,7 @@ PDFSecurityHandler::AuthorizationResult PDFPublicKeySecurityHandler::authenticat
|
|||||||
PKCS7* pkcs7 = recipientItem.get();
|
PKCS7* pkcs7 = recipientItem.get();
|
||||||
|
|
||||||
openssl_ptr<BIO> dataBuffer(BIO_new(BIO_s_mem()), BIO_free_all);
|
openssl_ptr<BIO> dataBuffer(BIO_new(BIO_s_mem()), BIO_free_all);
|
||||||
if (PKCS7_decrypt(pkcs7, keyPtr, certificatePtr, dataBuffer.get(), 0) == 1)
|
if (PKCS7_decrypt(pkcs7, keyPtr, certificatePtr, dataBuffer.get(), PKCS7_BINARY) == 1)
|
||||||
{
|
{
|
||||||
BUF_MEM* memoryBuffer = nullptr;
|
BUF_MEM* memoryBuffer = nullptr;
|
||||||
BIO_get_mem_ptr(dataBuffer.get(), &memoryBuffer);
|
BIO_get_mem_ptr(dataBuffer.get(), &memoryBuffer);
|
||||||
@ -2351,18 +2491,6 @@ bool PDFPublicKeySecurityHandler::isAllowed(Permission permission) const
|
|||||||
return m_permissions & static_cast<uint32_t>(permission);
|
return m_permissions & static_cast<uint32_t>(permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PermissionFlag : uint32_t
|
|
||||||
{
|
|
||||||
PKSH_Owner = 1 << 1,
|
|
||||||
PKSH_PrintLowResolution = 1 << 2,
|
|
||||||
PKSH_Modify = 1 << 3,
|
|
||||||
PKSH_CopyContent = 1 << 4,
|
|
||||||
PKSH_ModifyAnnotationsFillFormFields = 1 << 5,
|
|
||||||
PKSH_FillFormFields = 1 << 8,
|
|
||||||
PKSH_Assemble = 1 << 10,
|
|
||||||
PKSH_PrintHighResolution = 1 << 11
|
|
||||||
};
|
|
||||||
|
|
||||||
if (m_permissions & PKSH_Owner)
|
if (m_permissions & PKSH_Owner)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
@ -201,6 +201,8 @@ public:
|
|||||||
static PDFSecurityHandlerPointer createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id);
|
static PDFSecurityHandlerPointer createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend class PDFSecurityHandlerFactory;
|
||||||
|
|
||||||
static bool parseBool(const PDFDictionary* dictionary, const char* key, bool required, bool defaultValue = true);
|
static bool parseBool(const PDFDictionary* dictionary, const char* key, bool required, bool defaultValue = true);
|
||||||
static QByteArray parseName(const PDFDictionary* dictionary, const char* key, bool required, const char* defaultValue = nullptr);
|
static QByteArray parseName(const PDFDictionary* dictionary, const char* key, bool required, const char* defaultValue = nullptr);
|
||||||
static PDFInteger parseInt(const PDFDictionary* dictionary, const char* key, bool required, PDFInteger defaultValue = -1);
|
static PDFInteger parseInt(const PDFDictionary* dictionary, const char* key, bool required, PDFInteger defaultValue = -1);
|
||||||
@ -278,6 +280,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend class PDFSecurityHandlerFactory;
|
||||||
|
|
||||||
/// Decrypts data using specified filter. This function can be called only, if authorization was successfull.
|
/// Decrypts data using specified filter. This function can be called only, if authorization was successfull.
|
||||||
/// \param data Data to be decrypted
|
/// \param data Data to be decrypted
|
||||||
/// \param filter Filter to be used for decryption
|
/// \param filter Filter to be used for decryption
|
||||||
@ -421,6 +425,18 @@ private:
|
|||||||
PKCS7_S5
|
PKCS7_S5
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PermissionFlag : uint32_t
|
||||||
|
{
|
||||||
|
PKSH_Owner = 1 << 1,
|
||||||
|
PKSH_PrintLowResolution = 1 << 2,
|
||||||
|
PKSH_Modify = 1 << 3,
|
||||||
|
PKSH_CopyContent = 1 << 4,
|
||||||
|
PKSH_ModifyAnnotationsFillFormFields = 1 << 5,
|
||||||
|
PKSH_FillFormFields = 1 << 8,
|
||||||
|
PKSH_Assemble = 1 << 10,
|
||||||
|
PKSH_PrintHighResolution = 1 << 11
|
||||||
|
};
|
||||||
|
|
||||||
/// What operations shall be permitted, when document is opened with user access.
|
/// What operations shall be permitted, when document is opened with user access.
|
||||||
uint32_t m_permissions = 0;
|
uint32_t m_permissions = 0;
|
||||||
|
|
||||||
@ -440,7 +456,8 @@ public:
|
|||||||
None,
|
None,
|
||||||
RC4,
|
RC4,
|
||||||
AES_128,
|
AES_128,
|
||||||
AES_256
|
AES_256,
|
||||||
|
Certificate
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EncryptContents
|
enum EncryptContents
|
||||||
@ -458,6 +475,7 @@ public:
|
|||||||
QString ownerPassword;
|
QString ownerPassword;
|
||||||
uint32_t permissions = 0;
|
uint32_t permissions = 0;
|
||||||
QByteArray id;
|
QByteArray id;
|
||||||
|
QString certificateFileName;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates security handler based on given settings. If security handler cannot
|
/// Creates security handler based on given settings. If security handler cannot
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "pdfutils.h"
|
#include "pdfutils.h"
|
||||||
#include "pdfwidgetutils.h"
|
#include "pdfwidgetutils.h"
|
||||||
#include "pdfsecurityhandler.h"
|
#include "pdfsecurityhandler.h"
|
||||||
|
#include "pdfcertificatemanager.h"
|
||||||
#include "pdfdbgheap.h"
|
#include "pdfdbgheap.h"
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
@ -40,6 +41,7 @@ PDFEncryptionSettingsDialog::PDFEncryptionSettingsDialog(QByteArray documentId,
|
|||||||
ui->algorithmComboBox->addItem(tr("RC4 128-bit | R4"), int(pdf::PDFSecurityHandlerFactory::RC4));
|
ui->algorithmComboBox->addItem(tr("RC4 128-bit | R4"), int(pdf::PDFSecurityHandlerFactory::RC4));
|
||||||
ui->algorithmComboBox->addItem(tr("AES 128-bit | R4"), int(pdf::PDFSecurityHandlerFactory::AES_128));
|
ui->algorithmComboBox->addItem(tr("AES 128-bit | R4"), int(pdf::PDFSecurityHandlerFactory::AES_128));
|
||||||
ui->algorithmComboBox->addItem(tr("AES 256-bit | R6"), int(pdf::PDFSecurityHandlerFactory::AES_256));
|
ui->algorithmComboBox->addItem(tr("AES 256-bit | R6"), int(pdf::PDFSecurityHandlerFactory::AES_256));
|
||||||
|
ui->algorithmComboBox->addItem(tr("Certificate Encryption"), int(pdf::PDFSecurityHandlerFactory::Certificate));
|
||||||
|
|
||||||
ui->algorithmComboBox->setCurrentIndex(0);
|
ui->algorithmComboBox->setCurrentIndex(0);
|
||||||
|
|
||||||
@ -73,6 +75,7 @@ PDFEncryptionSettingsDialog::PDFEncryptionSettingsDialog(QByteArray documentId,
|
|||||||
m_checkBoxToPermission[ui->permAssembleCheckBox] = pdf::PDFSecurityHandler::Permission::Assemble;
|
m_checkBoxToPermission[ui->permAssembleCheckBox] = pdf::PDFSecurityHandler::Permission::Assemble;
|
||||||
m_checkBoxToPermission[ui->permPrintHighResolutionCheckBox] = pdf::PDFSecurityHandler::Permission::PrintHighResolution;
|
m_checkBoxToPermission[ui->permPrintHighResolutionCheckBox] = pdf::PDFSecurityHandler::Permission::PrintHighResolution;
|
||||||
|
|
||||||
|
updateCertificates();
|
||||||
updateUi();
|
updateUi();
|
||||||
updatePasswordScore();
|
updatePasswordScore();
|
||||||
|
|
||||||
@ -95,6 +98,7 @@ void PDFEncryptionSettingsDialog::updateUi()
|
|||||||
|
|
||||||
const pdf::PDFSecurityHandlerFactory::Algorithm algorithm = static_cast<const pdf::PDFSecurityHandlerFactory::Algorithm>(ui->algorithmComboBox->currentData().toInt());
|
const pdf::PDFSecurityHandlerFactory::Algorithm algorithm = static_cast<const pdf::PDFSecurityHandlerFactory::Algorithm>(ui->algorithmComboBox->currentData().toInt());
|
||||||
const bool encrypted = algorithm != pdf::PDFSecurityHandlerFactory::None;
|
const bool encrypted = algorithm != pdf::PDFSecurityHandlerFactory::None;
|
||||||
|
const bool isEncryptedUsingCertificate = algorithm == pdf::PDFSecurityHandlerFactory::Certificate;
|
||||||
|
|
||||||
switch (algorithm)
|
switch (algorithm)
|
||||||
{
|
{
|
||||||
@ -108,6 +112,7 @@ void PDFEncryptionSettingsDialog::updateUi()
|
|||||||
ui->algorithmHintWidget->setCurrentValue(4);
|
ui->algorithmHintWidget->setCurrentValue(4);
|
||||||
break;
|
break;
|
||||||
case pdf::PDFSecurityHandlerFactory::AES_256:
|
case pdf::PDFSecurityHandlerFactory::AES_256:
|
||||||
|
case pdf::PDFSecurityHandlerFactory::Certificate:
|
||||||
ui->algorithmHintWidget->setCurrentValue(5);
|
ui->algorithmHintWidget->setCurrentValue(5);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -116,20 +121,40 @@ void PDFEncryptionSettingsDialog::updateUi()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->userPasswordEnableCheckBox->setEnabled(encrypted);
|
ui->certificateComboBox->setEnabled(isEncryptedUsingCertificate);
|
||||||
ui->ownerPasswordEnableCheckBox->setEnabled(false);
|
|
||||||
|
|
||||||
if (!encrypted)
|
if (!isEncryptedUsingCertificate)
|
||||||
{
|
{
|
||||||
ui->userPasswordEnableCheckBox->setChecked(false);
|
ui->userPasswordEnableCheckBox->setEnabled(encrypted);
|
||||||
ui->ownerPasswordEnableCheckBox->setChecked(false);
|
ui->ownerPasswordEnableCheckBox->setEnabled(false);
|
||||||
|
|
||||||
ui->userPasswordEdit->clear();
|
if (!encrypted)
|
||||||
ui->ownerPasswordEdit->clear();
|
{
|
||||||
|
ui->userPasswordEnableCheckBox->setChecked(false);
|
||||||
|
ui->ownerPasswordEnableCheckBox->setChecked(false);
|
||||||
|
|
||||||
|
ui->userPasswordEdit->clear();
|
||||||
|
ui->ownerPasswordEdit->clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->ownerPasswordEnableCheckBox->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->certificateComboBox->setCurrentIndex(-1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ui->ownerPasswordEnableCheckBox->setChecked(true);
|
ui->userPasswordEnableCheckBox->setEnabled(false);
|
||||||
|
ui->ownerPasswordEnableCheckBox->setEnabled(false);
|
||||||
|
|
||||||
|
ui->userPasswordEnableCheckBox->setChecked(true);
|
||||||
|
ui->ownerPasswordEnableCheckBox->setChecked(false);
|
||||||
|
|
||||||
|
if (ui->certificateComboBox->currentIndex() == -1 && ui->certificateComboBox->count() > 0)
|
||||||
|
{
|
||||||
|
ui->certificateComboBox->setCurrentIndex(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->userPasswordEdit->setEnabled(ui->userPasswordEnableCheckBox->isChecked());
|
ui->userPasswordEdit->setEnabled(ui->userPasswordEnableCheckBox->isChecked());
|
||||||
@ -158,6 +183,21 @@ void PDFEncryptionSettingsDialog::updateUi()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFEncryptionSettingsDialog::updateCertificates()
|
||||||
|
{
|
||||||
|
QFileInfoList certificates = pdf::PDFCertificateManager::getCertificates();
|
||||||
|
|
||||||
|
QVariant currentCertificate = ui->certificateComboBox->currentData();
|
||||||
|
|
||||||
|
ui->certificateComboBox->clear();
|
||||||
|
for (const QFileInfo& certificateItem : certificates)
|
||||||
|
{
|
||||||
|
ui->certificateComboBox->addItem(certificateItem.fileName(), certificateItem.absoluteFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->certificateComboBox->setCurrentIndex(ui->certificateComboBox->findData(currentCertificate));
|
||||||
|
}
|
||||||
|
|
||||||
void PDFEncryptionSettingsDialog::updatePasswordScore()
|
void PDFEncryptionSettingsDialog::updatePasswordScore()
|
||||||
{
|
{
|
||||||
const pdf::PDFSecurityHandlerFactory::Algorithm algorithm = static_cast<const pdf::PDFSecurityHandlerFactory::Algorithm>(ui->algorithmComboBox->currentData().toInt());
|
const pdf::PDFSecurityHandlerFactory::Algorithm algorithm = static_cast<const pdf::PDFSecurityHandlerFactory::Algorithm>(ui->algorithmComboBox->currentData().toInt());
|
||||||
@ -188,6 +228,7 @@ void PDFEncryptionSettingsDialog::accept()
|
|||||||
settings.userPassword = ui->userPasswordEdit->text();
|
settings.userPassword = ui->userPasswordEdit->text();
|
||||||
settings.ownerPassword = ui->ownerPasswordEdit->text();
|
settings.ownerPassword = ui->ownerPasswordEdit->text();
|
||||||
settings.permissions = 0;
|
settings.permissions = 0;
|
||||||
|
settings.certificateFileName = ui->certificateComboBox->currentData().toString();
|
||||||
|
|
||||||
for (auto item : m_checkBoxToPermission)
|
for (auto item : m_checkBoxToPermission)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +50,7 @@ private:
|
|||||||
Ui::PDFEncryptionSettingsDialog* ui;
|
Ui::PDFEncryptionSettingsDialog* ui;
|
||||||
|
|
||||||
void updateUi();
|
void updateUi();
|
||||||
|
void updateCertificates();
|
||||||
void updatePasswordScore();
|
void updatePasswordScore();
|
||||||
|
|
||||||
bool m_isUpdatingUi;
|
bool m_isUpdatingUi;
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>705</width>
|
<width>843</width>
|
||||||
<height>609</height>
|
<height>620</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@ -20,8 +20,8 @@
|
|||||||
<string>Encryption Method</string>
|
<string>Encryption Method</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="methodGroupBoxLayout">
|
<layout class="QGridLayout" name="methodGroupBoxLayout">
|
||||||
<item row="0" column="1">
|
<item row="0" column="2">
|
||||||
<widget class="QComboBox" name="algorithmComboBox"/>
|
<widget class="pdfviewer::PDFEncryptionStrengthHintWidget" name="algorithmHintWidget" native="true"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="encryptionAlgorithm">
|
<widget class="QLabel" name="encryptionAlgorithm">
|
||||||
@ -30,19 +30,29 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="2">
|
<item row="0" column="1">
|
||||||
<widget class="pdfviewer::PDFEncryptionStrengthHintWidget" name="algorithmHintWidget" native="true"/>
|
<widget class="QComboBox" name="algorithmComboBox"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0" colspan="3">
|
<item row="2" column="0" colspan="3">
|
||||||
<widget class="QLabel" name="encryptionMethodHintLabel">
|
<widget class="QLabel" name="encryptionMethodHintLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><html><head/><body><p>Select encryption algorithm. AES-256 is strongly recommended, because older encryption algorithm can be potentially broken. Select older algorithms (as AES-128 or RC4) only, if you need backward compatibility. Also, choose a strong password to ensure strong encryption.</p></body></html></string>
|
<string><html><head/><body><p>Select encryption algorithm. AES-256 is strongly recommended, because older encryption algorithm can be potentially broken. Select older algorithms (as AES-128 or RC4) only, if you need backward compatibility. Also, choose a strong password to ensure strong encryption.</p><p>Public key security using certificate is also supported. In that case, you must select a certificate with private key, and this certificate is then used to encrypt data. User, which wants to open document encrypted with certificate, must have a private key to the certificae.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="certificateLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Certificate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="certificateComboBox"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -1202,6 +1202,12 @@ void PDFProgramController::onActionEncryptionTriggered()
|
|||||||
{
|
{
|
||||||
pdf::PDFSecurityHandlerPointer updatedSecurityHandler = dialog.getUpdatedSecurityHandler();
|
pdf::PDFSecurityHandlerPointer updatedSecurityHandler = dialog.getUpdatedSecurityHandler();
|
||||||
|
|
||||||
|
if (!updatedSecurityHandler)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(m_mainWindow, QApplication::applicationDisplayName(), tr("Failed to create security handler."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Jakub Melka: If we changed encryption (password), recheck, that user doesn't
|
// Jakub Melka: If we changed encryption (password), recheck, that user doesn't
|
||||||
// forgot (or accidentally entered wrong) password. So, we require owner authentization
|
// forgot (or accidentally entered wrong) password. So, we require owner authentization
|
||||||
// to continue.
|
// to continue.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user