Encryption tool

This commit is contained in:
Jakub Melka
2021-06-01 16:09:00 +02:00
parent 453a3a24c7
commit c22cba2f50
12 changed files with 320 additions and 13 deletions

View File

@@ -495,7 +495,7 @@ PDFObjectFactory& PDFObjectFactory::operator<<(WrapEmptyArray)
PDFObject PDFObjectFactory::createTextString(QString textString)
{
if (!PDFEncoding::canConvertToEncoding(textString, PDFEncoding::Encoding::PDFDoc))
if (!PDFEncoding::canConvertToEncoding(textString, PDFEncoding::Encoding::PDFDoc, nullptr))
{
// Use unicode encoding
QByteArray ba;

View File

@@ -2132,7 +2132,7 @@ QString PDFEncoding::convert(const QByteArray& stream, PDFEncoding::Encoding enc
return result;
}
QByteArray PDFEncoding::convertToEncoding(const QString& string, PDFEncoding::Encoding encoding)
QByteArray PDFEncoding::convertToEncoding(const QString& string, Encoding encoding)
{
QByteArray result;
@@ -2160,11 +2160,12 @@ QByteArray PDFEncoding::convertToEncoding(const QString& string, PDFEncoding::En
return result;
}
bool PDFEncoding::canConvertToEncoding(const QString& string, PDFEncoding::Encoding encoding)
bool PDFEncoding::canConvertToEncoding(const QString& string, Encoding encoding, QString* invalidCharacters)
{
const encoding::EncodingTable* table = getTableForEncoding(encoding);
Q_ASSERT(table);
bool isConvertible = true;
for (QChar character : string)
{
ushort unicode = character.unicode();
@@ -2181,14 +2182,23 @@ bool PDFEncoding::canConvertToEncoding(const QString& string, PDFEncoding::Encod
if (!converted)
{
return false;
isConvertible = false;
if (!invalidCharacters)
{
// We are not storing invalid characters - we can break on first not convertible
// character.
break;
}
*invalidCharacters += character;
}
}
return true;
return isConvertible;
}
bool PDFEncoding::canConvertFromEncoding(const QByteArray& stream, PDFEncoding::Encoding encoding)
bool PDFEncoding::canConvertFromEncoding(const QByteArray& stream, Encoding encoding)
{
const encoding::EncodingTable* table = getTableForEncoding(encoding);
for (const unsigned char index : stream)
@@ -2403,6 +2413,24 @@ QString PDFEncoding::convertSmartFromByteStringToUnicode(const QByteArray& strea
return QString::fromLatin1(stream.toHex()).toUpper();
}
QString PDFEncoding::getEncodingCharacters(Encoding encoding)
{
QString string;
if (const encoding::EncodingTable* table = getTableForEncoding(encoding))
{
for (const QChar& character : *table)
{
if (character != QChar(0xFFFD))
{
string += character;
}
}
}
return string;
}
bool PDFEncoding::hasUnicodeLeadMarkings(const QByteArray& stream)
{
if (stream.size() >= 2)

View File

@@ -75,7 +75,8 @@ public:
/// are also present in given encoding).
/// \param string String to be tested
/// \param encoding Encoding used in verification of conversion
static bool canConvertToEncoding(const QString& string, Encoding encoding);
/// \param[out] invalidCharacters Storage, where not convertible characters are inserted
static bool canConvertToEncoding(const QString& string, Encoding encoding, QString* invalidCharacters);
/// Checks, if stream can be converted to string using encoding (i.e. all
/// characters are defined). If all characters are valid, then true is
@@ -120,6 +121,11 @@ public:
/// \returns Unicode string or string converted to hexadecimal representation
static QString convertSmartFromByteStringToUnicode(const QByteArray& stream, bool* isBinary);
/// Returns all characters of the given encoding
/// \param encoding Encoding
/// \returns All characters reprezentable by encoding.
static QString getEncodingCharacters(Encoding encoding);
private:
/// Returns true, if byte array has UTF-16BE/LE unicode marking bytes at the
/// stream start. If they are present, then byte stream is probably encoded

View File

@@ -191,19 +191,26 @@ void PDFDecryptOrEncryptObjectVisitor::visitStream(const PDFStream* stream)
QByteArray processedData;
if (!processedDictionary.hasKey("Crypt"))
{
// Is it an embedded file?
const PDFObject& object = processedDictionary.get("Type");
const bool isEmbeddedFile = object.isName() && object.getString() == "EmbeddedFile";
const PDFSecurityHandler::EncryptionScope scope = !isEmbeddedFile ? PDFSecurityHandler::EncryptionScope::Stream : PDFSecurityHandler::EncryptionScope::EmbeddedFile;
switch (m_mode)
{
case pdf::PDFDecryptOrEncryptObjectVisitor::Mode::Decrypt:
processedData = m_securityHandler->decrypt(*stream->getContent(), m_reference, PDFSecurityHandler::EncryptionScope::Stream);
processedData = m_securityHandler->decrypt(*stream->getContent(), m_reference, scope);
break;
case pdf::PDFDecryptOrEncryptObjectVisitor::Mode::Encrypt:
processedData = m_securityHandler->encrypt(*stream->getContent(), m_reference, PDFSecurityHandler::EncryptionScope::Stream);
processedData = m_securityHandler->encrypt(*stream->getContent(), m_reference, scope);
break;
default:
Q_ASSERT(false);
break;
}
processedDictionary.setEntry(PDFInplaceOrMemoryString("Length"), PDFObject::createInteger(processedData.size()));
}
else
{
@@ -212,8 +219,7 @@ void PDFDecryptOrEncryptObjectVisitor::visitStream(const PDFStream* stream)
case pdf::PDFDecryptOrEncryptObjectVisitor::Mode::Decrypt:
{
processedData = *stream->getContent();
processedDictionary.removeEntry(PDFSecurityHandler::OBJECT_REFERENCE_DICTIONARY_NAME);
processedDictionary.addEntry(PDFInplaceOrMemoryString(PDFSecurityHandler::OBJECT_REFERENCE_DICTIONARY_NAME), PDFObject::createReference(m_reference));
processedDictionary.setEntry(PDFInplaceOrMemoryString(PDFSecurityHandler::OBJECT_REFERENCE_DICTIONARY_NAME), PDFObject::createReference(m_reference));
break;
}
@@ -1991,4 +1997,48 @@ QByteArray PDFSecurityHandlerFactory::generateRandomByteArray(QRandomGenerator&
return ba;
}
bool PDFSecurityHandlerFactory::validate(const SecuritySettings& settings, QString* errorMessage)
{
switch (settings.algorithm)
{
case pdf::PDFSecurityHandlerFactory::RC4:
case pdf::PDFSecurityHandlerFactory::AES_128:
{
QString invalidCharacters;
if (!PDFEncoding::canConvertToEncoding(settings.userPassword, PDFEncoding::Encoding::PDFDoc, &invalidCharacters))
{
if (errorMessage)
{
Q_ASSERT(!invalidCharacters.isEmpty());
*errorMessage = tr("User password contains invalid characters: %1.").arg(invalidCharacters);
}
return false;
}
if (!PDFEncoding::canConvertToEncoding(settings.ownerPassword, PDFEncoding::Encoding::PDFDoc, &invalidCharacters))
{
if (errorMessage)
{
Q_ASSERT(!invalidCharacters.isEmpty());
*errorMessage = tr("Owner password contains invalid characters: %1.").arg(invalidCharacters);
}
return false;
}
break;
}
case pdf::PDFSecurityHandlerFactory::None:
case pdf::PDFSecurityHandlerFactory::AES_256:
break;
default:
Q_ASSERT(false);
break;
}
return true;
}
} // namespace pdf

View File

@@ -380,6 +380,8 @@ private:
/// Factory, which creates security handler based on settings.
class Pdf4QtLIBSHARED_EXPORT PDFSecurityHandlerFactory
{
Q_DECLARE_TR_FUNCTIONS(pdf::PDFSecurityHandlerFactory)
public:
enum Algorithm
@@ -432,6 +434,11 @@ public:
/// \param generator Random number generator
/// \param size Target size
static QByteArray generateRandomByteArray(QRandomGenerator& generator, int size);
/// Validates security settings
/// \param settings Settings
/// \param[out] errorMessage Error message
static bool validate(const SecuritySettings& settings, QString* errorMessage);
};
} // namespace pdf