vcl/inc/pdf/PDFEncryptor.hxx | 24 +++++++++++++++++---- vcl/inc/pdf/pdfwriter_impl.hxx | 3 -- vcl/source/gdi/pdfwriter_impl.cxx | 9 ++++--- vcl/source/gdi/pdfwriter_impl2.cxx | 42 +++++++++++-------------------------- vcl/source/pdf/PDFEncryptor.cxx | 33 +++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 39 deletions(-)
New commits: commit 2630015100c66a5ec19f07d786b5d0aab7d7892a Author: Tomaž Vajngerl <[email protected]> AuthorDate: Thu Nov 7 14:35:18 2024 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Mon Nov 25 09:53:30 2024 +0100 pdf: move stream/string encryption into PDFEncryptor Change-Id: Ie710e51faa7d65686d72a03d1ef4ca40dff8c27e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176215 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/vcl/inc/pdf/PDFEncryptor.hxx b/vcl/inc/pdf/PDFEncryptor.hxx index dca2255139e8..5b9f50492742 100644 --- a/vcl/inc/pdf/PDFEncryptor.hxx +++ b/vcl/inc/pdf/PDFEncryptor.hxx @@ -12,16 +12,22 @@ #include <string_view> #include <rtl/cipher.h> -#include <com/sun/star/uno/Reference.hxx> +#include <rtl/ustring.hxx> +#include <vector> namespace vcl { struct PDFEncryptionProperties; } + namespace com::sun::star::beans { class XMaterialHolder; } +namespace com::sun::star::uno +{ +template <typename> class Reference; +} namespace vcl::pdf { @@ -38,6 +44,10 @@ private: sal_Int32 m_nKeyLength = 0; // key length, 16 or 5 sal_Int32 m_nRC4KeyLength = 0; // key length, 16 or 10, to be input to the algorithm 3.1 + + /* set to true if the following stream must be encrypted, used inside writeBuffer() */ + bool m_bEncryptThisStream = false; + public: PDFEncryptor(); ~PDFEncryptor(); @@ -45,9 +55,6 @@ public: /* used to cipher the stream data and for password management */ rtlCipher m_aCipher = nullptr; - /* set to true if the following stream must be encrypted, used inside writeBuffer() */ - bool m_bEncryptThisStream = false; - sal_Int32 getAccessPermissions() { return m_nAccessPermissions; } sal_Int32 getKeyLength() { return m_nKeyLength; } sal_Int32 getRC4KeyLength() { return m_nRC4KeyLength; } @@ -58,6 +65,15 @@ public: const css::uno::Reference<css::beans::XMaterialHolder>& xEncryptionMaterialHolder, PDFEncryptionProperties& rProperties); void setupKeysAndCheck(PDFEncryptionProperties& rProperties); + + void setupEncryption(std::vector<sal_uInt8> const& rEncryptionKey, sal_Int32 nObject); + void enableStreamEncryption(); + void disableStreamEncryption(); + + bool isStreamEncryptionEnabled() { return m_bEncryptThisStream; } + + void encrypt(const void* pInput, sal_uInt64 nInputSize, sal_uInt8* pOutput, + sal_uInt64 nOutputsSize); }; } diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx index 486363e83cf4..5756bebf0082 100644 --- a/vcl/inc/pdf/pdfwriter_impl.hxx +++ b/vcl/inc/pdf/pdfwriter_impl.hxx @@ -837,10 +837,9 @@ private: void addRoleMap(OString aAlias, PDFWriter::StructElement eType); - /* this function implements part of the PDF spec algorithm 3.1 in encryption, the rest (the actual encryption) is in PDFWriterImpl::writeBuffer */ void checkAndEnableStreamEncryption( sal_Int32 nObject ) override; - void disableStreamEncryption() override { m_aPDFEncryptor.m_bEncryptThisStream = false; } + void disableStreamEncryption() override; /* */ void enableStringEncryption( sal_Int32 nObject ); diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index b6f916a560c1..893471b3a34b 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -1739,15 +1739,16 @@ bool PDFWriterImpl::writeBufferBytes( const void* pBuffer, sal_uInt64 nBytes ) else { bool buffOK = true; - if (m_aPDFEncryptor.m_bEncryptThisStream) + if (m_aPDFEncryptor.isStreamEncryptionEnabled()) { - /* implement the encryption part of the PDF spec encryption algorithm 3.1 */ m_vEncryptionBuffer.resize(nBytes); if (buffOK) - rtl_cipher_encodeARCFOUR(m_aPDFEncryptor.m_aCipher, pBuffer, static_cast<sal_Size>(nBytes), m_vEncryptionBuffer.data(), static_cast<sal_Size>(nBytes)); + { + m_aPDFEncryptor.encrypt(pBuffer, nBytes, m_vEncryptionBuffer.data(), nBytes); + } } - const void* pWriteBuffer = (m_aPDFEncryptor.m_bEncryptThisStream && buffOK) ? m_vEncryptionBuffer.data() : pBuffer; + const void* pWriteBuffer = (m_aPDFEncryptor.isStreamEncryptionEnabled() && buffOK) ? m_vEncryptionBuffer.data() : pBuffer; m_DocDigest.update(static_cast<unsigned char const*>(pWriteBuffer), static_cast<sal_uInt32>(nBytes)); if (m_aFile.write(pWriteBuffer, nBytes, nWritten) != osl::File::E_None) diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx index 0f309f375c20..547c0fb36896 100644 --- a/vcl/source/gdi/pdfwriter_impl2.cxx +++ b/vcl/source/gdi/pdfwriter_impl2.cxx @@ -1078,43 +1078,27 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa // Encryption methods -void PDFWriterImpl::checkAndEnableStreamEncryption( sal_Int32 nObject ) +void PDFWriterImpl::checkAndEnableStreamEncryption(sal_Int32 nObject) { - if( !m_aContext.Encryption.Encrypt() ) + if (!m_aContext.Encryption.Encrypt()) return; - m_aPDFEncryptor.m_bEncryptThisStream = true; - sal_Int32 i = m_aPDFEncryptor.getKeyLength(); - m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>(nObject); - m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>( nObject >> 8 ); - m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>( nObject >> 16 ); - // the other location of m_nEncryptionKey is already set to 0, our fixed generation number - // do the MD5 hash - ::std::vector<unsigned char> const nMD5Sum(::comphelper::Hash::calculateHash( - m_aContext.Encryption.EncryptionKey.data(), i+2, ::comphelper::HashType::MD5)); - // the i+2 to take into account the generation number, always zero - // initialize the RC4 with the key - // key length: see algorithm 3.1, step 4: (N+5) max 16 - rtl_cipher_initARCFOUR(m_aPDFEncryptor.m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum.data(), m_aPDFEncryptor.getRC4KeyLength(), nullptr, 0); + m_aPDFEncryptor.enableStreamEncryption(); + m_aPDFEncryptor.setupEncryption(m_aContext.Encryption.EncryptionKey, nObject); } -void PDFWriterImpl::enableStringEncryption( sal_Int32 nObject ) +void PDFWriterImpl::disableStreamEncryption() { - if( !m_aContext.Encryption.Encrypt() ) + m_aPDFEncryptor.disableStreamEncryption(); + +} + +void PDFWriterImpl::enableStringEncryption(sal_Int32 nObject) +{ + if (!m_aContext.Encryption.Encrypt()) return; - sal_Int32 i = m_aPDFEncryptor.getKeyLength(); - m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>(nObject); - m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>( nObject >> 8 ); - m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>( nObject >> 16 ); - // the other location of m_nEncryptionKey is already set to 0, our fixed generation number - // do the MD5 hash - // the i+2 to take into account the generation number, always zero - ::std::vector<unsigned char> const nMD5Sum(::comphelper::Hash::calculateHash( - m_aContext.Encryption.EncryptionKey.data(), i+2, ::comphelper::HashType::MD5)); - // initialize the RC4 with the key - // key length: see algorithm 3.1, step 4: (N+5) max 16 - rtl_cipher_initARCFOUR(m_aPDFEncryptor.m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum.data(), m_aPDFEncryptor.getRC4KeyLength(), nullptr, 0); + m_aPDFEncryptor.setupEncryption(m_aContext.Encryption.EncryptionKey, nObject); } const tools::Long unsetRun[256] = diff --git a/vcl/source/pdf/PDFEncryptor.cxx b/vcl/source/pdf/PDFEncryptor.cxx index 2c6d37296d42..16b88ec160b0 100644 --- a/vcl/source/pdf/PDFEncryptor.cxx +++ b/vcl/source/pdf/PDFEncryptor.cxx @@ -380,6 +380,7 @@ bool PDFEncryptor::prepareEncryption( return bSuccess; } +/* this function implements part of the PDF spec algorithm 3.1 in encryption */ void PDFEncryptor::setupKeysAndCheck(vcl::PDFEncryptionProperties& rProperties) { // sanity check @@ -399,6 +400,38 @@ void PDFEncryptor::setupKeysAndCheck(vcl::PDFEncryptionProperties& rProperties) } } +void PDFEncryptor::enableStreamEncryption() { m_bEncryptThisStream = true; } + +void PDFEncryptor::disableStreamEncryption() { m_bEncryptThisStream = false; } + +void PDFEncryptor::setupEncryption(std::vector<sal_uInt8> const& rEncryptionKey, sal_Int32 nObject) +{ + std::vector<sal_uInt8> aKey(rEncryptionKey.begin(), rEncryptionKey.begin() + m_nKeyLength); + std::vector<sal_uInt8> aObjectArray{ + sal_uInt8(nObject), sal_uInt8(nObject >> 8), sal_uInt8(nObject >> 16), + 0, // generation number, always zero + 0 // generation number, always zero + }; + aKey.insert(aKey.end(), aObjectArray.begin(), aObjectArray.end()); + + // do the MD5 hash + auto const nMD5Sum + = comphelper::Hash::calculateHash(aKey.data(), aKey.size(), ::comphelper::HashType::MD5); + + // initialize the RC4 with the key + // key length: see algorithm 3.1, step 4: (N+5) max 16 + rtl_cipher_initARCFOUR(m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum.data(), getRC4KeyLength(), + nullptr, 0); +} + +/* implement the encryption part of the PDF spec encryption algorithm 3.1 */ +void PDFEncryptor::encrypt(const void* pInput, sal_uInt64 nInputSize, sal_uInt8* pOutput, + sal_uInt64 nOutputsSize) +{ + rtl_cipher_encodeARCFOUR(m_aCipher, pInput, sal_Size(nInputSize), pOutput, + sal_Size(nOutputsSize)); +} + } // end vcl::pdf /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
