diff options
25 files changed, 724 insertions, 157 deletions
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<css::io::XInputStream>& rxInputStream, + void encrypt(const css::uno::Reference<css::io::XInputStream>& rxInputStream, css::uno::Reference<css::io::XOutputStream>& 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 <memory> 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<css::io::XInputStream> & rxInputStream, + virtual void encrypt(const css::uno::Reference<css::io::XInputStream> & rxInputStream, css::uno::Reference<css::io::XOutputStream> & 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 <com/sun/star/uno/Reference.hxx> #include <com/sun/star/uno/Sequence.hxx> -#include <oox/crypto/CryptoEngine.hxx> #include <rtl/ustring.hxx> 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<CryptoEngine> mEngine; - CryptoType mCryptoType; + css::uno::Reference< css::uno::XComponentContext > mxContext; + oox::ole::OleStorage& mrOleStorage; + css::uno::Sequence<css::beans::NamedValue> 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 <oox/dllapi.h> #include <com/sun/star/uno/Reference.hxx> -#include <oox/crypto/Standard2007Engine.hxx> +#include <com/sun/star/uno/Sequence.hxx> #include <rtl/ustring.hxx> 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<css::io::XInputStream>& rxInputStream, + void encrypt(const css::uno::Reference<css::io::XInputStream>& rxInputStream, css::uno::Reference<css::io::XOutputStream>& 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 <oox/dllapi.h> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/packages/XPackageEncryption.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <oox/crypto/CryptoEngine.hxx> + +namespace com::sun::star::uno +{ +class XComponentContext; +} + +namespace oox +{ +namespace crypto +{ +class OOX_DLLPUBLIC StrongEncryptionDataSpace final + : public cppu::WeakImplHelper<css::lang::XServiceInfo, css::packages::XPackageEncryption> +{ + css::uno::Reference<css::uno::XComponentContext> mxContext; + std::unique_ptr<CryptoEngine> mCryptoEngine; + + css::uno::Reference<css::io::XInputStream> + getStream(const css::uno::Sequence<css::beans::NamedValue>& rStreams, + const rtl::OUString sStreamName); + +public: + StrongEncryptionDataSpace(const css::uno::Reference<css::uno::XComponentContext>& rxContext); + + // Decryption + + virtual sal_Bool SAL_CALL generateEncryptionKey(const OUString& rPassword) override; + virtual sal_Bool SAL_CALL + readEncryptionInfo(const css::uno::Sequence<css::beans::NamedValue>& aStreams) override; + virtual sal_Bool SAL_CALL + decrypt(const css::uno::Reference<css::io::XInputStream>& rxInputStream, + css::uno::Reference<css::io::XOutputStream>& rxOutputStream) override; + + virtual sal_Bool SAL_CALL checkDataIntegrity() override; + + // Encryption + + virtual css::uno::Sequence<css::beans::NamedValue> + SAL_CALL encrypt(const css::uno::Reference<css::io::XInputStream>& rxInputStream) override; + + virtual sal_Bool SAL_CALL + setupEncryption(const css::uno::Sequence<css::beans::NamedValue>& rMediaEncData) override; + + virtual css::uno::Sequence<css::beans::NamedValue> + 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<OUString> 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 <com/sun/star/packages/XPackageEncryption.idl> + + +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 <com/sun/star/uno/XInterface.idl> + +#include <com/sun/star/io/XInputStream.idl> +#include <com/sun/star/io/XOutputStream.idl> + + +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<com::sun::star::beans::NamedValue> 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<com::sun::star::beans::NamedValue> 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<com::sun::star::beans::NamedValue> 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<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> 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<const SfxFilter>& 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<css::beans::NamedValue> 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; |