summaryrefslogtreecommitdiff
path: root/vcl/source
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source')
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx88
-rw-r--r--vcl/source/pdf/PDFEncryptionInitialization.cxx1
-rw-r--r--vcl/source/pdf/PDFEncryptorR6.cxx127
3 files changed, 188 insertions, 28 deletions
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index aa841973df17..56311e7f2791 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -96,7 +96,7 @@
#include <pdf/objectcopier.hxx>
#include <pdf/pdfwriter_impl.hxx>
#include <pdf/PdfConfig.hxx>
-#include <pdf/IPDFEncryptor.hxx>
+#include <pdf/PDFEncryptorR6.hxx>
#include <pdf/PDFEncryptor.hxx>
#include <o3tl/sorted_vector.hxx>
#include <frozen/bits/defines.h>
@@ -143,6 +143,12 @@ void appendHex(sal_Int8 nInt, OStringBuffer& rBuffer)
rBuffer.append( pHexDigits[ nInt & 15 ] );
}
+void appendHexArray(sal_uInt8* pArray, size_t nSize, OStringBuffer& rBuffer)
+{
+ for (size_t i = 0; i < nSize; i++)
+ appendHex(pArray[i], rBuffer);
+}
+
void appendName( std::u16string_view rStr, OStringBuffer& rBuffer )
{
// FIXME i59651 add a check for max length of 127 chars? Per PDF spec 1.4, appendix C.1
@@ -1459,7 +1465,10 @@ PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext,
if (xEncryptionMaterialHolder.is())
{
- m_pPDFEncryptor.reset(new PDFEncryptor);
+ if (m_aContext.Version == PDFWriter::PDFVersion::PDF_2_0 || m_aContext.Version == PDFWriter::PDFVersion::PDF_A_4)
+ m_pPDFEncryptor.reset(new PDFEncryptorR6);
+ else
+ m_pPDFEncryptor.reset(new PDFEncryptor);
m_pPDFEncryptor->prepareEncryption(xEncryptionMaterialHolder, m_aContext.Encryption);
}
@@ -1618,10 +1627,10 @@ inline void PDFWriterImpl::appendUnicodeTextStringEncrypt( const OUString& rInSt
*pCopy++ = static_cast<sal_uInt8>( aUnChar & 255 );
}
//encrypt in place
- m_pPDFEncryptor->encrypt(m_vEncryptionBuffer.data(), nChars, m_vEncryptionBuffer, nChars);
+ std::vector<sal_uInt8> aNewBuffer(nChars);
+ m_pPDFEncryptor->encrypt(m_vEncryptionBuffer.data(), nChars, aNewBuffer, nChars);
//now append, hexadecimal (appendHex), the encrypted result
- for(int i = 0; i < nChars; i++)
- appendHex( m_vEncryptionBuffer[i], rOutBuffer );
+ appendHexArray(aNewBuffer.data(), aNewBuffer.size(), rOutBuffer);
}
else
PDFWriter::AppendUnicodeTextString(rInString, rOutBuffer);
@@ -1639,7 +1648,7 @@ inline void PDFWriterImpl::appendLiteralStringEncrypt( std::string_view rInStrin
//encrypt the string in a buffer, then append it
enableStringEncryption(nInObjectNumber);
m_pPDFEncryptor->encrypt(rInString.data(), nChars, m_vEncryptionBuffer, nChars);
- appendLiteralString( reinterpret_cast<char*>(m_vEncryptionBuffer.data()), nChars, rOutBuffer );
+ appendLiteralString(reinterpret_cast<char*>(m_vEncryptionBuffer.data()), m_vEncryptionBuffer.size(), rOutBuffer);
}
else
appendLiteralString( rInString.data(), nChars , rOutBuffer );
@@ -1738,34 +1747,42 @@ bool PDFWriterImpl::writeBufferBytes( const void* pBuffer, sal_uInt64 nBytes )
}
sal_uInt64 nWritten;
- if( m_pCodec )
+ sal_uInt64 nActualSize = nBytes;
+
+ // we are compressing the stream
+ if (m_pCodec)
{
m_pCodec->Write( *m_pMemStream, static_cast<const sal_uInt8*>(pBuffer), static_cast<sal_uLong>(nBytes) );
nWritten = nBytes;
}
else
{
+ // is it encrypted?
bool bStreamEncryption = m_pPDFEncryptor && m_pPDFEncryptor->isStreamEncryptionEnabled();
if (bStreamEncryption)
{
- m_vEncryptionBuffer.resize(nBytes);
- m_pPDFEncryptor->encrypt(pBuffer, nBytes, m_vEncryptionBuffer, nBytes);
+ nActualSize = m_pPDFEncryptor->calculateSizeIncludingHeader(nActualSize);
+ m_vEncryptionBuffer.resize(nActualSize);
+ m_pPDFEncryptor->encrypt(pBuffer, nBytes, m_vEncryptionBuffer, nActualSize);
}
const void* pWriteBuffer = bStreamEncryption ? m_vEncryptionBuffer.data() : pBuffer;
- m_DocDigest.update(static_cast<unsigned char const*>(pWriteBuffer), static_cast<sal_uInt32>(nBytes));
+ m_DocDigest.update(static_cast<unsigned char const*>(pWriteBuffer), sal_uInt32(nActualSize));
- if (m_aFile.write(pWriteBuffer, nBytes, nWritten) != osl::File::E_None)
+
+ if (m_aFile.write(pWriteBuffer, nActualSize, nWritten) != osl::File::E_None)
nWritten = 0;
- if( nWritten != nBytes )
+ if (nWritten != nActualSize)
{
m_aFile.close();
m_bOpen = false;
+ return false;
}
+ return true;
}
- return nWritten == nBytes;
+ return nWritten == nActualSize;
}
void PDFWriterImpl::newPage( double nPageWidth, double nPageHeight, PDFWriter::Orientation eOrientation )
@@ -6160,12 +6177,34 @@ sal_Int32 PDFWriterImpl::emitEncrypt()
aWriter.startObject(nObject);
aWriter.startDict();
aWriter.write("/Filter", "/Standard");
- aWriter.write("/V", 2);
- aWriter.write("/Length", 128);
- aWriter.write("/R", 3);
- // emit the owner password, must not be encrypted
- aWriter.writeHexArray("/O", rProperties.OValue.data(), rProperties.OValue.size());
- aWriter.writeHexArray("/U", rProperties.UValue.data(), rProperties.UValue.size());
+ aWriter.write("/V", m_pPDFEncryptor->getVersion());
+ aWriter.write("/Length", m_pPDFEncryptor->getKeyLength() * 8);
+ aWriter.write("/R", m_pPDFEncryptor->getRevision());
+
+ if (m_pPDFEncryptor->getVersion() == 5 && m_pPDFEncryptor->getRevision() == 6)
+ {
+ // emit the owner password, must not be encrypted
+ aWriter.writeHexArray("/U", rProperties.UValue.data(), rProperties.UValue.size());
+ aWriter.writeHexArray("/UE", rProperties.UE.data(), rProperties.UE.size());
+ aWriter.writeHexArray("/O", rProperties.OValue.data(), rProperties.OValue.size());
+ aWriter.writeHexArray("/OE", rProperties.OE.data(), rProperties.OE.size());
+
+ // Encrypted perms
+ std::vector<sal_uInt8> aEncryptedPermissions = m_pPDFEncryptor->getEncryptedAccessPermissions(rProperties.EncryptionKey);
+ aWriter.writeHexArray("/Perms", aEncryptedPermissions.data(), aEncryptedPermissions.size());
+
+ // Write content filter stuff - to select we want AESv3 256bit
+ aWriter.write("/CF", "<</StdCF <</CFM /AESV3 /Length 256>>>>");
+ aWriter.write("/StmF", "/StdCF");
+ aWriter.write("/StrF", "/StdCF");
+ aWriter.write("/EncryptMetadata", " false ");
+ }
+ else
+ {
+ // emit the owner password, must not be encrypted
+ aWriter.writeHexArray("/U", rProperties.UValue.data(), rProperties.UValue.size());
+ aWriter.writeHexArray("/O", rProperties.OValue.data(), rProperties.OValue.size());
+ }
aWriter.write("/P", m_pPDFEncryptor->getAccessPermissions());
aWriter.endDict();
aWriter.endObject();
@@ -9823,15 +9862,10 @@ bool PDFWriterImpl::writeBitmapObject( const BitmapEmit& rObject, bool bMask )
m_vEncryptionBuffer[nChar++] = rColor.GetBlue();
}
//encrypt the colorspace lookup table
- m_pPDFEncryptor->encrypt(m_vEncryptionBuffer.data(), nChar, m_vEncryptionBuffer, nChar);
+ std::vector<sal_uInt8> aOutputBuffer(nChar);
+ m_pPDFEncryptor->encrypt(m_vEncryptionBuffer.data(), nChar, aOutputBuffer, nChar);
//now queue the data for output
- nChar = 0;
- for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
- {
- appendHex(m_vEncryptionBuffer[nChar++], aLine );
- appendHex(m_vEncryptionBuffer[nChar++], aLine );
- appendHex(m_vEncryptionBuffer[nChar++], aLine );
- }
+ appendHexArray(aOutputBuffer.data(), aOutputBuffer.size(), aLine);
}
else //no encryption requested (PDF/A-1a program flow drops here)
{
diff --git a/vcl/source/pdf/PDFEncryptionInitialization.cxx b/vcl/source/pdf/PDFEncryptionInitialization.cxx
index df06968fc290..c58898329eac 100644
--- a/vcl/source/pdf/PDFEncryptionInitialization.cxx
+++ b/vcl/source/pdf/PDFEncryptionInitialization.cxx
@@ -24,6 +24,7 @@ css::uno::Reference<css::beans::XMaterialHolder> initEncryption(const OUString&
{
rtl::Reference<EncryptionHashTransporter> pTransporter = new EncryptionHashTransporter;
PDFEncryptor::initEncryption(*pTransporter, i_rOwnerPassword, i_rUserPassword);
+ PDFEncryptorR6::initEncryption(*pTransporter, i_rOwnerPassword, i_rUserPassword);
return pTransporter;
}
diff --git a/vcl/source/pdf/PDFEncryptorR6.cxx b/vcl/source/pdf/PDFEncryptorR6.cxx
index b3e6f9e3059e..c16d7cb1a276 100644
--- a/vcl/source/pdf/PDFEncryptorR6.cxx
+++ b/vcl/source/pdf/PDFEncryptorR6.cxx
@@ -14,11 +14,14 @@
#include <comphelper/hash.hxx>
#include <comphelper/random.hxx>
+using namespace css;
+
namespace vcl::pdf
{
namespace
{
constexpr size_t IV_SIZE = 16;
+constexpr size_t BLOCK_SIZE = 16;
constexpr size_t KEY_SIZE = 32;
constexpr size_t SALT_SIZE = 8;
@@ -155,7 +158,7 @@ std::vector<sal_uInt8> encryptPerms(std::vector<sal_uInt8>& rPerms,
std::vector<sal_uInt8> createPerms(sal_Int32 nAccessPermissions, bool bEncryptMetadata)
{
std::vector<sal_uInt8> aPermsCreated;
- generateBytes(aPermsCreated, 16);
+ generateBytes(aPermsCreated, 16); // fill with random data - mainly for last 4 bytes
aPermsCreated[0] = sal_uInt8(nAccessPermissions);
aPermsCreated[1] = sal_uInt8(nAccessPermissions >> 8);
aPermsCreated[2] = sal_uInt8(nAccessPermissions >> 16);
@@ -249,6 +252,128 @@ size_t addPaddingToVector(std::vector<sal_uInt8>& rVector, size_t nBlockSize)
return nPaddedSize;
}
+class VCL_DLLPUBLIC EncryptionContext
+{
+private:
+ std::vector<sal_uInt8> maKey;
+ std::vector<sal_uInt8> maInitVector;
+
+public:
+ EncryptionContext(std::vector<sal_uInt8> const& rKey, std::vector<sal_uInt8> const& rIV)
+ : maKey(rKey)
+ , maInitVector(rIV)
+ {
+ }
+
+ /** Algorithm 1.A: Encryption of data using the AES algorithms
+ *
+ **/
+ void encrypt(const void* pInput, sal_uInt64 nInputSize, std::vector<sal_uInt8>& rOutput)
+ {
+ comphelper::Encrypt aEncrypt(maKey, maInitVector, comphelper::CryptoType::AES_256_CBC);
+ const sal_uInt8* pInputBytes = static_cast<const sal_uInt8*>(pInput);
+ std::vector<sal_uInt8> aInput(pInputBytes, pInputBytes + nInputSize);
+ size_t nPaddedSize = addPaddingToVector(aInput, BLOCK_SIZE);
+ std::vector<sal_uInt8> aOutput(nPaddedSize);
+ aEncrypt.update(aOutput, aInput);
+ rOutput.resize(nPaddedSize + IV_SIZE);
+ std::copy(maInitVector.begin(), maInitVector.end(), rOutput.begin());
+ std::copy(aOutput.begin(), aOutput.end(), rOutput.begin() + IV_SIZE);
+ }
+};
+
+PDFEncryptorR6::PDFEncryptorR6() = default;
+PDFEncryptorR6::~PDFEncryptorR6() = default;
+
+std::vector<sal_uInt8> PDFEncryptorR6::getEncryptedAccessPermissions(std::vector<sal_uInt8>& rKey)
+{
+ std::vector<sal_uInt8> aPerms = createPerms(m_nAccessPermissions, false);
+ return encryptPerms(aPerms, rKey);
+}
+
+void PDFEncryptorR6::initEncryption(EncryptionHashTransporter& rEncryptionHashTransporter,
+ const OUString& rOwnerPassword, const OUString& rUserPassword)
+{
+ if (rUserPassword.isEmpty())
+ return;
+
+ std::vector<sal_uInt8> aEncryptionKey = vcl::pdf::generateKey();
+ rEncryptionHashTransporter.setEncryptionKey(aEncryptionKey);
+
+ std::vector<sal_uInt8> U;
+ std::vector<sal_uInt8> UE;
+
+ OString pUserPasswordUtf8 = OUStringToOString(rUserPassword, RTL_TEXTENCODING_UTF8);
+ vcl::pdf::generateUandUE(reinterpret_cast<const sal_uInt8*>(pUserPasswordUtf8.getStr()),
+ pUserPasswordUtf8.getLength(), aEncryptionKey, U, UE);
+
+ rEncryptionHashTransporter.setU(U);
+ rEncryptionHashTransporter.setUE(UE);
+
+ OUString aOwnerPasswordToUse = rOwnerPassword.isEmpty() ? rUserPassword : rOwnerPassword;
+
+ std::vector<sal_uInt8> O;
+ std::vector<sal_uInt8> OE;
+
+ OString pOwnerPasswordUtf8 = OUStringToOString(aOwnerPasswordToUse, RTL_TEXTENCODING_UTF8);
+ vcl::pdf::generateOandOE(reinterpret_cast<const sal_uInt8*>(pOwnerPasswordUtf8.getStr()),
+ pOwnerPasswordUtf8.getLength(), aEncryptionKey, U, O, OE);
+
+ rEncryptionHashTransporter.setO(O);
+ rEncryptionHashTransporter.setOE(OE);
+}
+
+bool PDFEncryptorR6::prepareEncryption(
+ const uno::Reference<beans::XMaterialHolder>& xEncryptionMaterialHolder,
+ vcl::PDFEncryptionProperties& rProperties)
+{
+ auto* pTransporter
+ = EncryptionHashTransporter::getEncHashTransporter(xEncryptionMaterialHolder);
+
+ if (!pTransporter)
+ {
+ rProperties.clear();
+ return false;
+ }
+
+ rProperties.UValue = pTransporter->getU();
+ rProperties.UE = pTransporter->getUE();
+ rProperties.OValue = pTransporter->getO();
+ rProperties.OE = pTransporter->getOE();
+ rProperties.EncryptionKey = pTransporter->getEncryptionKey();
+
+ return true;
+}
+
+void PDFEncryptorR6::setupKeysAndCheck(vcl::PDFEncryptionProperties& rProperties)
+{
+ m_nAccessPermissions = rProperties.getAccessPermissions();
+}
+
+sal_uInt64 PDFEncryptorR6::calculateSizeIncludingHeader(sal_uInt64 nSize)
+{
+ return IV_SIZE + comphelper::roundUp<sal_uInt64>(nSize, BLOCK_SIZE);
+}
+
+void PDFEncryptorR6::setupEncryption(std::vector<sal_uInt8>& rEncryptionKey, sal_Int32 /*nObject*/)
+{
+ std::vector<sal_uInt8> aInitVector;
+ generateBytes(aInitVector, IV_SIZE);
+ m_pEncryptionContext = std::make_unique<EncryptionContext>(rEncryptionKey, aInitVector);
+}
+
+void PDFEncryptorR6::setupEncryptionWithIV(std::vector<sal_uInt8>& rEncryptionKey,
+ std::vector<sal_uInt8>& rInitvector)
+{
+ m_pEncryptionContext = std::make_unique<EncryptionContext>(rEncryptionKey, rInitvector);
+}
+
+void PDFEncryptorR6::encrypt(const void* pInput, sal_uInt64 nInputSize,
+ std::vector<sal_uInt8>& rOutput, sal_uInt64 /*nOutputSize*/)
+{
+ m_pEncryptionContext->encrypt(pInput, nInputSize, rOutput);
+}
+
} // end vcl::pdf
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */