diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2024-11-22 23:46:29 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2024-12-24 07:28:38 +0100 |
commit | 6912dd8dda491740d35e1aabe8518330b412684e (patch) | |
tree | d919f09d0191bd500b75e38164420cccacadaf1b | |
parent | 7257cd8b5420e398f14456e6713de61850223dba (diff) |
pdf: properly encrypt metadata (for Revision 6+)
Metadata should also be encrypted, and it is the default, so also
encrypt the metadata and properly set the flags in encrypt dict.
Change-Id: I083faa8174a1ed4b43ecaceaa11e27e87562e1b1
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177038
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178764
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r-- | vcl/inc/pdf/COSWriter.hxx | 14 | ||||
-rw-r--r-- | vcl/inc/pdf/IPDFEncryptor.hxx | 1 | ||||
-rw-r--r-- | vcl/inc/pdf/PDFEncryptor.hxx | 1 | ||||
-rw-r--r-- | vcl/inc/pdf/PDFEncryptorR6.hxx | 1 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 106 | ||||
-rw-r--r-- | vcl/source/pdf/PDFEncryptorR6.cxx | 2 |
6 files changed, 76 insertions, 49 deletions
diff --git a/vcl/inc/pdf/COSWriter.hxx b/vcl/inc/pdf/COSWriter.hxx index 4c90f6f4968e..b47dabbe5c7e 100644 --- a/vcl/inc/pdf/COSWriter.hxx +++ b/vcl/inc/pdf/COSWriter.hxx @@ -75,7 +75,7 @@ class COSWriter } public: - COSWriter(std::shared_ptr<IPDFEncryptor> const& pPDFEncryptor) + COSWriter(std::shared_ptr<IPDFEncryptor> const& pPDFEncryptor = nullptr) : mpPDFEncryptor(pPDFEncryptor) , maLine(1024) { @@ -92,9 +92,11 @@ public: OStringBuffer& getLine() { return maLine; } void startDict() { maLine.append("<<"); } - void endDict() { maLine.append(">>\n"); } + void startStream() { maLine.append("stream\n"); } + void endStream() { maLine.append("\nendstream\n"); } + void write(std::string_view key, std::string_view value) { maLine.append(key); @@ -108,6 +110,14 @@ public: maLine.append(value); } + void writeReference(std::string_view key, sal_Int32 nObjectID) + { + maLine.append(key); + maLine.append(" "); + maLine.append(nObjectID); + maLine.append(" 0 R"); + } + void writeKeyAndUnicode(std::string_view key, OUString const& rString) { maLine.append(key); diff --git a/vcl/inc/pdf/IPDFEncryptor.hxx b/vcl/inc/pdf/IPDFEncryptor.hxx index 61ef8676da46..099e16783d54 100644 --- a/vcl/inc/pdf/IPDFEncryptor.hxx +++ b/vcl/inc/pdf/IPDFEncryptor.hxx @@ -52,6 +52,7 @@ public: /** the numerical value of the access permissions, according to PDF spec, must be signed */ virtual sal_Int32 getAccessPermissions() = 0; + virtual bool isMetadataEncrypted() = 0; /** Encrypted access permission * diff --git a/vcl/inc/pdf/PDFEncryptor.hxx b/vcl/inc/pdf/PDFEncryptor.hxx index 9a65c5a0043b..1583da4779c0 100644 --- a/vcl/inc/pdf/PDFEncryptor.hxx +++ b/vcl/inc/pdf/PDFEncryptor.hxx @@ -47,6 +47,7 @@ public: sal_Int32 getRevision() override { return 3; }; sal_Int32 getAccessPermissions() override { return m_nAccessPermissions; } + bool isMetadataEncrypted() override { return false; } sal_Int32 getKeyLength() override { return m_nKeyLength; } sal_Int32 getRC4KeyLength() { return m_nRC4KeyLength; } diff --git a/vcl/inc/pdf/PDFEncryptorR6.hxx b/vcl/inc/pdf/PDFEncryptorR6.hxx index 56fe094469c6..ca7a6e388b2d 100644 --- a/vcl/inc/pdf/PDFEncryptorR6.hxx +++ b/vcl/inc/pdf/PDFEncryptorR6.hxx @@ -128,6 +128,7 @@ public: sal_Int32 getVersion() override { return 5; } sal_Int32 getRevision() override { return 6; } sal_Int32 getAccessPermissions() override { return m_nAccessPermissions; } + bool isMetadataEncrypted() override { return true; } /** Key length - AES 256 bit */ sal_Int32 getKeyLength() override { return 256 / 8; } diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index ae63f2844d37..5444ff99a563 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -5622,9 +5622,9 @@ bool PDFWriterImpl::emitCatalog() if( nMetadataObject ) { - aLine.append("/Metadata "); - aLine.append( nMetadataObject ); - aLine.append( " 0 R" ); + COSWriter aWriter; + aWriter.writeReference("/Metadata", nMetadataObject); + aLine.append(aWriter.getLine()); } aLine.append( ">>\n" @@ -6025,52 +6025,64 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata() //get the object number for all the destinations sal_Int32 nObject = createObject(); - if( updateObject( nObject ) ) - { - pdf::XmpMetadata aMetadata; + if (!updateObject(nObject)) + return 0; - if (m_nPDFA_Version > 0) - aMetadata.mnPDF_A = m_nPDFA_Version; - - aMetadata.mbPDF_UA = m_bIsPDF_UA; - - lcl_assignMeta(m_aContext.DocumentInfo.Title, aMetadata.msTitle); - lcl_assignMeta(m_aContext.DocumentInfo.Author, aMetadata.msAuthor); - lcl_assignMeta(m_aContext.DocumentInfo.Subject, aMetadata.msSubject); - lcl_assignMeta(m_aContext.DocumentInfo.Producer, aMetadata.msProducer); - aMetadata.msPDFVersion = getPDFVersionStr(m_aContext.Version); - lcl_assignMeta(m_aContext.DocumentInfo.Keywords, aMetadata.msKeywords); - lcl_assignMeta(m_aContext.DocumentInfo.Contributor, aMetadata.maContributor); - lcl_assignMeta(m_aContext.DocumentInfo.Coverage, aMetadata.msCoverage); - lcl_assignMeta(m_aContext.DocumentInfo.Identifier, aMetadata.msIdentifier); - lcl_assignMeta(m_aContext.DocumentInfo.Publisher, aMetadata.maPublisher); - lcl_assignMeta(m_aContext.DocumentInfo.Relation, aMetadata.maRelation); - lcl_assignMeta(m_aContext.DocumentInfo.Rights, aMetadata.msRights); - lcl_assignMeta(m_aContext.DocumentInfo.Source, aMetadata.msSource); - lcl_assignMeta(m_aContext.DocumentInfo.Type, aMetadata.msType); - lcl_assignMeta(m_aContext.DocumentInfo.Creator, aMetadata.m_sCreatorTool); - aMetadata.m_sCreateDate = m_aCreationMetaDateString; - - OStringBuffer aMetadataObj( 1024 ); - - aMetadataObj.append( nObject ); - aMetadataObj.append( " 0 obj\n" ); - - aMetadataObj.append( "<</Type/Metadata/Subtype/XML/Length " ); - - aMetadataObj.append( sal_Int32(aMetadata.getSize()) ); - aMetadataObj.append( ">>\nstream\n" ); - if ( !writeBuffer( aMetadataObj ) ) - return 0; - //emit the stream - if ( !writeBufferBytes( aMetadata.getData(), aMetadata.getSize() ) ) + pdf::XmpMetadata aMetadata; + + if (m_nPDFA_Version > 0) + aMetadata.mnPDF_A = m_nPDFA_Version; + + aMetadata.mbPDF_UA = m_bIsPDF_UA; + + lcl_assignMeta(m_aContext.DocumentInfo.Title, aMetadata.msTitle); + lcl_assignMeta(m_aContext.DocumentInfo.Author, aMetadata.msAuthor); + lcl_assignMeta(m_aContext.DocumentInfo.Subject, aMetadata.msSubject); + lcl_assignMeta(m_aContext.DocumentInfo.Producer, aMetadata.msProducer); + aMetadata.msPDFVersion = getPDFVersionStr(m_aContext.Version); + lcl_assignMeta(m_aContext.DocumentInfo.Keywords, aMetadata.msKeywords); + lcl_assignMeta(m_aContext.DocumentInfo.Contributor, aMetadata.maContributor); + lcl_assignMeta(m_aContext.DocumentInfo.Coverage, aMetadata.msCoverage); + lcl_assignMeta(m_aContext.DocumentInfo.Identifier, aMetadata.msIdentifier); + lcl_assignMeta(m_aContext.DocumentInfo.Publisher, aMetadata.maPublisher); + lcl_assignMeta(m_aContext.DocumentInfo.Relation, aMetadata.maRelation); + lcl_assignMeta(m_aContext.DocumentInfo.Rights, aMetadata.msRights); + lcl_assignMeta(m_aContext.DocumentInfo.Source, aMetadata.msSource); + lcl_assignMeta(m_aContext.DocumentInfo.Type, aMetadata.msType); + lcl_assignMeta(m_aContext.DocumentInfo.Creator, aMetadata.m_sCreatorTool); + aMetadata.m_sCreateDate = m_aCreationMetaDateString; + + { + COSWriter aWriter; + aWriter.startObject(nObject); + aWriter.startDict(); + aWriter.write("/Type", "/Metadata"); + aWriter.write("/Subtype", "/XML"); + aWriter.write("/Length", sal_Int32(aMetadata.getSize())); + aWriter.endDict(); + aWriter.startStream(); + if (!writeBuffer(aWriter.getLine())) return 0; + } - if( ! writeBuffer( "\nendstream\nendobj\n\n" ) ) - nObject = 0; + //emit the stream + bool bEncryptMetadata = m_pPDFEncryptor && m_pPDFEncryptor->isMetadataEncrypted(); + if (bEncryptMetadata) + checkAndEnableStreamEncryption(nObject); + + if (!writeBufferBytes(aMetadata.getData(), aMetadata.getSize())) + return 0; + + if (bEncryptMetadata) + disableStreamEncryption(); + + { + COSWriter aWriter; + aWriter.endStream(); + aWriter.endObject(); + if (!writeBuffer(aWriter.getLine())) + return 0; } - else - nObject = 0; return nObject; } @@ -6110,7 +6122,9 @@ sal_Int32 PDFWriterImpl::emitEncrypt() aWriter.write("/CF", "<</StdCF <</CFM /AESV3 /Length 256>>>>"); aWriter.write("/StmF", "/StdCF"); aWriter.write("/StrF", "/StdCF"); - aWriter.write("/EncryptMetadata", " false "); + // Encrypt metadata. Default is true. Relevant for Revision 6+ + if (!m_pPDFEncryptor->isMetadataEncrypted()) + aWriter.write("/EncryptMetadata", " false "); } else { diff --git a/vcl/source/pdf/PDFEncryptorR6.cxx b/vcl/source/pdf/PDFEncryptorR6.cxx index d951b738246f..52dceddc9636 100644 --- a/vcl/source/pdf/PDFEncryptorR6.cxx +++ b/vcl/source/pdf/PDFEncryptorR6.cxx @@ -284,7 +284,7 @@ PDFEncryptorR6::~PDFEncryptorR6() = default; std::vector<sal_uInt8> PDFEncryptorR6::getEncryptedAccessPermissions(std::vector<sal_uInt8>& rKey) { - std::vector<sal_uInt8> aPerms = createPerms(m_nAccessPermissions, false); + std::vector<sal_uInt8> aPerms = createPerms(m_nAccessPermissions, isMetadataEncrypted()); return encryptPerms(aPerms, rKey); } |