comphelper/source/misc/docpasswordhelper.cxx |   68 +++++++++++++++++++++++++--
 package/source/xstor/owriteablestream.cxx    |    8 +--
 package/source/xstor/owriteablestream.hxx    |    3 -
 package/source/xstor/xstorage.cxx            |    2 
 sfx2/source/appl/appopen.cxx                 |   12 ++++
 sfx2/source/dialog/filedlghelper.cxx         |   18 ++++---
 6 files changed, 97 insertions(+), 14 deletions(-)

New commits:
commit ee373c60c8dbdff64a71b6d288f937b296015e36
Author:     Mike Kaganski <[email protected]>
AuthorDate: Fri Jan 3 22:40:07 2020 +0300
Commit:     Thorsten Behrens <[email protected]>
CommitDate: Sun Feb 9 11:33:27 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 <[email protected]>
    Tested-by: Mike Kaganski <[email protected]>
    (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..0c332230e555 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,22 @@ 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
+            aEncData = comphelper::concatSequences(
+                aEncData, comphelper::InitPropertySequence({
+                              { "STD97EncryptionKey", css::uno::Any(aEnc97Key) 
},
+                              { "STD97UniqueID", css::uno::Any(aUniqueID) },
+                              { "OOXPassword", css::uno::Any(aPassword) },
+                          }));
+        }
     }
 
     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..a32c61479169 100644
--- a/sfx2/source/appl/appopen.cxx
+++ b/sfx2/source/appl/appopen.cxx
@@ -240,6 +240,18 @@ 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)
+                            {
+                                aEncryptionData = comphelper::concatSequences(
+                                    aEncryptionData, 
std::initializer_list<beans::NamedValue>{
+                                                         { "ForSalvage", 
css::uno::Any(true) } });
+                            }
+
                             SfxDocPasswordVerifier aVerifier( xStorage );
                             aEncryptionData = 
::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
                                 aVerifier, aEncryptionData, aPassword, 
xInteractionHandler, pFile->GetOrigURL(), 
comphelper::DocPasswordRequestType::Standard );
commit f6f23f7b82e90fa64e4bcd305ec72bab945801d5
Author:     Mike Kaganski <[email protected]>
AuthorDate: Fri Nov 29 13:07:57 2019 +0300
Commit:     Thorsten Behrens <[email protected]>
CommitDate: Sun Feb 9 11:33:16 2020 +0100

    tdf#118639: store ODF encryption data for autorecovery
    
    When saving autorecovery information, ODF is used. If the original
    document is password-protected, its autorecovery is also generated
    password-protected (since ef87ff6680f79362a431db6e7ef2f40cfc576219).
    But when the stored encryption data for non-ODF document does not
    contain "PackageSHA256UTF8EncryptionKey" value, following
    ZipPackage::GetEncryptionKey fails, so the whole save fails.
    
    So just generate and append ODF encryption keys where we still have
    user password.
    
    Reviewed-on: https://gerrit.libreoffice.org/84052
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>
    (cherry picked from commit 63634738dd03cc74806ce6843c16ff5e51a371a0)
    Reviewed-on: https://gerrit.libreoffice.org/84133
    Reviewed-by: Xisco FaulĂ­ <[email protected]>
    (cherry picked from commit e569dc9824e95617d921bb8f115d243aea0125b9)
    Reviewed-on: https://gerrit.libreoffice.org/84232
    Reviewed-by: Adolfo Jayme Barrientos <[email protected]>
    (cherry picked from commit d1450f5bddd0f108078e0dfb11c9f130175fafe7)
    
    Conflicts:
            comphelper/source/misc/docpasswordhelper.cxx
    
    Change-Id: I776e28de784489521e4941d1075690f90c056014

diff --git a/comphelper/source/misc/docpasswordhelper.cxx 
b/comphelper/source/misc/docpasswordhelper.cxx
index 3f470520fbf5..f75997cfe440 100644
--- a/comphelper/source/misc/docpasswordhelper.cxx
+++ b/comphelper/source/misc/docpasswordhelper.cxx
@@ -426,6 +426,7 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
         bool* pbIsDefaultPassword )
 {
     css::uno::Sequence< css::beans::NamedValue > aEncData;
+    OUString aPassword;
     DocPasswordVerifierResult eResult = 
DocPasswordVerifierResult::WrongPassword;
 
     // first, try provided default passwords
@@ -439,8 +440,12 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
             if( !aIt->isEmpty() )
             {
                 eResult = rVerifier.verifyPassword( *aIt, aEncData );
-                if( pbIsDefaultPassword )
-                    *pbIsDefaultPassword = eResult == 
DocPasswordVerifierResult::OK;
+                if (eResult == DocPasswordVerifierResult::OK)
+                {
+                    aPassword = *aIt;
+                    if (pbIsDefaultPassword)
+                        *pbIsDefaultPassword = true;
+                }
             }
         }
     }
@@ -460,7 +465,11 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
     if( eResult == DocPasswordVerifierResult::WrongPassword )
     {
         if( !rMediaPassword.isEmpty() )
+        {
             eResult = rVerifier.verifyPassword( rMediaPassword, aEncData );
+            if (eResult == DocPasswordVerifierResult::OK)
+                aPassword = rMediaPassword;
+        }
     }
 
     // request a password (skip, if result is OK or ABORT)
@@ -476,6 +485,8 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
             {
                 if( !pRequest->getPassword().isEmpty() )
                     eResult = rVerifier.verifyPassword( 
pRequest->getPassword(), aEncData );
+                if (eResult == DocPasswordVerifierResult::OK)
+                    aPassword = pRequest->getPassword();
             }
             else
             {
@@ -488,6 +499,21 @@ OUString DocPasswordHelper::GetOoxHashAsBase64(
     {
     }
 
+    if (eResult == DocPasswordVerifierResult::OK && !aPassword.isEmpty())
+    {
+        if (std::find_if(std::cbegin(aEncData), std::cend(aEncData),
+                         [](const css::beans::NamedValue& val) {
+                             return val.Name == 
PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
+                         })
+            == std::cend(aEncData))
+        {
+            // tdf#118639: We need ODF encryption data for autorecovery, where 
password
+            // will already be unavailable, so generate and append it here
+            aEncData = comphelper::concatSequences(
+                aEncData, 
OStorageHelper::CreatePackageEncryptionData(aPassword));
+        }
+    }
+
     return (eResult == DocPasswordVerifierResult::OK) ? aEncData : 
uno::Sequence< beans::NamedValue >();
 }
 
diff --git a/sfx2/source/dialog/filedlghelper.cxx 
b/sfx2/source/dialog/filedlghelper.cxx
index 5e4055195eb5..eaf7f484ae85 100644
--- a/sfx2/source/dialog/filedlghelper.cxx
+++ b/sfx2/source/dialog/filedlghelper.cxx
@@ -2704,6 +2704,8 @@ ErrCode RequestPassword(const std::shared_ptr<const 
SfxFilter>& pCurrentFilter,
     {
         if ( pPasswordRequest->getPassword().getLength() )
         {
+            css::uno::Sequence< css::beans::NamedValue > aEncryptionData;
+
             // TODO/LATER: The filters should show the password dialog 
themself in future
             if ( bMSType )
             {
@@ -2712,7 +2714,7 @@ ErrCode RequestPassword(const std::shared_ptr<const 
SfxFilter>& pCurrentFilter,
                 {
                     ::comphelper::SequenceAsHashMap aHashData;
                     aHashData[ OUString( "OOXPassword"  ) ] <<= 
pPasswordRequest->getPassword();
-                    pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, 
uno::makeAny( aHashData.getAsConstNamedValueList() ) ) );
+                    aEncryptionData = aHashData.getAsConstNamedValueList();
                 }
                 else
                 {
@@ -2725,7 +2727,7 @@ ErrCode RequestPassword(const std::shared_ptr<const 
SfxFilter>& pCurrentFilter,
                         aHashData[ OUString( "STD97EncryptionKey"  ) ] <<= 
aEncryptionKey;
                         aHashData[ OUString( "STD97UniqueID"  ) ] <<= 
aUniqueID;
 
-                        pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, 
uno::makeAny( aHashData.getAsConstNamedValueList() ) ) );
+                        aEncryptionData = aHashData.getAsConstNamedValueList();
                     }
                     else
                     {
@@ -2733,10 +2735,14 @@ ErrCode RequestPassword(const std::shared_ptr<const 
SfxFilter>& pCurrentFilter,
                     }
                 }
             }
-            else
-            {
-                pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( 
::comphelper::OStorageHelper::CreatePackageEncryptionData( 
pPasswordRequest->getPassword() ) ) ) );
-            }
+
+            // tdf#118639: We need ODF encryption data for autorecovery where 
password will already
+            // be unavailable, even for non-ODF documents, so append it here 
unconditionally
+            pSet->Put(SfxUnoAnyItem(
+                SID_ENCRYPTIONDATA,
+                uno::makeAny(comphelper::concatSequences(
+                    aEncryptionData, 
comphelper::OStorageHelper::CreatePackageEncryptionData(
+                                         pPasswordRequest->getPassword())))));
         }
 
         if ( pPasswordRequest->getRecommendReadOnly() )
_______________________________________________
Libreoffice-commits mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to