summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/pdf/EncryptionHashTransporter.hxx29
-rw-r--r--vcl/inc/pdf/IPDFEncryptor.hxx6
-rw-r--r--vcl/inc/pdf/PDFEncryptorR6.hxx49
-rw-r--r--vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx136
-rw-r--r--vcl/qa/cppunit/pdfexport/pdfexport2.cxx21
-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
8 files changed, 396 insertions, 61 deletions
diff --git a/vcl/inc/pdf/EncryptionHashTransporter.hxx b/vcl/inc/pdf/EncryptionHashTransporter.hxx
index 596b6490570a..9b523f3f90f0 100644
--- a/vcl/inc/pdf/EncryptionHashTransporter.hxx
+++ b/vcl/inc/pdf/EncryptionHashTransporter.hxx
@@ -5,7 +5,6 @@
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
*/
#pragma once
@@ -28,8 +27,18 @@ namespace vcl::pdf
*/
class EncryptionHashTransporter : public cppu::WeakImplHelper<css::beans::XMaterialHolder>
{
+ // V2R3
std::unique_ptr<comphelper::Hash> m_pDigest;
std::vector<sal_uInt8> maOValue;
+
+ // V5R6
+ std::vector<sal_uInt8> mU;
+ std::vector<sal_uInt8> mUE;
+ std::vector<sal_uInt8> mO;
+ std::vector<sal_uInt8> mOE;
+ std::vector<sal_uInt8> maEncryptionKey;
+
+ // ID
sal_IntPtr maID;
public:
@@ -43,6 +52,24 @@ public:
void invalidate() { m_pDigest.reset(); }
+ std::vector<sal_uInt8> getU() { return mU; }
+ void setU(std::vector<sal_uInt8> const& rU) { mU = rU; }
+
+ std::vector<sal_uInt8> getUE() { return mUE; }
+ void setUE(std::vector<sal_uInt8> const& rUE) { mUE = rUE; }
+
+ std::vector<sal_uInt8> getO() { return mO; }
+ void setO(std::vector<sal_uInt8> const& rO) { mO = rO; }
+
+ std::vector<sal_uInt8> getOE() { return mOE; }
+ void setOE(std::vector<sal_uInt8> const& rOE) { mOE = rOE; }
+
+ std::vector<sal_uInt8> getEncryptionKey() { return maEncryptionKey; }
+ void setEncryptionKey(std::vector<sal_uInt8> const& rEncryptionKey)
+ {
+ maEncryptionKey = rEncryptionKey;
+ }
+
// XMaterialHolder
virtual css::uno::Any SAL_CALL getMaterial() override { return css::uno::Any(sal_Int64(maID)); }
diff --git a/vcl/inc/pdf/IPDFEncryptor.hxx b/vcl/inc/pdf/IPDFEncryptor.hxx
index 706eb82c71ed..61ef8676da46 100644
--- a/vcl/inc/pdf/IPDFEncryptor.hxx
+++ b/vcl/inc/pdf/IPDFEncryptor.hxx
@@ -5,7 +5,6 @@
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
*/
#pragma once
@@ -59,7 +58,7 @@ public:
* Depending on the encryption revision this may not be available. In that
* case we can expect empty content.
*/
- virtual std::vector<sal_uInt8> getEncryptedAccessPermissions()
+ virtual std::vector<sal_uInt8> getEncryptedAccessPermissions(std::vector<sal_uInt8>& /*rKey*/)
{
return std::vector<sal_uInt8>();
}
@@ -79,6 +78,9 @@ public:
/** Setup before we start encrypting - remembers the key */
virtual void setupEncryption(std::vector<sal_uInt8>& rEncryptionKey, sal_Int32 nObject) = 0;
+ /** Calculate the size of the output (by default the same as input) */
+ virtual sal_uInt64 calculateSizeIncludingHeader(sal_uInt64 nSize) { return nSize; }
+
/** Encrypts the input and stores into the output */
virtual void encrypt(const void* pInput, sal_uInt64 nInputSize, std::vector<sal_uInt8>& rOutput,
sal_uInt64 nOutputSize)
diff --git a/vcl/inc/pdf/PDFEncryptorR6.hxx b/vcl/inc/pdf/PDFEncryptorR6.hxx
index 219796ccf0a5..a8812fefcd21 100644
--- a/vcl/inc/pdf/PDFEncryptorR6.hxx
+++ b/vcl/inc/pdf/PDFEncryptorR6.hxx
@@ -13,9 +13,12 @@
#include <string_view>
#include <vector>
#include <vcl/dllapi.h>
+#include <pdf/IPDFEncryptor.hxx>
namespace vcl::pdf
{
+class EncryptionHashTransporter;
+
/** Algorithm 2.B: Computing a hash (revision 6 and later)
*
* Described in ISO 32000-2:2020(E) - 7.6.4.3.4
@@ -107,6 +110,52 @@ VCL_DLLPUBLIC std::vector<sal_uInt8> createPerms(sal_Int32 nAccessPermissions,
*/
VCL_DLLPUBLIC size_t addPaddingToVector(std::vector<sal_uInt8>& rVector, size_t nBlockSize);
+class EncryptionContext;
+
+/** IPDFEncryptor implementation of PDF encryption version 5 revision 6 added in PDF 2.0
+ *
+ * The complete algorithm is defined in PDF 2.0 specification ISO 32000-2:2020(E)
+ */
+class VCL_DLLPUBLIC PDFEncryptorR6 : public IPDFEncryptor
+{
+ std::unique_ptr<EncryptionContext> m_pEncryptionContext;
+ sal_Int32 m_nAccessPermissions = 0;
+
+public:
+ PDFEncryptorR6();
+ ~PDFEncryptorR6();
+
+ sal_Int32 getVersion() override { return 5; }
+ sal_Int32 getRevision() override { return 6; }
+ sal_Int32 getAccessPermissions() override { return m_nAccessPermissions; }
+ /** Key length - AES 256 bit */
+ sal_Int32 getKeyLength() override { return 256 / 8; }
+
+ std::vector<sal_uInt8> getEncryptedAccessPermissions(std::vector<sal_uInt8>& rKey) override;
+
+ static void initEncryption(EncryptionHashTransporter& rEncryptionHashTransporter,
+ const OUString& i_rOwnerPassword, const OUString& i_rUserPassword);
+
+ bool prepareEncryption(
+ const css::uno::Reference<css::beans::XMaterialHolder>& xEncryptionMaterialHolder,
+ PDFEncryptionProperties& rProperties) override;
+
+ void setupKeysAndCheck(PDFEncryptionProperties& rProperties) override;
+
+ sal_uInt64 calculateSizeIncludingHeader(sal_uInt64 nSize) override;
+
+ void setupEncryption(std::vector<sal_uInt8>& rEncryptionKey, sal_Int32 nObject) override;
+
+ void setupEncryptionWithIV(std::vector<sal_uInt8>& rInitvector, std::vector<sal_uInt8>& rIV);
+
+ /** Encrypts using Algorithm 1.A: Encryption of data using the AES algorithms
+ *
+ * Described in ISO 32000-2:2020(E) - 7.6.3.3
+ */
+ void encrypt(const void* pInput, sal_uInt64 nInputSize, std::vector<sal_uInt8>& rOutput,
+ sal_uInt64 nOutputsSize) override;
+};
+
} // end vcl::pdf
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx b/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx
index 40a4eb94c1b4..f4eeb2a9fd05 100644
--- a/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx
+++ b/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx
@@ -10,21 +10,25 @@
#include <sal/config.h>
#include <config_oox.h>
-#include <algorithm>
-#include <memory>
-#include <string_view>
-
#include <test/unoapi_test.hxx>
#include <o3tl/string_view.hxx>
-#include <vcl/filter/PDFiumLibrary.hxx>
-#include <vcl/pdfread.hxx>
-#include <comphelper/propertyvalue.hxx>
-#include <cmath>
-
+#include <unotools/mediadescriptor.hxx>
#include <comphelper/crypto/Crypto.hxx>
#include <comphelper/hash.hxx>
#include <comphelper/random.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+
+#include <vcl/filter/PDFiumLibrary.hxx>
+#include <vcl/pdfread.hxx>
+
+#include <com/sun/star/frame/XStorable.hpp>
+
+#include <algorithm>
+#include <memory>
+#include <string_view>
+#include <cmath>
#include <pdf/PDFEncryptorR6.hxx>
@@ -38,6 +42,9 @@ namespace
{
class PDFEncryptionTest : public UnoApiTest
{
+protected:
+ utl::MediaDescriptor maMediaDescriptor;
+
public:
PDFEncryptionTest()
: UnoApiTest("/vcl/qa/cppunit/pdfexport/data/")
@@ -79,6 +86,48 @@ std::vector<sal_uInt8> parseHex(std::string_view rString)
return aResult;
}
+CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testEncryptionRoundtrip_PDF_1_7)
+{
+ loadFromFile(u"BrownFoxLazyDog.odt");
+
+ // Save PDF
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ maMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
+ uno::Sequence<beans::PropertyValue> aFilterData = comphelper::InitPropertySequence(
+ { { "SelectPdfVersion", uno::Any(sal_Int32(17)) },
+ { "EncryptFile", uno::Any(true) },
+ { "DocumentOpenPassword", uno::Any(u"secret"_ustr) } });
+ maMediaDescriptor["FilterData"] <<= aFilterData;
+ xStorable->storeToURL(maTempFile.GetURL(), maMediaDescriptor.getAsConstPropertyValueList());
+
+ // Load the exported result in PDFium
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport("secret"_ostr);
+ CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount());
+ int nFileVersion = pPdfDocument->getFileVersion();
+ CPPUNIT_ASSERT_EQUAL(17, nFileVersion);
+}
+
+CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testEncryptionRoundtrip_PDF_2_0)
+{
+ loadFromFile(u"BrownFoxLazyDog.odt");
+
+ // Save PDF
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ maMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
+ uno::Sequence<beans::PropertyValue> aFilterData = comphelper::InitPropertySequence(
+ { { "SelectPdfVersion", uno::Any(sal_Int32(20)) },
+ { "EncryptFile", uno::Any(true) },
+ { "DocumentOpenPassword", uno::Any(u"secret"_ustr) } });
+ maMediaDescriptor["FilterData"] <<= aFilterData;
+ xStorable->storeToURL(maTempFile.GetURL(), maMediaDescriptor.getAsConstPropertyValueList());
+
+ // Load the exported result in PDFium
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport("secret"_ostr);
+ CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount());
+ int nFileVersion = pPdfDocument->getFileVersion();
+ CPPUNIT_ASSERT_EQUAL(20, nFileVersion);
+}
+
CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testComputeHashForR6)
{
const sal_uInt8 pOwnerPass[] = { 'T', 'e', 's', 't' };
@@ -257,6 +306,75 @@ CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testPadding)
CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x0B), aVector[i]);
}
+CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testFileDecryption)
+{
+ std::vector<sal_uInt8> aData
+ = parseHex("d07efca5cce3c18fd8e344d45d826886d1774c5e1e310c971f8578924f848fc6");
+
+ std::vector<sal_uInt8> iv(aData.begin(), aData.begin() + 16);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("d07efca5cce3c18fd8e344d45d826886"),
+ comphelper::hashToString(iv));
+
+ std::vector<sal_uInt8> aEncryptedString(aData.begin() + 16, aData.end());
+
+ std::vector<sal_uInt8> U = parseHex("7BD210807A0277FECC52C261C442F02E1AD62C1A23553348B8F8AF7320"
+ "DC9978FAB7E65E1BF4CA76F4BE5E6D2AA8C7D5");
+
+ std::vector<sal_uInt8> UE
+ = parseHex("67022D91A6BDF3179F488DC9658E54B78A0AD05C6A9C419DCD17A6941C151197");
+
+ const sal_uInt8 pUserPass[] = { 'T', 'e', 's', 't' };
+
+ CPPUNIT_ASSERT_EQUAL(true, vcl::pdf::validateUserPassword(pUserPass, 4, U));
+
+ std::vector<sal_uInt8> aDecryptedKey = vcl::pdf::decryptKey(pUserPass, 4, U, UE);
+
+ CPPUNIT_ASSERT_EQUAL(
+ std::string("90e657b78c0315610f3f421bd396ff635fa8fe3cf2ea399e7e1ae23e6185b4fc"),
+ comphelper::hashToString(aDecryptedKey));
+
+ comphelper::Decrypt aDecrypt(aDecryptedKey, iv, comphelper::CryptoType::AES_256_CBC);
+
+ std::vector<sal_uInt8> aOutput(aEncryptedString.size(), 0);
+
+ aDecrypt.update(aOutput, aEncryptedString);
+
+ CPPUNIT_ASSERT_EQUAL(
+ std::string("656e2d47420b0b0b0b0b0b0b0b0b0b0b"), // 'en-GB' + padding 0x0B = 11 chars
+ comphelper::hashToString(aOutput));
+}
+
+CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testFileEncryption)
+{
+ std::vector<sal_uInt8> aKey
+ = parseHex("90e657b78c0315610f3f421bd396ff635fa8fe3cf2ea399e7e1ae23e6185b4fc");
+ std::vector<sal_uInt8> aIV = parseHex("d07efca5cce3c18fd8e344d45d826886");
+
+ static constexpr const auto aData = std::to_array<sal_uInt8>({ 'e', 'n', '-', 'G', 'B' });
+
+ std::vector<sal_uInt8> aEncryptedBuffer;
+
+ vcl::pdf::PDFEncryptorR6 aEncryptor;
+ aEncryptor.setupEncryptionWithIV(aKey, aIV);
+ aEncryptor.encrypt(aData.data(), aData.size(), aEncryptedBuffer, aData.size());
+
+ CPPUNIT_ASSERT_EQUAL(
+ std::string("d07efca5cce3c18fd8e344d45d826886d1774c5e1e310c971f8578924f848fc6"),
+ comphelper::hashToString(aEncryptedBuffer));
+
+ // Decrypt
+ std::vector<sal_uInt8> aEncryptedIV(aEncryptedBuffer.begin(), aEncryptedBuffer.begin() + 16);
+ std::vector<sal_uInt8> aEncryptedString(aEncryptedBuffer.begin() + 16, aEncryptedBuffer.end());
+ comphelper::Decrypt aDecrypt(aKey, aEncryptedIV, comphelper::CryptoType::AES_256_CBC);
+ std::vector<sal_uInt8> aOutputString(aEncryptedString.size(), 0);
+ aDecrypt.update(aOutputString, aEncryptedString);
+
+ CPPUNIT_ASSERT_EQUAL(
+ std::string("656e2d47420b0b0b0b0b0b0b0b0b0b0b"), // 'en-GB' + padding 0x0B = 11 chars
+ comphelper::hashToString(aOutputString));
+}
+
} // end anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx
index 20acdc856aeb..548036654222 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx
@@ -750,27 +750,6 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testVersion20)
CPPUNIT_ASSERT_EQUAL(20, nFileVersion);
}
-CPPUNIT_TEST_FIXTURE(PdfExportTest2, testEncryptionRoundtrip)
-{
- mxComponent = loadFromDesktop("private:factory/swriter");
-
- // Save PDF
- uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
- aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
- uno::Sequence<beans::PropertyValue> aFilterData = comphelper::InitPropertySequence(
- { { "SelectPdfVersion", uno::Any(sal_Int32(20)) },
- { "EncryptFile", uno::Any(true) },
- { "DocumentOpenPassword", uno::Any(u"secret"_ustr) } });
- aMediaDescriptor["FilterData"] <<= aFilterData;
- xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
-
- // Load the exported result in PDFium
- std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport("secret"_ostr);
- CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount());
- int nFileVersion = pPdfDocument->getFileVersion();
- CPPUNIT_ASSERT_EQUAL(20, nFileVersion);
-}
-
// Check round-trip of importing and exporting the PDF with PDFium filter,
// which imports the PDF document as multiple PDFs as graphic object.
// Each page in the document has one PDF graphic object which content is
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: */