diff options
-rw-r--r-- | comphelper/source/misc/docpasswordhelper.cxx | 42 | ||||
-rw-r--r-- | package/source/xstor/owriteablestream.cxx | 8 | ||||
-rw-r--r-- | package/source/xstor/owriteablestream.hxx | 3 | ||||
-rw-r--r-- | package/source/xstor/xstorage.cxx | 2 | ||||
-rw-r--r-- | sfx2/source/appl/appopen.cxx | 16 |
5 files changed, 65 insertions, 6 deletions
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 ); |