mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Encryption settings dialog, authorization as owner
This commit is contained in:
@@ -449,11 +449,6 @@ public:
|
||||
/// header.
|
||||
QByteArray getVersion() const;
|
||||
|
||||
private:
|
||||
friend class PDFDocumentReader;
|
||||
friend class PDFDocumentBuilder;
|
||||
friend class PDFOptimizer;
|
||||
|
||||
explicit PDFDocument(PDFObjectStorage&& storage, PDFVersion version) :
|
||||
m_pdfObjectStorage(std::move(storage))
|
||||
{
|
||||
@@ -462,6 +457,11 @@ private:
|
||||
m_info.version = version;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class PDFDocumentReader;
|
||||
friend class PDFDocumentBuilder;
|
||||
friend class PDFOptimizer;
|
||||
|
||||
/// Initialize data based on object in the storage.
|
||||
/// Can throw exception if error is detected.
|
||||
void init();
|
||||
|
@@ -508,6 +508,11 @@ PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObj
|
||||
return PDFSecurityHandlerPointer(new PDFStandardSecurityHandler(qMove(handler)));
|
||||
}
|
||||
|
||||
PDFSecurityHandler* PDFStandardSecurityHandler::clone() const
|
||||
{
|
||||
return new PDFStandardSecurityHandler(*this);
|
||||
}
|
||||
|
||||
PDFSecurityHandler::AuthorizationResult PDFStandardSecurityHandler::authenticate(const std::function<QString(bool*)>& getPasswordCallback, bool authorizeOwnerOnly)
|
||||
{
|
||||
QByteArray password;
|
||||
@@ -664,7 +669,7 @@ PDFSecurityHandler::AuthorizationResult PDFStandardSecurityHandler::authenticate
|
||||
return AuthorizationResult::Failed;
|
||||
}
|
||||
|
||||
password = adjustPassword(getPasswordCallback(&passwordObtained));
|
||||
password = adjustPassword(getPasswordCallback(&passwordObtained), m_R);
|
||||
}
|
||||
|
||||
return AuthorizationResult::Cancelled;
|
||||
@@ -1375,11 +1380,11 @@ PDFStandardSecurityHandler::UserOwnerData_r6 PDFStandardSecurityHandler::parsePa
|
||||
return result;
|
||||
}
|
||||
|
||||
QByteArray PDFStandardSecurityHandler::adjustPassword(const QString& password)
|
||||
QByteArray PDFStandardSecurityHandler::adjustPassword(const QString& password, int revision)
|
||||
{
|
||||
QByteArray result;
|
||||
|
||||
switch (m_R)
|
||||
switch (revision)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
@@ -1486,4 +1491,84 @@ bool PDFStandardSecurityHandler::isUnicodeMappedToNothing(ushort unicode)
|
||||
}
|
||||
}
|
||||
|
||||
PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const PDFSecurityHandlerFactory::SecuritySettings& settings)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int PDFSecurityHandlerFactory::getPasswordOptimalEntropy()
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
|
||||
int PDFSecurityHandlerFactory::getPasswordEntropy(const QString& password, Algorithm algorithm)
|
||||
{
|
||||
if (algorithm == None)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
QByteArray adjustedPassword = PDFStandardSecurityHandler::adjustPassword(password, getRevisionFromAlgorithm(algorithm));
|
||||
|
||||
if (adjustedPassword.isEmpty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int length = adjustedPassword.length();
|
||||
std::sort(adjustedPassword.begin(), adjustedPassword.end());
|
||||
|
||||
int charCount = 0;
|
||||
char lastChar = adjustedPassword.front();
|
||||
PDFReal entropy = 0.0;
|
||||
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
const char currentChar = adjustedPassword[i];
|
||||
|
||||
if (currentChar == lastChar)
|
||||
{
|
||||
++charCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
const PDFReal probability = PDFReal(charCount) / PDFReal(length);
|
||||
entropy += -probability * std::log2(probability);
|
||||
|
||||
charCount = 1;
|
||||
lastChar = currentChar;
|
||||
}
|
||||
}
|
||||
|
||||
// Jakub Melka: last character
|
||||
const PDFReal probability = PDFReal(charCount) / PDFReal(length);
|
||||
entropy += -probability * std::log2(probability);
|
||||
|
||||
return entropy * length;
|
||||
}
|
||||
|
||||
int PDFSecurityHandlerFactory::getRevisionFromAlgorithm(Algorithm algorithm)
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case None:
|
||||
return 0;
|
||||
|
||||
case RC4:
|
||||
return 3;
|
||||
|
||||
case AES_128:
|
||||
return 4;
|
||||
|
||||
case AES_256:
|
||||
return 6;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
@@ -109,6 +109,9 @@ public:
|
||||
/// Retrieve encryption mode (none/standard encryption/custom)
|
||||
virtual EncryptionMode getMode() const = 0;
|
||||
|
||||
/// Creates a clone of this object
|
||||
virtual PDFSecurityHandler* clone() const = 0;
|
||||
|
||||
/// Performs authentication of the document content access. First, algorithm should check,
|
||||
/// if empty password allows document access (so, for example, only owner password is provided).
|
||||
/// If this fails, function \p getPasswordCallback is called to retrieve user entered password.
|
||||
@@ -214,6 +217,7 @@ class PDFNoneSecurityHandler : public PDFSecurityHandler
|
||||
{
|
||||
public:
|
||||
virtual EncryptionMode getMode() const override { return EncryptionMode::None; }
|
||||
virtual PDFSecurityHandler* clone() const override { return new PDFNoneSecurityHandler(); }
|
||||
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 decryptByFilter(const QByteArray& data, const QByteArray&, PDFObjectReference) const override { return data; }
|
||||
@@ -231,6 +235,7 @@ class PDFStandardSecurityHandler : public PDFSecurityHandler
|
||||
{
|
||||
public:
|
||||
virtual EncryptionMode getMode() const override { return EncryptionMode::Standard; }
|
||||
virtual PDFSecurityHandler* clone() const 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 decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const override;
|
||||
@@ -249,6 +254,9 @@ public:
|
||||
QByteArray fileEncryptionKey;
|
||||
};
|
||||
|
||||
/// Adjusts the password according to the PDF specification
|
||||
static QByteArray adjustPassword(const QString& password, int revision);
|
||||
|
||||
private:
|
||||
friend PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id);
|
||||
|
||||
@@ -288,8 +296,6 @@ private:
|
||||
/// Parses parts of the user/owner data (U/O values of the encryption dictionary)
|
||||
UserOwnerData_r6 parseParts(const QByteArray& data) const;
|
||||
|
||||
/// Adjusts the password according to the PDF specification
|
||||
QByteArray adjustPassword(const QString& password);
|
||||
|
||||
/// Decrypts data using specified filter. This function can be called only, if authorization was successfull.
|
||||
/// \param data Data to be decrypted
|
||||
@@ -356,6 +362,57 @@ private:
|
||||
AuthorizationData m_authorizationData;
|
||||
};
|
||||
|
||||
/// Factory, which creates security handler based on settings.
|
||||
class Pdf4QtLIBSHARED_EXPORT PDFSecurityHandlerFactory
|
||||
{
|
||||
public:
|
||||
|
||||
enum Algorithm
|
||||
{
|
||||
None,
|
||||
RC4,
|
||||
AES_128,
|
||||
AES_256
|
||||
};
|
||||
|
||||
enum EncryptContents
|
||||
{
|
||||
All,
|
||||
AllExceptMetadata,
|
||||
EmbeddedFiles
|
||||
};
|
||||
|
||||
struct SecuritySettings
|
||||
{
|
||||
Algorithm algorithm = None;
|
||||
EncryptContents encryptContents = All;
|
||||
QString userPassword;
|
||||
QString ownerPassword;
|
||||
uint32_t permissions = 0;
|
||||
};
|
||||
|
||||
/// Creates security handler based on given settings. If security handler cannot
|
||||
/// be created, then nullptr is returned.
|
||||
/// \param settings Security handler settings
|
||||
static PDFSecurityHandlerPointer createSecurityHandler(const SecuritySettings& settings);
|
||||
|
||||
/// Returns optimal number of bits (entropy) for strong password
|
||||
static int getPasswordOptimalEntropy();
|
||||
|
||||
/// Calculates password entropy (number of bits), can be used
|
||||
/// for ranking the password security. Encryption algorithm must be also
|
||||
/// considered, because password is adjusted according to the specification
|
||||
/// before it's entropy is being computed.
|
||||
/// \param password Password to be scored
|
||||
/// \param algorithm Encryption algorithm
|
||||
static int getPasswordEntropy(const QString& password, Algorithm algorithm);
|
||||
|
||||
/// Returns revision number of standard security handler for a given
|
||||
/// algorithm. If algorithm is invalid or None, zero is returned.
|
||||
/// \param algorithm Algorithm
|
||||
static int getRevisionFromAlgorithm(Algorithm algorithm);
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user