diff options
author | Vasily Melenchuk <vasily.melenchuk@cib.de> | 2019-11-08 17:53:30 +0300 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2020-05-25 10:06:12 +0200 |
commit | aef6106e4c2d956ee89be2a67372de0774d6087f (patch) | |
tree | 71a2ed10796e3dbd76bc8cad401343d3cbd51438 /sc | |
parent | c6665a0fc8cdad31160daad65c10894cd3174584 (diff) |
calc: add XPackageEncryption support for binary xls
This adds read support for API-based MS-CRYPTO algos.
DRM encryption is implemented as a service and desrption
will be called if we found corresponding streams inside
binary OLE package.
Change-Id: Ie580e5c12c48ccf99f9a932b1c66eb35866b7ef4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/84439
Tested-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Diffstat (limited to 'sc')
-rw-r--r-- | sc/source/filter/excel/excel.cxx | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/sc/source/filter/excel/excel.cxx b/sc/source/filter/excel/excel.cxx index 386342988060..40f320cf530e 100644 --- a/sc/source/filter/excel/excel.cxx +++ b/sc/source/filter/excel/excel.cxx @@ -24,7 +24,9 @@ #include <sot/exchange.hxx> #include <filter/msfilter/classids.hxx> #include <tools/globname.hxx> +#include <com/sun/star/packages/XPackageEncryption.hpp> #include <com/sun/star/ucb/ContentCreationException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> #include <unotools/streamwrap.hxx> #include <unotools/defaultencoding.hxx> #include <unotools/wincodepage.hxx> @@ -34,6 +36,8 @@ #include <xistream.hxx> #include <xltools.hxx> #include <docoptio.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <comphelper/processfactory.hxx> #include <docsh.hxx> #include <scerrors.hxx> @@ -44,6 +48,99 @@ #include <memory> +using namespace css; + +static void lcl_getListOfStreams(SotStorage * pStorage, comphelper::SequenceAsHashMap& aStreamsData, const OUString& sPrefix) +{ + SvStorageInfoList aElements; + pStorage->FillInfoList(&aElements); + for (const auto & aElement : aElements) + { + OUString sStreamFullName = sPrefix.getLength() ? sPrefix + "/" + aElement.GetName() : aElement.GetName(); + if (aElement.IsStorage()) + { + SotStorage * pSubStorage = pStorage->OpenSotStorage(aElement.GetName(), StreamMode::STD_READ | StreamMode::SHARE_DENYALL); + lcl_getListOfStreams(pSubStorage, aStreamsData, sStreamFullName); + } + else + { + // Read stream + tools::SvRef<SotStorageStream> rStream = pStorage->OpenSotStream(aElement.GetName(), StreamMode::READ | StreamMode::SHARE_DENYALL); + if (rStream.is()) + { + sal_Int32 nStreamSize = rStream->GetSize(); + uno::Sequence< sal_Int8 > oData; + oData.realloc(nStreamSize); + sal_Int32 nReadBytes = rStream->ReadBytes(oData.getArray(), nStreamSize); + if (nStreamSize == nReadBytes) + aStreamsData[sStreamFullName] <<= oData; + } + } + } +} + +static tools::SvRef<SotStorage> lcl_DRMDecrypt(SfxMedium& rMedium, tools::SvRef<SotStorage>& rStorage, std::shared_ptr<SvStream>& rNewStorageStrm) +{ + tools::SvRef<SotStorage> aNewStorage; + + // We have DRM encrypted storage. We should try to decrypt it first, if we can + uno::Sequence< uno::Any > aArguments; + uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); + uno::Reference< packages::XPackageEncryption > xPackageEncryption( + xComponentContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.oox.crypto.DRMDataSpace", aArguments, xComponentContext), uno::UNO_QUERY); + + if (!xPackageEncryption.is()) + { + // We do not know how to decrypt this + return aNewStorage; + } + + comphelper::SequenceAsHashMap aStreamsData; + lcl_getListOfStreams(rStorage.get(), aStreamsData, ""); + + try { + uno::Sequence<beans::NamedValue> aStreams = aStreamsData.getAsConstNamedValueList(); + if (!xPackageEncryption->readEncryptionInfo(aStreams)) + { + // We failed with decryption + return aNewStorage; + } + + tools::SvRef<SotStorageStream> rContentStream = rStorage->OpenSotStream("\011DRMContent", StreamMode::READ | StreamMode::SHARE_DENYALL); + if (!rContentStream.is()) + { + return aNewStorage; + } + + rNewStorageStrm = std::make_shared<SvMemoryStream>(); + + uno::Reference<io::XInputStream > xInputStream(new utl::OSeekableInputStreamWrapper(rContentStream.get(), false)); + uno::Reference<io::XOutputStream > xDecryptedStream(new utl::OSeekableOutputStreamWrapper(*rNewStorageStrm)); + + if (!xPackageEncryption->decrypt(xInputStream, xDecryptedStream)) + { + // We failed with decryption + return aNewStorage; + } + + rNewStorageStrm->Seek(0); + + // Further reading is done from new document + aNewStorage = new SotStorage(*rNewStorageStrm); + + // Set the media descriptor data + uno::Sequence<beans::NamedValue> aEncryptionData = xPackageEncryption->createEncryptionData(""); + rMedium.GetItemSet()->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, uno::makeAny(aEncryptionData))); + } + catch (const std::exception&) + { + return aNewStorage; + } + + return aNewStorage; +} + ErrCode ScFormatFilterPluginImpl::ScImportExcel( SfxMedium& rMedium, ScDocument* pDocument, const EXCIMPFORMAT eFormat ) { // check the passed Calc document @@ -69,6 +166,7 @@ ErrCode ScFormatFilterPluginImpl::ScImportExcel( SfxMedium& rMedium, ScDocument* // try to open an OLE storage tools::SvRef<SotStorage> xRootStrg; tools::SvRef<SotStorageStream> xStrgStrm; + std::shared_ptr<SvStream> aNewStorageStrm; if( SotStorage::IsStorageFile( pMedStrm ) ) { xRootStrg = new SotStorage( pMedStrm, false ); @@ -79,6 +177,13 @@ ErrCode ScFormatFilterPluginImpl::ScImportExcel( SfxMedium& rMedium, ScDocument* // try to open "Book" or "Workbook" stream in OLE storage if( xRootStrg.is() ) { + // Check if there is DRM encryption in storage + tools::SvRef<SotStorageStream> xDRMStrm = ScfTools::OpenStorageStreamRead(xRootStrg, "\011DRMContent"); + if (xDRMStrm.is()) + { + xRootStrg = lcl_DRMDecrypt(rMedium, xRootStrg, aNewStorageStrm); + } + // try to open the "Book" stream tools::SvRef<SotStorageStream> xBookStrm = ScfTools::OpenStorageStreamRead( xRootStrg, EXC_STREAM_BOOK ); XclBiff eBookBiff = xBookStrm.is() ? XclImpStream::DetectBiffVersion( *xBookStrm ) : EXC_BIFF_UNKNOWN; |