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