comphelper/source/misc/docpasswordhelper.cxx | 41 ++++++++++++++++++++++++++- package/source/xstor/owriteablestream.cxx | 8 +++-- package/source/xstor/owriteablestream.hxx | 3 + package/source/xstor/xstorage.cxx | 2 - sfx2/source/appl/appopen.cxx | 16 ++++++++++ 5 files changed, 64 insertions(+), 6 deletions(-)
New commits: commit b6809c72b509fcc223c80595d554902a1b4f4e24 Author: Mike Kaganski <[email protected]> AuthorDate: Fri Jan 3 22:40:07 2020 +0300 Commit: Samuel Mehrbrodt <[email protected]> CommitDate: Mon Feb 10 16:36:22 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 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88330 Tested-by: Jenkins Reviewed-by: Samuel Mehrbrodt <[email protected]> diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx index af3741347344..630f59535f37 100644 --- a/comphelper/source/misc/docpasswordhelper.cxx +++ b/comphelper/source/misc/docpasswordhelper.cxx @@ -425,6 +425,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; @@ -451,7 +470,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 ) @@ -510,6 +529,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 b9ea32c3ed70..8ea05ac945a9 100644 --- a/package/source/xstor/owriteablestream.cxx +++ b/package/source/xstor/owriteablestream.cxx @@ -81,9 +81,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 ) @@ -1161,7 +1163,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 629d679fdccf..35e85595318c 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 ec8275ae445d..0eb39c65daff 100644 --- a/package/source/xstor/xstorage.cxx +++ b/package/source/xstor/xstorage.cxx @@ -860,7 +860,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 592fd4b28a16..7d1ad8c16639 100644 --- a/sfx2/source/appl/appopen.cxx +++ b/sfx2/source/appl/appopen.cxx @@ -44,6 +44,7 @@ #include <rtl/ustring.hxx> #include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> #include <comphelper/storagehelper.hxx> #include <comphelper/synchronousdispatch.hxx> @@ -243,6 +244,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 ); _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
