From b9353394f46e46485fd148f2842f0c1e8e5322e3 Mon Sep 17 00:00:00 2001 From: Vasily Melenchuk Date: Tue, 3 Sep 2019 21:08:34 +0300 Subject: [MS-OFFCRYPTO] convert oox implementation into UNO service To permit pluggable crypto services, abstract existing implementation behind an XPackageEncryption API. Previous code already had two halfway-polymorphic classes (agile and standard 2007 engine), so we're not adding much additional layers. As MS crypto always uses OLE storage to wrap content into one single file, current implementation passes all substorage names down into XPackageEncryption APi, so different downstream implementations (e.g. for MS RMS, or Azure AIP) are possible. Because OleStorage classes are internal to LibO core, access is provided via XInput/XOutput stream API function. Change-Id: Icc32a4e0ce215090c3b739f1dcaa0654b36b7f08 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/84436 Tested-by: Jenkins Reviewed-by: Thorsten Behrens --- include/oox/crypto/AgileEngine.hxx | 6 +- include/oox/crypto/CryptTools.hxx | 4 +- include/oox/crypto/CryptoEngine.hxx | 6 +- include/oox/crypto/DocumentDecryption.hxx | 22 +-- include/oox/crypto/DocumentEncryption.hxx | 17 +- include/oox/crypto/Standard2007Engine.hxx | 6 +- include/oox/crypto/StrongEncryptionDataSpace.hxx | 76 ++++++++ offapi/UnoApi_offapi.mk | 2 + offapi/com/sun/star/packages/PackageEncryption.idl | 25 +++ .../com/sun/star/packages/XPackageEncryption.idl | 134 ++++++++++++++ oox/Library_oox.mk | 1 + oox/qa/unit/CryptoTest.cxx | 46 ++--- oox/source/core/filterdetect.cxx | 20 +- oox/source/core/xmlfilterbase.cxx | 19 +- oox/source/crypto/AgileEngine.cxx | 10 +- oox/source/crypto/CryptTools.cxx | 4 +- oox/source/crypto/DocumentDecryption.cxx | 185 +++++++++++++----- oox/source/crypto/DocumentEncryption.cxx | 72 +++++-- oox/source/crypto/Standard2007Engine.cxx | 6 +- oox/source/crypto/StrongEncryptionDataSpace.cxx | 206 +++++++++++++++++++++ oox/util/oox.component | 4 + sfx2/source/dialog/filedlghelper.cxx | 3 +- solenv/bin/native-code.py | 1 + sw/qa/inc/swmodeltestbase.hxx | 1 + unotools/source/misc/mediadescriptor.cxx | 5 +- 25 files changed, 724 insertions(+), 157 deletions(-) create mode 100644 include/oox/crypto/StrongEncryptionDataSpace.hxx create mode 100644 offapi/com/sun/star/packages/PackageEncryption.idl create mode 100644 offapi/com/sun/star/packages/XPackageEncryption.idl create mode 100644 oox/source/crypto/StrongEncryptionDataSpace.cxx diff --git a/include/oox/crypto/AgileEngine.hxx b/include/oox/crypto/AgileEngine.hxx index b4aeec6de5be..ac028533d71c 100644 --- a/include/oox/crypto/AgileEngine.hxx +++ b/include/oox/crypto/AgileEngine.hxx @@ -25,7 +25,7 @@ namespace oox { } namespace oox { -namespace core { +namespace crypto { struct OOX_DLLPUBLIC AgileEncryptionInfo { @@ -125,7 +125,7 @@ public: void writeEncryptionInfo(BinaryXOutputStream& rStream) override; - void encrypt(css::uno::Reference& rxInputStream, + void encrypt(const css::uno::Reference& rxInputStream, css::uno::Reference& rxOutputStream, sal_uInt32 nSize) override; @@ -141,7 +141,7 @@ public: bool setupEncryptionKey(OUString const & rPassword); }; -} // namespace core +} // namespace crypto } // namespace oox #endif diff --git a/include/oox/crypto/CryptTools.hxx b/include/oox/crypto/CryptTools.hxx index 4e8d8e586922..31d90efcbc49 100644 --- a/include/oox/crypto/CryptTools.hxx +++ b/include/oox/crypto/CryptTools.hxx @@ -27,7 +27,7 @@ #include namespace oox { -namespace core { +namespace crypto { /** Rounds up the input to the nearest multiple * @@ -114,7 +114,7 @@ public: }; -} // namespace core +} // namespace crypto } // namespace oox #endif diff --git a/include/oox/crypto/CryptoEngine.hxx b/include/oox/crypto/CryptoEngine.hxx index 8a947f10d106..72bde8920dfc 100644 --- a/include/oox/crypto/CryptoEngine.hxx +++ b/include/oox/crypto/CryptoEngine.hxx @@ -25,7 +25,7 @@ namespace oox { } namespace oox { -namespace core { +namespace crypto { class CryptoEngine { @@ -53,14 +53,14 @@ public: virtual bool setupEncryption(const OUString& rPassword) = 0; - virtual void encrypt(css::uno::Reference & rxInputStream, + virtual void encrypt(const css::uno::Reference & rxInputStream, css::uno::Reference & rxOutputStream, sal_uInt32 nSize) = 0; virtual bool checkDataIntegrity() = 0; }; -} // namespace core +} // namespace crypto } // namespace oox #endif diff --git a/include/oox/crypto/DocumentDecryption.hxx b/include/oox/crypto/DocumentDecryption.hxx index 7919fa7a40f3..2c058121c1b7 100644 --- a/include/oox/crypto/DocumentDecryption.hxx +++ b/include/oox/crypto/DocumentDecryption.hxx @@ -17,7 +17,6 @@ #include #include -#include #include namespace com::sun::star { @@ -25,29 +24,24 @@ namespace com::sun::star { namespace io { class XInputStream; } namespace io { class XStream; } namespace uno { class XComponentContext; } + namespace packages { class XPackageEncryption; } } namespace oox::ole { class OleStorage; } namespace oox { -namespace core { +namespace crypto { class DocumentDecryption { private: - enum CryptoType - { - UNKNOWN, - STANDARD_2007, - AGILE - }; - - oox::ole::OleStorage& mrOleStorage; - std::unique_ptr mEngine; - CryptoType mCryptoType; + css::uno::Reference< css::uno::XComponentContext > mxContext; + oox::ole::OleStorage& mrOleStorage; + css::uno::Sequence maStreamsSequence; + css::uno::Reference< css::packages::XPackageEncryption > mxPackageEncryption; public: - DocumentDecryption(oox::ole::OleStorage& rOleStorage); + DocumentDecryption(const css::uno::Reference< css::uno::XComponentContext >& rxContext, oox::ole::OleStorage& rOleStorage); bool decrypt(const css::uno::Reference< css::io::XStream >& xDocumentStream); bool readEncryptionInfo(); @@ -57,7 +51,7 @@ public: }; -} // namespace core +} // namespace crypto } // namespace oox #endif diff --git a/include/oox/crypto/DocumentEncryption.hxx b/include/oox/crypto/DocumentEncryption.hxx index 9be7c99bb41c..17480652aa8d 100644 --- a/include/oox/crypto/DocumentEncryption.hxx +++ b/include/oox/crypto/DocumentEncryption.hxx @@ -14,38 +14,43 @@ #include #include -#include +#include #include namespace com::sun::star { namespace io { class XStream; } + namespace packages { class XPackageEncryption; } + namespace beans { struct NamedValue; } + namespace uno { class XComponentContext; } } namespace oox::ole { class OleStorage; } namespace oox { -namespace core { +namespace crypto { class DocumentEncryption { private: + css::uno::Reference< css::uno::XComponentContext > mxContext; css::uno::Reference< css::io::XStream > mxDocumentStream; oox::ole::OleStorage& mrOleStorage; OUString maPassword; - Standard2007Engine mEngine; + css::uno::Reference< css::packages::XPackageEncryption > mxPackageEncryption; + const css::uno::Sequence< css::beans::NamedValue >& mMediaEncData; public: - DocumentEncryption( + DocumentEncryption(const css::uno::Reference< css::uno::XComponentContext >& rxContext, css::uno::Reference< css::io::XStream > const & xDocumentStream, oox::ole::OleStorage& rOleStorage, - const OUString& aPassword); + const css::uno::Sequence< css::beans::NamedValue >& rMediaEncData); bool encrypt(); }; -} // namespace core +} // namespace crypto } // namespace oox #endif diff --git a/include/oox/crypto/Standard2007Engine.hxx b/include/oox/crypto/Standard2007Engine.hxx index 7583447319c6..4a6eaae9e43c 100644 --- a/include/oox/crypto/Standard2007Engine.hxx +++ b/include/oox/crypto/Standard2007Engine.hxx @@ -23,7 +23,7 @@ namespace oox { } namespace oox { -namespace core { +namespace crypto { class OOX_DLLPUBLIC Standard2007Engine final : public CryptoEngine { @@ -45,7 +45,7 @@ public: bool checkDataIntegrity() override; - void encrypt(css::uno::Reference& rxInputStream, + void encrypt(const css::uno::Reference& rxInputStream, css::uno::Reference& rxOutputStream, sal_uInt32 nSize) override; @@ -55,7 +55,7 @@ public: }; -} // namespace core +} // namespace crypto } // namespace oox #endif diff --git a/include/oox/crypto/StrongEncryptionDataSpace.hxx b/include/oox/crypto/StrongEncryptionDataSpace.hxx new file mode 100644 index 000000000000..d287970e6519 --- /dev/null +++ b/include/oox/crypto/StrongEncryptionDataSpace.hxx @@ -0,0 +1,76 @@ +/* -*- 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/. + * + */ + +#ifndef INCLUDED_OOX_CRYPTO_STRONGENCRYPTINDATASPACE_HXX +#define INCLUDED_OOX_CRYPTO_STRONGENCRYPTINDATASPACE_HXX + +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::uno +{ +class XComponentContext; +} + +namespace oox +{ +namespace crypto +{ +class OOX_DLLPUBLIC StrongEncryptionDataSpace final + : public cppu::WeakImplHelper +{ + css::uno::Reference mxContext; + std::unique_ptr mCryptoEngine; + + css::uno::Reference + getStream(const css::uno::Sequence& rStreams, + const rtl::OUString sStreamName); + +public: + StrongEncryptionDataSpace(const css::uno::Reference& rxContext); + + // Decryption + + virtual sal_Bool SAL_CALL generateEncryptionKey(const OUString& rPassword) override; + virtual sal_Bool SAL_CALL + readEncryptionInfo(const css::uno::Sequence& aStreams) override; + virtual sal_Bool SAL_CALL + decrypt(const css::uno::Reference& rxInputStream, + css::uno::Reference& rxOutputStream) override; + + virtual sal_Bool SAL_CALL checkDataIntegrity() override; + + // Encryption + + virtual css::uno::Sequence + SAL_CALL encrypt(const css::uno::Reference& rxInputStream) override; + + virtual sal_Bool SAL_CALL + setupEncryption(const css::uno::Sequence& rMediaEncData) override; + + virtual css::uno::Sequence + SAL_CALL createEncryptionData(const OUString& rPassword) override; + + // com.sun.star.lang.XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + +} // namespace crypto +} // namespace oox + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk index 61262689343b..aacbe14805d3 100644 --- a/offapi/UnoApi_offapi.mk +++ b/offapi/UnoApi_offapi.mk @@ -2934,6 +2934,8 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/packages,\ NoRawFormatException \ WrongPasswordException \ XDataSinkEncrSupport \ + XPackageEncryption \ + PackageEncryption \ )) $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/packages/manifest,\ XManifestReader \ diff --git a/offapi/com/sun/star/packages/PackageEncryption.idl b/offapi/com/sun/star/packages/PackageEncryption.idl new file mode 100644 index 000000000000..a2ab55ed3be8 --- /dev/null +++ b/offapi/com/sun/star/packages/PackageEncryption.idl @@ -0,0 +1,25 @@ +/* -*- 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/. + */ +#ifndef __com_sun_star_packages_PackageEncryption_idl__ +#define __com_sun_star_packages_PackageEncryption_idl__ + +#include + + +module com { module sun { module star { module packages { + + +service PackageEncryption : XPackageEncryption; + + +}; }; }; }; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/offapi/com/sun/star/packages/XPackageEncryption.idl b/offapi/com/sun/star/packages/XPackageEncryption.idl new file mode 100644 index 000000000000..402c3e2f25d4 --- /dev/null +++ b/offapi/com/sun/star/packages/XPackageEncryption.idl @@ -0,0 +1,134 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef __com_sun_star_packages_XPackageEncryption_idl__ +#define __com_sun_star_packages_XPackageEncryption_idl__ + +#include + +#include +#include + + +module com { module sun { module star { module packages { + + +/** Allows to transparently plug-in crypto for PackageStreams. + + @since LibreOffice 6.5 + */ +interface XPackageEncryption: com::sun::star::uno::XInterface +{ + /** Read package crypto information + + @param rStreams + Substreams of the package (in the case of MS encryption, those + are OLE substorage streams). + + @returns + True if crypto info could be retrieved, and engine initialised. False otherwise. + */ + boolean readEncryptionInfo([in] sequence < com::sun::star::beans::NamedValue > rStreams); + + /** Set or refresh encrytion key + + @param rPassword + Optional password to use for generating encryption key. + + @returns + True if key setup was successful. False otherwise. + */ + boolean generateEncryptionKey([in] string rPassword); + + /** Decrypt document content + + After crypto setup via readEncryptionInfo(), pipe package bits through + encryption engine. + + @param rxInputStream + Input data (encrypted) + + @param rxOutputStream + Output data (decrypted) + + @returns + True if decryption finished without error. False otherwise. + */ + boolean decrypt([in] com::sun::star::io::XInputStream rxInputStream, + [out] com::sun::star::io::XOutputStream rxOutputStream); + + /** Create key-value list of encryption meta data + + After generateEncryptionKey() succeeded in setting up crypto, + use this method to create requisite meta data. Depending on + underlying crypto, this can be a salt, init vector, or other + algorithm-specific information that needs to be stored + alongside an encrypted document + + @param rPassword + Same password as provided to generateEncryptionKey + + @returns + Sequence of opaque key-value pairs needed for decrypting this + setup. Can be passed back into other instances of this service + via setupEncryption() + */ + sequence createEncryptionData([in] string rPassword); + + /** Set key-value list of encryption meta data + + Use this method to setup requisite encryption meta + data. Depending on the underlying crypto, this can be a salt, init + vector, or other algorithm-specific information that needs to + be stored alongside an encrypted document + + @returns + True if encryption algo setup finished without error. False otherwise. + */ + boolean setupEncryption([in] sequence rMediaEncData); + + /** Encrypt given stream + + After setting up crypto via setupEncryption(), use this method to encrypt content. + + @returns + Sequence of named output streams, specific to the crypto + provider. The names of sequence entry denote the substream + identifiers, if any. In the case of MS OLE storage, it's the + substorage names. + */ + sequence encrypt([in] com::sun::star::io::XInputStream rxInputStream); + + /** Check if decryption meta data is valid + + Some implementations might for example check HMAC values + here. Call this before trusting encrypted data. + + @returns + True if decryption algo setup finished without error and + consistency checks have passed. False otherwise. + */ + boolean checkDataIntegrity(); +}; + + +}; }; }; }; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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 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 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 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 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 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 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 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 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& rEncryptionData ) override; virtual DocPasswordVerifierResult verifyEncryptionData( const Sequence& 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& 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 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 extendedSalt(mInfo.hmacKey); @@ -759,7 +759,7 @@ void AgileEngine::writeEncryptionInfo(BinaryXOutputStream & rStream) rStream.writeMemory(aMemStream.GetData(), aMemStream.GetSize()); } -void AgileEngine::encrypt(css::uno::Reference & rxInputStream, +void AgileEngine::encrypt(const css::uno::Reference & rxInputStream, css::uno::Reference & rxOutputStream, sal_uInt32 nSize) { @@ -799,7 +799,7 @@ void AgileEngine::encrypt(css::uno::Reference & 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(&nSegment); @@ -822,6 +822,6 @@ void AgileEngine::encrypt(css::uno::Reference & 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 #endif // USE_TLS_NSS -namespace oox::core { +namespace oox::crypto { #if USE_TLS_OPENSSL struct CryptoImpl @@ -478,6 +478,6 @@ std::vector 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 #include +#include #include -#include -#include -#include -#include +#include +#include #include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace { + +void lcl_getListOfStreams(oox::StorageBase* pStorage, std::vector& 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 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 xEncryptionInfo = mrOleStorage.openInputStream("EncryptionInfo"); + // Read 0x6DataSpaces/DataSpaceMap + uno::Reference 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 DocumentDecryption::createEncryptionData(const OUString& rPassword) { - comphelper::SequenceAsHashMap aEncryptionData; + if (!mxPackageEncryption.is()) + return uno::Sequence(); - 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& xDocumentStream) @@ -89,25 +177,26 @@ bool DocumentDecryption::decrypt(const uno::Reference& xDocumentStr if (!mrOleStorage.isStorage()) return false; + if (!mxPackageEncryption.is()) + return false; + // open the required input streams in the encrypted package uno::Reference xEncryptedPackage = mrOleStorage.openInputStream("EncryptedPackage"); // create temporary file for unencrypted package uno::Reference 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 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 #include #include +#include +#include #include #include +#include -namespace oox::core { +namespace oox::crypto { using namespace css::io; using namespace css::uno; +using namespace css::beans; -DocumentEncryption::DocumentEncryption(Reference const & xDocumentStream, +DocumentEncryption::DocumentEncryption(const Reference< XComponentContext >& rxContext, + Reference const & xDocumentStream, oox::ole::OleStorage& rOleStorage, - const OUString& rPassword) - : mxDocumentStream(xDocumentStream) + const Sequence& 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 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 (mxDocumentStream->getInputStream(), UNO_SET_THROW); Reference 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(mrOleStorage.openOutputStream("EncryptedPackage"), UNO_SET_THROW); + mxPackageEncryption->setupEncryption(mMediaEncData); - mEngine.encrypt(xInputStream, xOutputStream, aLength); + Sequence aStreams = mxPackageEncryption->encrypt(xInputStream); - xOutputStream->flush(); - xOutputStream->closeOutput(); + for (const NamedValue & aStream : std::as_const(aStreams)) + { + Reference xOutputStream(mrOleStorage.openOutputStream(aStream.Name), UNO_SET_THROW); + BinaryXOutputStream aBinaryOutputStream(xOutputStream, true); - Reference xEncryptionInfo(mrOleStorage.openOutputStream("EncryptionInfo"), UNO_SET_THROW); - BinaryXOutputStream aEncryptionInfoBinaryOutputStream(xEncryptionInfo, false); + css::uno::Sequence 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 -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 & rxInputStream, +void Standard2007Engine::encrypt(const css::uno::Reference & rxInputStream, css::uno::Reference & rxOutputStream, sal_uInt32 nSize) { @@ -316,6 +316,6 @@ bool Standard2007Engine::readEncryptionInfo(css::uno::Reference +#include +#include +#include +#include +#include +#include + +#include +#include + +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& 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& rxInputStream, + Reference& rxOutputStream) +{ + if (!mCryptoEngine) + return false; + + BinaryXInputStream aInputStream(rxInputStream, true); + BinaryXOutputStream aOutputStream(rxOutputStream, true); + + mCryptoEngine->decrypt(aInputStream, aOutputStream); + + rxOutputStream->flush(); + return true; +} + +Reference StrongEncryptionDataSpace::getStream(const Sequence& rStreams, + const OUString sStreamName) +{ + for (const auto& aStream : rStreams) + { + if (aStream.Name == sStreamName) + { + Sequence aSeq; + aStream.Value >>= aSeq; + Reference aStream2( + io::SequenceInputStream::createStreamFromSequence(mxContext, aSeq), + UNO_QUERY_THROW); + return aStream2; + } + } + return nullptr; +} + +sal_Bool StrongEncryptionDataSpace::readEncryptionInfo(const Sequence& aStreams) +{ + Reference 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& rMediaEncData) +{ + if (!mCryptoEngine) + return false; + + OUString sPassword; + for (const auto& aParam : rMediaEncData) + { + if (aParam.Name == "OOXPassword") + { + aParam.Value >>= sPassword; + } + } + + return mCryptoEngine->setupEncryption(sPassword); +} + +Sequence StrongEncryptionDataSpace::createEncryptionData(const OUString& rPassword) +{ + comphelper::SequenceAsHashMap aEncryptionData; + aEncryptionData["OOXPassword"] <<= rPassword; + aEncryptionData["CryptoType"] <<= OUString("StrongEncryptionDataSpace"); + + return aEncryptionData.getAsConstNamedValueList(); +} + +Sequence +StrongEncryptionDataSpace::encrypt(const Reference& rxInputStream) +{ + if (!mCryptoEngine) + return Sequence(); + + Reference xSeekable(rxInputStream, UNO_QUERY); + if (!xSeekable.is()) + return Sequence(); + + sal_uInt32 aLength = xSeekable->getLength(); // check length of the stream + + Reference xOutputStream( + mxContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.io.SequenceOutputStream", mxContext), + UNO_QUERY); + + mCryptoEngine->encrypt(rxInputStream, xOutputStream, aLength); + + comphelper::SequenceAsHashMap aStreams; + + Reference xEncodedFileSequenceStream(xOutputStream, UNO_QUERY); + aStreams["EncryptedPackage"] <<= xEncodedFileSequenceStream->getWrittenBytes(); + + Reference aEncryptionInfoStream( + mxContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.io.SequenceOutputStream", mxContext), + UNO_QUERY); + BinaryXOutputStream rStream(aEncryptionInfoStream, false); + mCryptoEngine->writeEncryptionInfo(rStream); + aEncryptionInfoStream->flush(); + Reference 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 SAL_CALL StrongEncryptionDataSpace::getSupportedServiceNames() +{ + Sequence 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 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"> + + + diff --git a/sfx2/source/dialog/filedlghelper.cxx b/sfx2/source/dialog/filedlghelper.cxx index e39033880c0e..1400bf71e17b 100644 --- a/sfx2/source/dialog/filedlghelper.cxx +++ b/sfx2/source/dialog/filedlghelper.cxx @@ -2697,7 +2697,8 @@ ErrCode RequestPassword(const std::shared_ptr& pCurrentFilter, if (bOOXML) { ::comphelper::SequenceAsHashMap aHashData; - aHashData[ OUString( "OOXPassword" ) ] <<= pPasswordRequest->getPassword(); + aHashData[ OUString( "OOXPassword" ) ] <<= pPasswordRequest->getPassword(); + aHashData[ OUString( "CryptoType" ) ] <<= OUString( "Standard" ); aEncryptionData = aHashData.getAsConstNamedValueList(); } else diff --git a/solenv/bin/native-code.py b/solenv/bin/native-code.py index f5012b2ff18f..d2165c197ac9 100755 --- a/solenv/bin/native-code.py +++ b/solenv/bin/native-code.py @@ -358,6 +358,7 @@ core_constructor_list = [ "com_sun_star_comp_oox_docprop_DocumentPropertiesImporter_get_implementation", "com_sun_star_comp_oox_ppt_PowerPointImport_get_implementation", "com_sun_star_comp_oox_ShapeContextHandler_get_implementation", + "com_sun_star_comp_oox_crypto_StrongEncryptionDataSpace_get_implementation", ] # edit group for apps, where you can edit documents diff --git a/sw/qa/inc/swmodeltestbase.hxx b/sw/qa/inc/swmodeltestbase.hxx index c6cbf9f83afe..32db863d5d3d 100644 --- a/sw/qa/inc/swmodeltestbase.hxx +++ b/sw/qa/inc/swmodeltestbase.hxx @@ -808,6 +808,7 @@ protected: { OUString sPassword = OUString::createFromAscii(pPassword); css::uno::Sequence aEncryptionData { + { "CryptoType", css::uno::makeAny(OUString("Standard")) }, { "OOXPassword", css::uno::makeAny(sPassword) } }; aMediaDescriptor[utl::MediaDescriptor::PROP_ENCRYPTIONDATA()] <<= aEncryptionData; diff --git a/unotools/source/misc/mediadescriptor.cxx b/unotools/source/misc/mediadescriptor.cxx index 1b830fb4e7d9..7f8f4e3c3785 100644 --- a/unotools/source/misc/mediadescriptor.cxx +++ b/unotools/source/misc/mediadescriptor.cxx @@ -473,8 +473,9 @@ css::uno::Sequence< css::beans::NamedValue > MediaDescriptor::requestAndVerifyDo erase( PROP_PASSWORD() ); erase( PROP_ENCRYPTIONDATA() ); - // insert valid password into media descriptor (but not a default password) - if( aEncryptionData.hasElements() && !bIsDefaultPassword ) + // insert encryption info into media descriptor + // TODO + if( aEncryptionData.hasElements() ) (*this)[ PROP_ENCRYPTIONDATA() ] <<= aEncryptionData; return aEncryptionData; -- cgit