[Libreoffice-commits] core.git: Branch 'distro/cib/libreoffice-6-1' - comphelper/source package/source sfx2/source

Mike Kaganski (via logerrit) logerrit at kemper.freedesktop.org
Sun Feb 9 14:20:13 UTC 2020


Rebased ref, commits from common ancestor:
commit 5b6c866d522e7eef636a5fa4048c39c1ea60e466
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Fri Jan 3 22:40:07 2020 +0300
Commit:     Thorsten Behrens <Thorsten.Behrens at CIB.de>
CommitDate: Sun Feb 9 15:19:00 2020 +0100

    tdf#93389: keep encryption information for autorecovered MS formats
    
    The autorecovery data is stored in ODF, regardless of the original
    document format. When restoring, type detection generates ODF data,
    which is stored in the media descriptor attached to document, even
    after real filter was restored (see AutoRecovery::implts_openDocs).
    If real filter is not ODF, then at the save time, it doesn't find
    necessary information in encryption data, and makes not encrypted
    package.
    
    This patch adds both MS binary data, and OOXML data, to existing
    ODF data for recovered password-protected documents (regardless of
    their real filter).
    
    TODO: only add required information to encryption data: pass real
    filter name to DocPasswordHelper::requestAndVerifyDocPassword from
    AutoRecovery::implts_openDocs.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86201
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    Tested-by: Mike Kaganski <mike.kaganski at collabora.com>
    (cherry picked from commit dd198398b6e5c84ab1255a90ef96e6445b66a64f)
    
    Conflicts:
            comphelper/source/misc/docpasswordhelper.cxx
    
    Change-Id: I4717f067ad3c40167312b99eefef5584a467bfed
    (cherry picked from commit 6017cdff264afc3b98beeba1330d6df28102fe7a)

diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx
index f75997cfe440..1a4f29755c36 100644
--- a/comphelper/source/misc/docpasswordhelper.cxx
+++ b/comphelper/source/misc/docpasswordhelper.cxx
@@ -25,6 +25,7 @@
 #include <comphelper/storagehelper.hxx>
 #include <comphelper/hash.hxx>
 #include <comphelper/base64.hxx>
+#include <comphelper/propertysequence.hxx>
 #include <comphelper/sequence.hxx>
 #include <com/sun/star/beans/PropertyValue.hpp>
 #include <com/sun/star/task/XInteractionHandler.hpp>
@@ -429,6 +430,25 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
     OUString aPassword;
     DocPasswordVerifierResult eResult = DocPasswordVerifierResult::WrongPassword;
 
+    sal_Int32 nMediaEncDataCount = rMediaEncData.getLength();
+
+    // tdf#93389: if the document is being restored from autorecovery, we need to add encryption
+    // data also for real document type.
+    // TODO: get real filter name here (from CheckPasswd_Impl), to only add necessary data
+    bool bForSalvage = false;
+    if (nMediaEncDataCount)
+    {
+        for (auto& val : rMediaEncData)
+        {
+            if (val.Name == "ForSalvage")
+            {
+                --nMediaEncDataCount; // don't consider this element below
+                val.Value >>= bForSalvage;
+                break;
+            }
+        }
+    }
+
     // first, try provided default passwords
     if( pbIsDefaultPassword )
         *pbIsDefaultPassword = false;
@@ -453,7 +473,7 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
     // try media encryption data (skip, if result is OK or ABORT)
     if( eResult == DocPasswordVerifierResult::WrongPassword )
     {
-        if( rMediaEncData.getLength() > 0 )
+        if (nMediaEncDataCount)
         {
             eResult = rVerifier.verifyEncryptionData( rMediaEncData );
             if( eResult == DocPasswordVerifierResult::OK )
@@ -512,6 +532,26 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
             aEncData = comphelper::concatSequences(
                 aEncData, OStorageHelper::CreatePackageEncryptionData(aPassword));
         }
+
+        if (bForSalvage)
+        {
+            // TODO: add individual methods for different target filter, and only call what's needed
+
+            // 1. Prepare binary MS formats encryption data
+            auto aUniqueID = GenerateRandomByteSequence(16);
+            auto aEnc97Key = GenerateStd97Key(aPassword.getStr(), aUniqueID);
+            // 2. Add MS binary and OOXML encryption data to result
+            uno::Sequence< beans::NamedValue > aContainer(3);
+            aContainer[0].Name = "STD97EncryptionKey";
+            aContainer[0].Value <<= aEnc97Key;
+            aContainer[1].Name = "STD97UniqueID";
+            aContainer[1].Value <<= aUniqueID;
+            aContainer[2].Name = "OOXPassword";
+            aContainer[2].Value <<= aPassword;
+
+            aEncData = comphelper::concatSequences(
+                aEncData, aContainer);
+        }
     }
 
     return (eResult == DocPasswordVerifierResult::OK) ? aEncData : uno::Sequence< beans::NamedValue >();
diff --git a/package/source/xstor/owriteablestream.cxx b/package/source/xstor/owriteablestream.cxx
index 2f49e497dd47..19e28e9dcb33 100644
--- a/package/source/xstor/owriteablestream.cxx
+++ b/package/source/xstor/owriteablestream.cxx
@@ -79,9 +79,11 @@ struct WSInternalData_Impl
 namespace package
 {
 
-bool PackageEncryptionDatasEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 )
+bool PackageEncryptionDataLessOrEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 )
 {
-    bool bResult = !aHash1.empty() && aHash1.size() == aHash2.size();
+    // tdf#93389: aHash2 may contain more than in aHash1, if it contains also data for other package
+    // formats (as in case of autorecovery)
+    bool bResult = !aHash1.empty() && aHash1.size() <= aHash2.size();
     for ( ::comphelper::SequenceAsHashMap::const_iterator aIter = aHash1.begin();
           bResult && aIter != aHash1.end();
           ++aIter )
@@ -1160,7 +1162,7 @@ uno::Reference< io::XStream > OWriteStream_Impl::GetStream( sal_Int32 nStreamMod
 
     if ( m_bHasCachedEncryptionData )
     {
-        if ( !::package::PackageEncryptionDatasEqual( m_aEncryptionData, aEncryptionData ) )
+        if ( !::package::PackageEncryptionDataLessOrEqual( m_aEncryptionData, aEncryptionData ) )
             throw packages::WrongPasswordException();
 
         // the correct key must be set already
diff --git a/package/source/xstor/owriteablestream.hxx b/package/source/xstor/owriteablestream.hxx
index e3eeaf09d4fd..5501d6a4df47 100644
--- a/package/source/xstor/owriteablestream.hxx
+++ b/package/source/xstor/owriteablestream.hxx
@@ -55,7 +55,8 @@ namespace com { namespace sun { namespace star { namespace uno {
 } } } }
 
 namespace package {
-    bool PackageEncryptionDatasEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 );
+    // all data in aHash1 is contained in aHash2
+    bool PackageEncryptionDataLessOrEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 );
 }
 
 struct WSInternalData_Impl;
diff --git a/package/source/xstor/xstorage.cxx b/package/source/xstor/xstorage.cxx
index 0a43a07869f9..1725b1627762 100644
--- a/package/source/xstor/xstorage.cxx
+++ b/package/source/xstor/xstorage.cxx
@@ -857,7 +857,7 @@ void OStorage_Impl::CopyStorageElement( SotElement_Impl* pElement,
                 SAL_INFO("package.xstor", "No Encryption: " << rNoEncryptionException);
             }
 
-            if (bHasCommonEncryptionData && ::package::PackageEncryptionDatasEqual(pElement->m_xStream->GetCachedEncryptionData(), aCommonEncryptionData))
+            if (bHasCommonEncryptionData && ::package::PackageEncryptionDataLessOrEqual(pElement->m_xStream->GetCachedEncryptionData(), aCommonEncryptionData))
             {
                 // If the stream can be opened with the common storage password
                 // it must be stored with the common storage password as well
diff --git a/sfx2/source/appl/appopen.cxx b/sfx2/source/appl/appopen.cxx
index 47ba55e34947..bea5aba9fe4d 100644
--- a/sfx2/source/appl/appopen.cxx
+++ b/sfx2/source/appl/appopen.cxx
@@ -44,6 +44,7 @@
 #include <comphelper/processfactory.hxx>
 #include <comphelper/storagehelper.hxx>
 #include <comphelper/string.hxx>
+#include <comphelper/sequence.hxx>
 #include <comphelper/synchronousdispatch.hxx>
 
 #include <vcl/wrkwin.hxx>
@@ -240,6 +241,21 @@ ErrCode CheckPasswd_Impl
                             if ( !aEncryptionData.hasElements() && aGpgProperties.hasElements() )
                                 aEncryptionData = ::comphelper::DocPasswordHelper::decryptGpgSession(aGpgProperties);
 
+                            // tdf#93389: if recoverying a document, encryption data should contain
+                            // entries for the real filter, not only for recovery ODF, to keep it
+                            // encrypted. Pass this in encryption data.
+                            // TODO: pass here the real filter (from AutoRecovery::implts_openDocs)
+                            // to marshal this to requestAndVerifyDocPassword
+                            if (pSet->GetItemState(SID_DOC_SALVAGE, false) == SfxItemState::SET)
+                            {
+                                uno::Sequence< beans::NamedValue > aContainer(1);
+                                aContainer[0].Name = "ForSalvage";
+                                aContainer[0].Value <<= true;
+
+                                aEncryptionData = comphelper::concatSequences(
+                                    aEncryptionData, aContainer);
+                            }
+
                             SfxDocPasswordVerifier aVerifier( xStorage );
                             aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
                                 aVerifier, aEncryptionData, aPassword, xInteractionHandler, pFile->GetOrigURL(), comphelper::DocPasswordRequestType::Standard );


More information about the Libreoffice-commits mailing list