summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasily Melenchuk <vasily.melenchuk@cib.de>2019-09-03 21:08:34 +0300
committerThorsten Behrens <Thorsten.Behrens@CIB.de>2020-05-25 10:04:15 +0200
commitb9353394f46e46485fd148f2842f0c1e8e5322e3 (patch)
treebf3dcc20cafbc00275c7154858379361b5147ff9
parent2f17679a46ca1336cb82ef652e09f423c5b8923d (diff)
[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 <Thorsten.Behrens@CIB.de>
-rw-r--r--include/oox/crypto/AgileEngine.hxx6
-rw-r--r--include/oox/crypto/CryptTools.hxx4
-rw-r--r--include/oox/crypto/CryptoEngine.hxx6
-rw-r--r--include/oox/crypto/DocumentDecryption.hxx22
-rw-r--r--include/oox/crypto/DocumentEncryption.hxx17
-rw-r--r--include/oox/crypto/Standard2007Engine.hxx6
-rw-r--r--include/oox/crypto/StrongEncryptionDataSpace.hxx76
-rw-r--r--offapi/UnoApi_offapi.mk2
-rw-r--r--offapi/com/sun/star/packages/PackageEncryption.idl25
-rw-r--r--offapi/com/sun/star/packages/XPackageEncryption.idl134
-rw-r--r--oox/Library_oox.mk1
-rw-r--r--oox/qa/unit/CryptoTest.cxx46
-rw-r--r--oox/source/core/filterdetect.cxx20
-rw-r--r--oox/source/core/xmlfilterbase.cxx19
-rw-r--r--oox/source/crypto/AgileEngine.cxx10
-rw-r--r--oox/source/crypto/CryptTools.cxx4
-rw-r--r--oox/source/crypto/DocumentDecryption.cxx185
-rw-r--r--oox/source/crypto/DocumentEncryption.cxx72
-rw-r--r--oox/source/crypto/Standard2007Engine.cxx6
-rw-r--r--oox/source/crypto/StrongEncryptionDataSpace.cxx206
-rw-r--r--oox/util/oox.component4
-rw-r--r--sfx2/source/dialog/filedlghelper.cxx3
-rwxr-xr-xsolenv/bin/native-code.py1
-rw-r--r--sw/qa/inc/swmodeltestbase.hxx1
-rw-r--r--unotools/source/misc/mediadescriptor.cxx5
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;