vcl/inc/pdf/COSWriter.hxx         |   14 ++++-
 vcl/inc/pdf/IPDFEncryptor.hxx     |    1 
 vcl/inc/pdf/PDFEncryptor.hxx      |    1 
 vcl/inc/pdf/PDFEncryptorR6.hxx    |    1 
 vcl/source/gdi/pdfwriter_impl.cxx |  106 +++++++++++++++++++++-----------------
 vcl/source/pdf/PDFEncryptorR6.cxx |    2 
 6 files changed, 76 insertions(+), 49 deletions(-)

New commits:
commit 0755af3f73fafccbbe4034988a8789f00fc604af
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Fri Nov 22 23:46:29 2024 +0900
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Dec 16 12:29:16 2024 +0100

    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 <vmik...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

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(">>
"); }
 
+    void startStream() { maLine.append("stream
"); }
+    void endStream() { maLine.append("
endstream
"); }
+
     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 f37ece808362..46466da33a3c 100644
--- a/vcl/inc/pdf/IPDFEncryptor.hxx
+++ b/vcl/inc/pdf/IPDFEncryptor.hxx
@@ -53,6 +53,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 d8465d80c233..8862c0fa0f2d 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 a76ca07f8035..4746b53fdc0f 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -5572,9 +5572,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( ">>
"
@@ -5970,52 +5970,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
" );
-
-        aMetadataObj.append( "<</Type/Metadata/Subtype/XML/Length " );
-
-        aMetadataObj.append( sal_Int32(aMetadata.getSize()) );
-        aMetadataObj.append( ">>
stream
" );
-        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( "
endstream
endobj

" ) )
-            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;
 }
@@ -6055,7 +6067,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);
 }
 

Reply via email to