diff options
Diffstat (limited to 'oox')
-rw-r--r-- | oox/Library_oox.mk | 1 | ||||
-rw-r--r-- | oox/qa/unit/CryptoTest.cxx | 46 | ||||
-rw-r--r-- | oox/source/core/filterdetect.cxx | 20 | ||||
-rw-r--r-- | oox/source/core/xmlfilterbase.cxx | 19 | ||||
-rw-r--r-- | oox/source/crypto/AgileEngine.cxx | 10 | ||||
-rw-r--r-- | oox/source/crypto/CryptTools.cxx | 4 | ||||
-rw-r--r-- | oox/source/crypto/DocumentDecryption.cxx | 185 | ||||
-rw-r--r-- | oox/source/crypto/DocumentEncryption.cxx | 72 | ||||
-rw-r--r-- | oox/source/crypto/Standard2007Engine.cxx | 6 | ||||
-rw-r--r-- | oox/source/crypto/StrongEncryptionDataSpace.cxx | 206 | ||||
-rw-r--r-- | oox/util/oox.component | 4 |
11 files changed, 450 insertions, 123 deletions
diff --git a/oox/Library_oox.mk b/oox/Library_oox.mk index cc235b87e360..3d8b46b2a24b 100644 --- a/oox/Library_oox.mk +++ b/oox/Library_oox.mk @@ -102,6 +102,7 @@ $(eval $(call gb_Library_add_exception_objects,oox,\ oox/source/crypto/DocumentEncryption \ oox/source/crypto/DocumentDecryption \ oox/source/crypto/Standard2007Engine \ + oox/source/crypto/StrongEncryptionDataSpace \ oox/source/docprop/docprophandler \ oox/source/docprop/ooxmldocpropimport \ oox/source/drawingml/chart/axiscontext \ diff --git a/oox/qa/unit/CryptoTest.cxx b/oox/qa/unit/CryptoTest.cxx index e1a4781d234c..c4058619e5c9 100644 --- a/oox/qa/unit/CryptoTest.cxx +++ b/oox/qa/unit/CryptoTest.cxx @@ -66,7 +66,7 @@ void CryptoTest::testCryptoHash() aContentString.getStr() + aContentString.getLength()); std::vector<sal_uInt8> aKey = { 'k', 'e', 'y' }; { - oox::core::CryptoHash aCryptoHash(aKey, oox::core::CryptoHashType::SHA1); + oox::crypto::CryptoHash aCryptoHash(aKey, oox::crypto::CryptoHashType::SHA1); aCryptoHash.update(aContent); std::vector<sal_uInt8> aHash = aCryptoHash.finalize(); CPPUNIT_ASSERT_EQUAL(std::string("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"), @@ -74,7 +74,7 @@ void CryptoTest::testCryptoHash() } { - oox::core::CryptoHash aCryptoHash(aKey, oox::core::CryptoHashType::SHA256); + oox::crypto::CryptoHash aCryptoHash(aKey, oox::crypto::CryptoHashType::SHA256); aCryptoHash.update(aContent); std::vector<sal_uInt8> aHash = aCryptoHash.finalize(); CPPUNIT_ASSERT_EQUAL( @@ -83,7 +83,7 @@ void CryptoTest::testCryptoHash() } { - oox::core::CryptoHash aCryptoHash(aKey, oox::core::CryptoHashType::SHA512); + oox::crypto::CryptoHash aCryptoHash(aKey, oox::crypto::CryptoHashType::SHA512); aCryptoHash.update(aContent); std::vector<sal_uInt8> aHash = aCryptoHash.finalize(); CPPUNIT_ASSERT_EQUAL( @@ -95,18 +95,18 @@ void CryptoTest::testCryptoHash() void CryptoTest::testRoundUp() { - CPPUNIT_ASSERT_EQUAL(16, oox::core::roundUp(16, 16)); - CPPUNIT_ASSERT_EQUAL(32, oox::core::roundUp(32, 16)); - CPPUNIT_ASSERT_EQUAL(64, oox::core::roundUp(64, 16)); + CPPUNIT_ASSERT_EQUAL(16, oox::crypto::roundUp(16, 16)); + CPPUNIT_ASSERT_EQUAL(32, oox::crypto::roundUp(32, 16)); + CPPUNIT_ASSERT_EQUAL(64, oox::crypto::roundUp(64, 16)); - CPPUNIT_ASSERT_EQUAL(16, oox::core::roundUp(01, 16)); - CPPUNIT_ASSERT_EQUAL(32, oox::core::roundUp(17, 16)); - CPPUNIT_ASSERT_EQUAL(32, oox::core::roundUp(31, 16)); + CPPUNIT_ASSERT_EQUAL(16, oox::crypto::roundUp(01, 16)); + CPPUNIT_ASSERT_EQUAL(32, oox::crypto::roundUp(17, 16)); + CPPUNIT_ASSERT_EQUAL(32, oox::crypto::roundUp(31, 16)); } void CryptoTest::testStandard2007() { - oox::core::Standard2007Engine aEngine; + oox::crypto::Standard2007Engine aEngine; { aEngine.setupEncryption("Password"); @@ -173,7 +173,7 @@ void CryptoTest::testStandard2007() void CryptoTest::testAgileEncryptionVerifier() { - oox::core::AgileEngine aEngine; + oox::crypto::AgileEngine aEngine; OUString aPassword("Password"); @@ -200,9 +200,9 @@ void CryptoTest::testAgileEncrpytionInfoWritingAndParsing() { // Preset AES128 - SHA1 SvMemoryStream aEncryptionInfo; { - oox::core::AgileEngine aEngine; + oox::crypto::AgileEngine aEngine; - aEngine.setPreset(oox::core::AgileEncryptionPreset::AES_128_SHA1); + aEngine.setPreset(oox::crypto::AgileEncryptionPreset::AES_128_SHA1); aEngine.setupEncryption(aPassword); aKeyDataSalt = aEngine.getInfo().keyDataSalt; @@ -218,7 +218,7 @@ void CryptoTest::testAgileEncrpytionInfoWritingAndParsing() aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN); { - oox::core::AgileEngine aEngine; + oox::crypto::AgileEngine aEngine; uno::Reference<io::XInputStream> xInputStream( new utl::OSeekableInputStreamWrapper(aEncryptionInfo)); @@ -227,7 +227,7 @@ void CryptoTest::testAgileEncrpytionInfoWritingAndParsing() CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream)); - oox::core::AgileEncryptionInfo& rInfo = aEngine.getInfo(); + oox::crypto::AgileEncryptionInfo& rInfo = aEngine.getInfo(); CPPUNIT_ASSERT_EQUAL(sal_Int32(100000), rInfo.spinCount); CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.saltSize); CPPUNIT_ASSERT_EQUAL(sal_Int32(128), rInfo.keyBits); @@ -246,9 +246,9 @@ void CryptoTest::testAgileEncrpytionInfoWritingAndParsing() { // Preset AES256 - SHA512 SvMemoryStream aEncryptionInfo; { - oox::core::AgileEngine aEngine; + oox::crypto::AgileEngine aEngine; - aEngine.setPreset(oox::core::AgileEncryptionPreset::AES_256_SHA512); + aEngine.setPreset(oox::crypto::AgileEncryptionPreset::AES_256_SHA512); aEngine.setupEncryption(aPassword); aKeyDataSalt = aEngine.getInfo().keyDataSalt; @@ -264,7 +264,7 @@ void CryptoTest::testAgileEncrpytionInfoWritingAndParsing() aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN); { - oox::core::AgileEngine aEngine; + oox::crypto::AgileEngine aEngine; uno::Reference<io::XInputStream> xInputStream( new utl::OSeekableInputStreamWrapper(aEncryptionInfo)); @@ -273,7 +273,7 @@ void CryptoTest::testAgileEncrpytionInfoWritingAndParsing() CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream)); - oox::core::AgileEncryptionInfo& rInfo = aEngine.getInfo(); + oox::crypto::AgileEncryptionInfo& rInfo = aEngine.getInfo(); CPPUNIT_ASSERT_EQUAL(sal_Int32(100000), rInfo.spinCount); CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.saltSize); CPPUNIT_ASSERT_EQUAL(sal_Int32(256), rInfo.keyBits); @@ -301,7 +301,7 @@ void CryptoTest::testAgileDataIntegrityHmacKey() SvMemoryStream aEncryptionInfo; { - oox::core::AgileEngine aEngine; + oox::crypto::AgileEngine aEngine; aEngine.setupEncryption(aPassword); oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream( new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true); @@ -316,7 +316,7 @@ void CryptoTest::testAgileDataIntegrityHmacKey() aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN); { - oox::core::AgileEngine aEngine; + oox::crypto::AgileEngine aEngine; uno::Reference<io::XInputStream> xInputStream( new utl::OSeekableInputStreamWrapper(aEncryptionInfo)); @@ -346,7 +346,7 @@ void CryptoTest::testAgileEncryptingAndDecrypting() OString aTestString = OUStringToOString("1234567890ABCDEFGH", RTL_TEXTENCODING_UTF8); { - oox::core::AgileEngine aEngine; + oox::crypto::AgileEngine aEngine; // Setup input SvMemoryStream aUnencryptedInput; @@ -381,7 +381,7 @@ void CryptoTest::testAgileEncryptingAndDecrypting() aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN); { - oox::core::AgileEngine aEngine; + oox::crypto::AgileEngine aEngine; // Read encryption info uno::Reference<io::XInputStream> xEncryptionInfo( diff --git a/oox/source/core/filterdetect.cxx b/oox/source/core/filterdetect.cxx index 4a6edbdd7658..0ab68688c9be 100644 --- a/oox/source/core/filterdetect.cxx +++ b/oox/source/core/filterdetect.cxx @@ -276,23 +276,31 @@ bool lclIsZipPackage( const Reference< XComponentContext >& rxContext, const Ref class PasswordVerifier : public IDocPasswordVerifier { public: - explicit PasswordVerifier( DocumentDecryption& aDecryptor ); + explicit PasswordVerifier( crypto::DocumentDecryption& aDecryptor ); virtual DocPasswordVerifierResult verifyPassword( const OUString& rPassword, Sequence<NamedValue>& rEncryptionData ) override; virtual DocPasswordVerifierResult verifyEncryptionData( const Sequence<NamedValue>& rEncryptionData ) override; private: - DocumentDecryption& mDecryptor; + crypto::DocumentDecryption& mDecryptor; }; -PasswordVerifier::PasswordVerifier( DocumentDecryption& aDecryptor ) : +PasswordVerifier::PasswordVerifier( crypto::DocumentDecryption& aDecryptor ) : mDecryptor(aDecryptor) {} comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OUString& rPassword, Sequence<NamedValue>& rEncryptionData ) { - if(mDecryptor.generateEncryptionKey(rPassword)) - rEncryptionData = mDecryptor.createEncryptionData(rPassword); + try + { + if (mDecryptor.generateEncryptionKey(rPassword)) + rEncryptionData = mDecryptor.createEncryptionData(rPassword); + } + catch (...) + { + // Any exception is a reason to abort + return comphelper::DocPasswordVerifierResult::Abort; + } return rEncryptionData.hasElements() ? comphelper::DocPasswordVerifierResult::OK : comphelper::DocPasswordVerifierResult::WrongPassword; } @@ -326,7 +334,7 @@ Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescript { try { - DocumentDecryption aDecryptor(aOleStorage); + crypto::DocumentDecryption aDecryptor(mxContext, aOleStorage); if( aDecryptor.readEncryptionInfo() ) { diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx index 03d68fc232c4..5c5d5e5076e5 100644 --- a/oox/source/core/xmlfilterbase.cxx +++ b/oox/source/core/xmlfilterbase.cxx @@ -881,13 +881,7 @@ Reference<XStream> XmlFilterBase::implGetOutputStream( MediaDescriptor& rMediaDe MediaDescriptor::PROP_ENCRYPTIONDATA(), Sequence< NamedValue >() ); - OUString aPassword; - auto pProp = std::find_if(aMediaEncData.begin(), aMediaEncData.end(), - [](const NamedValue& rProp) { return rProp.Name == "OOXPassword"; }); - if (pProp != aMediaEncData.end()) - pProp->Value >>= aPassword; - - if (aPassword.isEmpty()) + if (aMediaEncData.getLength() == 0) { return FilterBase::implGetOutputStream( rMediaDescriptor ); } @@ -908,20 +902,13 @@ bool XmlFilterBase::implFinalizeExport( MediaDescriptor& rMediaDescriptor ) MediaDescriptor::PROP_ENCRYPTIONDATA(), Sequence< NamedValue >() ); - OUString aPassword; - - auto pProp = std::find_if(aMediaEncData.begin(), aMediaEncData.end(), - [](const NamedValue& rProp) { return rProp.Name == "OOXPassword"; }); - if (pProp != aMediaEncData.end()) - pProp->Value >>= aPassword; - - if (!aPassword.isEmpty()) + if (aMediaEncData.getLength()) { commitStorage(); Reference< XStream> xDocumentStream (FilterBase::implGetOutputStream(rMediaDescriptor)); oox::ole::OleStorage aOleStorage( getComponentContext(), xDocumentStream, true ); - DocumentEncryption encryptor(getMainDocumentStream(), aOleStorage, aPassword); + crypto::DocumentEncryption encryptor( getComponentContext(), getMainDocumentStream(), aOleStorage, aMediaEncData ); bRet = encryptor.encrypt(); if (bRet) aOleStorage.commit(); diff --git a/oox/source/crypto/AgileEngine.cxx b/oox/source/crypto/AgileEngine.cxx index d8c184caa46c..f4eb9d21ea6f 100644 --- a/oox/source/crypto/AgileEngine.cxx +++ b/oox/source/crypto/AgileEngine.cxx @@ -40,7 +40,7 @@ using namespace css::uno; using namespace css::xml::sax; using namespace css::xml; -namespace oox::core { +namespace oox::crypto { namespace { @@ -585,7 +585,7 @@ bool AgileEngine::encryptHmacKey() return false; // Encrypted salt must be multiple of block size - sal_Int32 nEncryptedSaltSize = oox::core::roundUp(mInfo.hashSize, mInfo.blockSize); + sal_Int32 nEncryptedSaltSize = oox::crypto::roundUp(mInfo.hashSize, mInfo.blockSize); // We need to extend hmacSalt to multiple of block size, padding with 0x36 std::vector<sal_uInt8> extendedSalt(mInfo.hmacKey); @@ -759,7 +759,7 @@ void AgileEngine::writeEncryptionInfo(BinaryXOutputStream & rStream) rStream.writeMemory(aMemStream.GetData(), aMemStream.GetSize()); } -void AgileEngine::encrypt(css::uno::Reference<css::io::XInputStream> & rxInputStream, +void AgileEngine::encrypt(const css::uno::Reference<css::io::XInputStream> & rxInputStream, css::uno::Reference<css::io::XOutputStream> & rxOutputStream, sal_uInt32 nSize) { @@ -799,7 +799,7 @@ void AgileEngine::encrypt(css::uno::Reference<css::io::XInputStream> & rxInputS while ((inputLength = aBinaryInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0) { sal_uInt32 correctedInputLength = inputLength % mInfo.blockSize == 0 ? - inputLength : oox::core::roundUp(inputLength, sal_uInt32(mInfo.blockSize)); + inputLength : oox::crypto::roundUp(inputLength, sal_uInt32(mInfo.blockSize)); // Update Key sal_uInt8* segmentBegin = reinterpret_cast<sal_uInt8*>(&nSegment); @@ -822,6 +822,6 @@ void AgileEngine::encrypt(css::uno::Reference<css::io::XInputStream> & rxInputS encryptHmacValue(); } -} // namespace oox::core +} // namespace oox::crypto /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/crypto/CryptTools.cxx b/oox/source/crypto/CryptTools.cxx index cc8c5a925b43..ff11ebbc0436 100644 --- a/oox/source/crypto/CryptTools.cxx +++ b/oox/source/crypto/CryptTools.cxx @@ -24,7 +24,7 @@ #include <pk11pub.h> #endif // USE_TLS_NSS -namespace oox::core { +namespace oox::crypto { #if USE_TLS_OPENSSL struct CryptoImpl @@ -478,6 +478,6 @@ std::vector<sal_uInt8> CryptoHash::finalize() return aHash; } -} // namespace oox::core +} // namespace oox::crypto /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/crypto/DocumentDecryption.cxx b/oox/source/crypto/DocumentDecryption.cxx index 1ed26f4d341c..45b820a89302 100644 --- a/oox/source/crypto/DocumentDecryption.cxx +++ b/oox/source/crypto/DocumentDecryption.cxx @@ -13,26 +13,89 @@ #include <comphelper/sequenceashashmap.hxx> #include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/io/XSeekable.hpp> #include <com/sun/star/io/XStream.hpp> -#include <oox/crypto/AgileEngine.hxx> -#include <oox/crypto/Standard2007Engine.hxx> -#include <oox/helper/binaryinputstream.hxx> -#include <oox/helper/binaryoutputstream.hxx> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/packages/XPackageEncryption.hpp> #include <oox/ole/olestorage.hxx> +#include <oox/helper/binaryinputstream.hxx> +#include <filter/msfilter/mscodec.hxx> + +#include <com/sun/star/task/PasswordRequestMode.hpp> +#include <comphelper/docpasswordrequest.hxx> +#include <comphelper/stillreadwriteinteraction.hxx> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/task/PasswordContainer.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> + +#include <sal/log.hxx> + +namespace { + +void lcl_getListOfStreams(oox::StorageBase* pStorage, std::vector<OUString>& rElementNames) +{ + std::vector< OUString > oElementNames; + pStorage->getElementNames(oElementNames); + for (const auto & sName : oElementNames) + { + oox::StorageRef rSubStorage = pStorage->openSubStorage(sName, false); + if (rSubStorage && rSubStorage->isStorage()) + { + lcl_getListOfStreams(rSubStorage.get(), rElementNames); + } + else + { + if (pStorage->isRootStorage()) + rElementNames.push_back(sName); + else + rElementNames.push_back(pStorage->getPath() + "/" + sName); + } + } +} + +} -namespace oox::core { +namespace oox::crypto { using namespace css; -DocumentDecryption::DocumentDecryption(oox::ole::OleStorage& rOleStorage) : - mrOleStorage(rOleStorage), - mCryptoType(UNKNOWN) -{} +DocumentDecryption::DocumentDecryption(const css::uno::Reference< css::uno::XComponentContext >& rxContext, + oox::ole::OleStorage& rOleStorage) : + mxContext(rxContext), + mrOleStorage(rOleStorage) +{ + // Get OLE streams into sequences for later use in CryptoEngine + std::vector< OUString > aStreamNames; + lcl_getListOfStreams(&mrOleStorage, aStreamNames); + + comphelper::SequenceAsHashMap aStreamsData; + for (const auto & sStreamName : aStreamNames) + { + uno::Reference<io::XInputStream> xStream = mrOleStorage.openInputStream(sStreamName); + if (!xStream.is()) + throw io::IOException( "Cannot open OLE input stream for " + sStreamName + "!" ); + + BinaryXInputStream aBinaryInputStream(xStream, true); + + css::uno::Sequence< sal_Int8 > oData; + sal_Int32 nStreamSize = aBinaryInputStream.size(); + sal_Int32 nReadBytes = aBinaryInputStream.readData(oData, nStreamSize); + + if (nStreamSize != nReadBytes) + { + SAL_WARN("oox", "OLE stream invalid content"); + throw io::IOException( "OLE stream invalid content for " + sStreamName + "!" ); + } + + aStreamsData[sStreamName] <<= oData; + } + maStreamsSequence = aStreamsData.getAsConstNamedValueList(); +} bool DocumentDecryption::generateEncryptionKey(const OUString& rPassword) { - if (mEngine) - return mEngine->generateEncryptionKey(rPassword); + if (mxPackageEncryption.is()) + return mxPackageEncryption->generateEncryptionKey(rPassword); return false; } @@ -41,45 +104,70 @@ bool DocumentDecryption::readEncryptionInfo() if (!mrOleStorage.isStorage()) return false; - uno::Reference<io::XInputStream> xEncryptionInfo = mrOleStorage.openInputStream("EncryptionInfo"); + // Read 0x6DataSpaces/DataSpaceMap + uno::Reference<io::XInputStream> xDataSpaceMap = mrOleStorage.openInputStream("\006DataSpaces/DataSpaceMap"); + OUString sDataSpaceName; - BinaryXInputStream aBinaryInputStream(xEncryptionInfo, true); - sal_uInt32 aVersion = aBinaryInputStream.readuInt32(); + if (xDataSpaceMap.is()) + { + BinaryXInputStream aDataSpaceStream(xDataSpaceMap, true); + sal_uInt32 aHeaderLength = aDataSpaceStream.readuInt32(); + SAL_WARN_IF(aHeaderLength != 8, "oox", "DataSpaceMap length != 8 is not supported. Some content may be skipped"); + sal_uInt32 aEntryCount = aDataSpaceStream.readuInt32(); + SAL_WARN_IF(aEntryCount != 1, "oox", "DataSpaceMap contains more than one entry. Some content may be skipped"); + + // Read each DataSpaceMapEntry (MS-OFFCRYPTO 2.1.6.1) + for (sal_uInt32 i = 0; i < aEntryCount; i++) + { + // entryLen unused for the moment + aDataSpaceStream.skip(sizeof(sal_uInt32)); + + // Read each DataSpaceReferenceComponent (MS-OFFCRYPTO 2.1.6.2) + sal_uInt32 aReferenceComponentCount = aDataSpaceStream.readuInt32(); + for (sal_uInt32 j = 0; j < aReferenceComponentCount; j++) + { + // Read next reference component + // refComponentType unused for the moment + aDataSpaceStream.skip(sizeof(sal_uInt32)); + sal_uInt32 aReferenceComponentNameLength = aDataSpaceStream.readuInt32(); + // sReferenceComponentName unused for the moment + aDataSpaceStream.readUnicodeArray(aReferenceComponentNameLength / 2); + aDataSpaceStream.skip((4 - (aReferenceComponentNameLength & 3)) & 3); // Skip padding + } + + sal_uInt32 aDataSpaceNameLength = aDataSpaceStream.readuInt32(); + sDataSpaceName = aDataSpaceStream.readUnicodeArray(aDataSpaceNameLength / 2); + aDataSpaceStream.skip((4 - (aDataSpaceNameLength & 3)) & 3); // Skip padding + } + } + else + { + // Fallback for documents generated by LO: they sometimes do not have all + // required by MS-OFFCRYPTO specification streams (0x6DataSpaces/DataSpaceMap and others) + SAL_WARN("oox", "Encrypted package does not contain DataSpaceMap"); + sDataSpaceName = "StrongEncryptionDataSpace"; + } - switch (aVersion) + uno::Sequence< uno::Any > aArguments; + mxPackageEncryption.set( + mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.oox.crypto." + sDataSpaceName, aArguments, mxContext), css::uno::UNO_QUERY); + + if (!mxPackageEncryption.is()) { - case msfilter::VERSION_INFO_2007_FORMAT: - case msfilter::VERSION_INFO_2007_FORMAT_SP2: - mCryptoType = STANDARD_2007; // Set encryption info format - mEngine.reset(new Standard2007Engine); - break; - case msfilter::VERSION_INFO_AGILE: - mCryptoType = AGILE; // Set encryption info format - mEngine.reset(new AgileEngine); - break; - default: - break; + // we do not know how to decrypt this document + return false; } - if (mEngine) - return mEngine->readEncryptionInfo(xEncryptionInfo); - return false; + + return mxPackageEncryption->readEncryptionInfo(maStreamsSequence); } uno::Sequence<beans::NamedValue> DocumentDecryption::createEncryptionData(const OUString& rPassword) { - comphelper::SequenceAsHashMap aEncryptionData; + if (!mxPackageEncryption.is()) + return uno::Sequence<beans::NamedValue>(); - if (mCryptoType == AGILE) - { - aEncryptionData["CryptoType"] <<= OUString("Agile"); - } - else if (mCryptoType == STANDARD_2007) - { - aEncryptionData["CryptoType"] <<= OUString("Standard"); - } - - aEncryptionData["OOXPassword"] <<= rPassword; - return aEncryptionData.getAsConstNamedValueList(); + return mxPackageEncryption->createEncryptionData(rPassword); } bool DocumentDecryption::decrypt(const uno::Reference<io::XStream>& xDocumentStream) @@ -89,25 +177,26 @@ bool DocumentDecryption::decrypt(const uno::Reference<io::XStream>& xDocumentStr if (!mrOleStorage.isStorage()) return false; + if (!mxPackageEncryption.is()) + return false; + // open the required input streams in the encrypted package uno::Reference<io::XInputStream> xEncryptedPackage = mrOleStorage.openInputStream("EncryptedPackage"); // create temporary file for unencrypted package uno::Reference<io::XOutputStream> xDecryptedPackage = xDocumentStream->getOutputStream(); - BinaryXOutputStream aDecryptedPackage(xDecryptedPackage, true); - BinaryXInputStream aEncryptedPackage(xEncryptedPackage, true); - bResult = mEngine->decrypt(aEncryptedPackage, aDecryptedPackage); + bResult = mxPackageEncryption->decrypt(xEncryptedPackage, xDecryptedPackage); - xDecryptedPackage->flush(); - aDecryptedPackage.seekToStart(); + css::uno::Reference<io::XSeekable> xSeekable(xDecryptedPackage, css::uno::UNO_QUERY); + xSeekable->seek(0); if (bResult) - return mEngine->checkDataIntegrity(); + return mxPackageEncryption->checkDataIntegrity(); return bResult; } -} // namespace oox::core +} // namespace oox::crypto /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/crypto/DocumentEncryption.cxx b/oox/source/crypto/DocumentEncryption.cxx index 1ea421c8392f..6b88549299a1 100644 --- a/oox/source/crypto/DocumentEncryption.cxx +++ b/oox/source/crypto/DocumentEncryption.cxx @@ -14,58 +14,90 @@ #include <com/sun/star/io/XOutputStream.hpp> #include <com/sun/star/io/XStream.hpp> #include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/packages/XPackageEncryption.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> #include <oox/helper/binaryoutputstream.hxx> #include <oox/ole/olestorage.hxx> +#include <sal/log.hxx> -namespace oox::core { +namespace oox::crypto { using namespace css::io; using namespace css::uno; +using namespace css::beans; -DocumentEncryption::DocumentEncryption(Reference<XStream> const & xDocumentStream, +DocumentEncryption::DocumentEncryption(const Reference< XComponentContext >& rxContext, + Reference<XStream> const & xDocumentStream, oox::ole::OleStorage& rOleStorage, - const OUString& rPassword) - : mxDocumentStream(xDocumentStream) + const Sequence<NamedValue>& rMediaEncData) + : mxContext(rxContext) + , mxDocumentStream(xDocumentStream) , mrOleStorage(rOleStorage) - , maPassword(rPassword) -{} + , mMediaEncData(rMediaEncData) +{ + // Select engine + for (int i = 0; i < rMediaEncData.getLength(); i++) + { + if (rMediaEncData[i].Name == "CryptoType") + { + OUString sCryptoType; + rMediaEncData[i].Value >>= sCryptoType; + + if (sCryptoType == "Standard") + sCryptoType = "StrongEncryptionDataSpace"; + + Sequence<Any> aArguments; + mxPackageEncryption.set( + mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.oox.crypto." + sCryptoType, aArguments, mxContext), css::uno::UNO_QUERY); + + if (!mxPackageEncryption.is()) + { + SAL_WARN("oox", "Requested encryption method \"" << sCryptoType << "\" is not supported"); + } + + break; + } + } +} bool DocumentEncryption::encrypt() { + if (!mxPackageEncryption.is()) + return false; + Reference<XInputStream> xInputStream (mxDocumentStream->getInputStream(), UNO_SET_THROW); Reference<XSeekable> xSeekable(xInputStream, UNO_QUERY); if (!xSeekable.is()) return false; - sal_uInt32 aLength = xSeekable->getLength(); // check length of the stream xSeekable->seek(0); // seek to begin of the document stream if (!mrOleStorage.isStorage()) return false; - mEngine.setupEncryption(maPassword); - - Reference<XOutputStream> xOutputStream(mrOleStorage.openOutputStream("EncryptedPackage"), UNO_SET_THROW); + mxPackageEncryption->setupEncryption(mMediaEncData); - mEngine.encrypt(xInputStream, xOutputStream, aLength); + Sequence<NamedValue> aStreams = mxPackageEncryption->encrypt(xInputStream); - xOutputStream->flush(); - xOutputStream->closeOutput(); + for (const NamedValue & aStream : std::as_const(aStreams)) + { + Reference<XOutputStream> xOutputStream(mrOleStorage.openOutputStream(aStream.Name), UNO_SET_THROW); + BinaryXOutputStream aBinaryOutputStream(xOutputStream, true); - Reference<XOutputStream> xEncryptionInfo(mrOleStorage.openOutputStream("EncryptionInfo"), UNO_SET_THROW); - BinaryXOutputStream aEncryptionInfoBinaryOutputStream(xEncryptionInfo, false); + css::uno::Sequence<sal_Int8> aStreamSequence; + aStream.Value >>= aStreamSequence; - mEngine.writeEncryptionInfo(aEncryptionInfoBinaryOutputStream); + aBinaryOutputStream.writeData(aStreamSequence); - aEncryptionInfoBinaryOutputStream.close(); - xEncryptionInfo->flush(); - xEncryptionInfo->closeOutput(); + aBinaryOutputStream.close(); + } return true; } -} // namespace oox::core +} // namespace oox::crypto /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/crypto/Standard2007Engine.cxx b/oox/source/crypto/Standard2007Engine.cxx index 0ad782522450..2aaf6f4ec3f3 100644 --- a/oox/source/crypto/Standard2007Engine.cxx +++ b/oox/source/crypto/Standard2007Engine.cxx @@ -17,7 +17,7 @@ #include <comphelper/hash.hxx> -namespace oox::core { +namespace oox::crypto { /* =========================================================================== */ /* Kudos to Caolan McNamara who provided the core decryption implementations. */ @@ -228,7 +228,7 @@ void Standard2007Engine::writeEncryptionInfo(BinaryXOutputStream& rStream) rStream.writeMemory(&mInfo.verifier, sizeof(msfilter::EncryptionVerifierAES)); } -void Standard2007Engine::encrypt(css::uno::Reference<css::io::XInputStream> & rxInputStream, +void Standard2007Engine::encrypt(const css::uno::Reference<css::io::XInputStream> & rxInputStream, css::uno::Reference<css::io::XOutputStream> & rxOutputStream, sal_uInt32 nSize) { @@ -316,6 +316,6 @@ bool Standard2007Engine::readEncryptionInfo(css::uno::Reference<css::io::XInputS return !aBinaryStream.isEof(); } -} // namespace oox::core +} // namespace oox::crypto /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/crypto/StrongEncryptionDataSpace.cxx b/oox/source/crypto/StrongEncryptionDataSpace.cxx new file mode 100644 index 000000000000..2e21a89158f6 --- /dev/null +++ b/oox/source/crypto/StrongEncryptionDataSpace.cxx @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include <oox/crypto/StrongEncryptionDataSpace.hxx> +#include <oox/crypto/AgileEngine.hxx> +#include <oox/crypto/Standard2007Engine.hxx> +#include <oox/helper/binaryoutputstream.hxx> +#include <oox/helper/binaryinputstream.hxx> +#include <com/sun/star/io/SequenceInputStream.hpp> +#include <com/sun/star/io/XSequenceOutputStream.hpp> + +#include <comphelper/sequenceashashmap.hxx> +#include <cppuhelper/supportsservice.hxx> + +using namespace css; +using namespace css::beans; +using namespace css::io; +using namespace css::lang; +using namespace css::uno; + +namespace oox +{ +namespace crypto +{ +StrongEncryptionDataSpace::StrongEncryptionDataSpace(const Reference<XComponentContext>& rxContext) + : mxContext(rxContext) + , mCryptoEngine(new Standard2007Engine) +{ +} + +sal_Bool StrongEncryptionDataSpace::generateEncryptionKey(const OUString& rPassword) +{ + if (!mCryptoEngine) + return false; + + return mCryptoEngine->generateEncryptionKey(rPassword); +} + +sal_Bool StrongEncryptionDataSpace::checkDataIntegrity() +{ + if (!mCryptoEngine) + return false; + + return mCryptoEngine->checkDataIntegrity(); +} + +sal_Bool StrongEncryptionDataSpace::decrypt(const Reference<XInputStream>& rxInputStream, + Reference<XOutputStream>& rxOutputStream) +{ + if (!mCryptoEngine) + return false; + + BinaryXInputStream aInputStream(rxInputStream, true); + BinaryXOutputStream aOutputStream(rxOutputStream, true); + + mCryptoEngine->decrypt(aInputStream, aOutputStream); + + rxOutputStream->flush(); + return true; +} + +Reference<XInputStream> StrongEncryptionDataSpace::getStream(const Sequence<NamedValue>& rStreams, + const OUString sStreamName) +{ + for (const auto& aStream : rStreams) + { + if (aStream.Name == sStreamName) + { + Sequence<sal_Int8> aSeq; + aStream.Value >>= aSeq; + Reference<XInputStream> aStream2( + io::SequenceInputStream::createStreamFromSequence(mxContext, aSeq), + UNO_QUERY_THROW); + return aStream2; + } + } + return nullptr; +} + +sal_Bool StrongEncryptionDataSpace::readEncryptionInfo(const Sequence<NamedValue>& aStreams) +{ + Reference<XInputStream> xEncryptionInfo = getStream(aStreams, "EncryptionInfo"); + if (!xEncryptionInfo.is()) + return false; + + BinaryXInputStream aBinaryInputStream(xEncryptionInfo, true); + sal_uInt32 aVersion = aBinaryInputStream.readuInt32(); + + switch (aVersion) + { + case msfilter::VERSION_INFO_2007_FORMAT: + case msfilter::VERSION_INFO_2007_FORMAT_SP2: + mCryptoEngine.reset(new Standard2007Engine); + break; + case msfilter::VERSION_INFO_AGILE: + mCryptoEngine.reset(new AgileEngine()); + break; + default: + break; + } + + if (!mCryptoEngine) + return false; + + return mCryptoEngine->readEncryptionInfo(xEncryptionInfo); +} + +sal_Bool StrongEncryptionDataSpace::setupEncryption(const Sequence<NamedValue>& rMediaEncData) +{ + if (!mCryptoEngine) + return false; + + OUString sPassword; + for (const auto& aParam : rMediaEncData) + { + if (aParam.Name == "OOXPassword") + { + aParam.Value >>= sPassword; + } + } + + return mCryptoEngine->setupEncryption(sPassword); +} + +Sequence<NamedValue> StrongEncryptionDataSpace::createEncryptionData(const OUString& rPassword) +{ + comphelper::SequenceAsHashMap aEncryptionData; + aEncryptionData["OOXPassword"] <<= rPassword; + aEncryptionData["CryptoType"] <<= OUString("StrongEncryptionDataSpace"); + + return aEncryptionData.getAsConstNamedValueList(); +} + +Sequence<NamedValue> +StrongEncryptionDataSpace::encrypt(const Reference<XInputStream>& rxInputStream) +{ + if (!mCryptoEngine) + return Sequence<NamedValue>(); + + Reference<XSeekable> xSeekable(rxInputStream, UNO_QUERY); + if (!xSeekable.is()) + return Sequence<NamedValue>(); + + sal_uInt32 aLength = xSeekable->getLength(); // check length of the stream + + Reference<XOutputStream> xOutputStream( + mxContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.io.SequenceOutputStream", mxContext), + UNO_QUERY); + + mCryptoEngine->encrypt(rxInputStream, xOutputStream, aLength); + + comphelper::SequenceAsHashMap aStreams; + + Reference<XSequenceOutputStream> xEncodedFileSequenceStream(xOutputStream, UNO_QUERY); + aStreams["EncryptedPackage"] <<= xEncodedFileSequenceStream->getWrittenBytes(); + + Reference<XOutputStream> aEncryptionInfoStream( + mxContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.io.SequenceOutputStream", mxContext), + UNO_QUERY); + BinaryXOutputStream rStream(aEncryptionInfoStream, false); + mCryptoEngine->writeEncryptionInfo(rStream); + aEncryptionInfoStream->flush(); + Reference<XSequenceOutputStream> aEncryptionInfoSequenceStream(aEncryptionInfoStream, + UNO_QUERY); + + aStreams["EncryptionInfo"] <<= aEncryptionInfoSequenceStream->getWrittenBytes(); + + return aStreams.getAsConstNamedValueList(); +} + +OUString SAL_CALL StrongEncryptionDataSpace::getImplementationName() +{ + return "com.sun.star.comp.oox.crypto.StrongEncryptionDataSpace"; +} + +sal_Bool SAL_CALL StrongEncryptionDataSpace::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL StrongEncryptionDataSpace::getSupportedServiceNames() +{ + Sequence<OUString> aServices{ "com.sun.star.packages.PackageEncryption" }; + return aServices; +} + +} // namespace crypto +} // namespace oox + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_oox_crypto_StrongEncryptionDataSpace_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new oox::crypto::StrongEncryptionDataSpace(pCtx)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/util/oox.component b/oox/util/oox.component index 32a8100b8fb8..ef54da9a11e2 100644 --- a/oox/util/oox.component +++ b/oox/util/oox.component @@ -40,4 +40,8 @@ constructor="com_sun_star_comp_oox_ShapeContextHandler_get_implementation"> <service name="com.sun.star.xml.sax.FastShapeContextHandler"/> </implementation> + <implementation name="com.sun.star.comp.oox.crypto.StrongEncryptionDataSpace" + constructor="com_sun_star_comp_oox_crypto_StrongEncryptionDataSpace_get_implementation"> + <service name="com.sun.star.packages.PackageEncryption"/> + </implementation> </component> |