tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / oox / source / crypto / DocumentDecryption.cxx
blobb6963f22c75ed660a620a2cdfd579376d190b38b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
11 #include <oox/crypto/DocumentDecryption.hxx>
13 #include <comphelper/sequenceashashmap.hxx>
15 #include <com/sun/star/beans/NamedValue.hpp>
16 #include <com/sun/star/io/XSeekable.hpp>
17 #include <com/sun/star/io/XStream.hpp>
18 #include <com/sun/star/io/IOException.hpp>
19 #include <com/sun/star/uno/XComponentContext.hpp>
20 #include <com/sun/star/packages/XPackageEncryption.hpp>
21 #include <oox/ole/olestorage.hxx>
22 #include <oox/helper/binaryinputstream.hxx>
24 #include <sal/log.hxx>
25 #include <utility>
27 namespace
29 void lcl_getListOfStreams(oox::StorageBase* pStorage, std::vector<OUString>& rElementNames)
31 std::vector<OUString> oElementNames;
32 pStorage->getElementNames(oElementNames);
33 for (const auto& sName : oElementNames)
35 oox::StorageRef rSubStorage = pStorage->openSubStorage(sName, false);
36 if (rSubStorage && rSubStorage->isStorage())
38 lcl_getListOfStreams(rSubStorage.get(), rElementNames);
40 else
42 if (pStorage->isRootStorage())
43 rElementNames.push_back(sName);
44 else
45 rElementNames.push_back(pStorage->getPath() + "/" + sName);
51 namespace oox::crypto
53 using namespace css;
55 DocumentDecryption::DocumentDecryption(css::uno::Reference<css::uno::XComponentContext> xContext,
56 oox::ole::OleStorage& rOleStorage)
57 : mxContext(std::move(xContext))
58 , mrOleStorage(rOleStorage)
60 // Get OLE streams into sequences for later use in CryptoEngine
61 std::vector<OUString> aStreamNames;
62 lcl_getListOfStreams(&mrOleStorage, aStreamNames);
64 comphelper::SequenceAsHashMap aStreamsData;
65 for (const auto& sStreamName : aStreamNames)
67 uno::Reference<io::XInputStream> xStream = mrOleStorage.openInputStream(sStreamName);
68 if (!xStream.is())
69 throw io::IOException("Cannot open OLE input stream for " + sStreamName + "!");
71 BinaryXInputStream aBinaryInputStream(xStream, true);
73 css::uno::Sequence<sal_Int8> oData;
74 sal_Int32 nStreamSize = aBinaryInputStream.size();
75 sal_Int32 nReadBytes = aBinaryInputStream.readData(oData, nStreamSize);
77 if (nStreamSize != nReadBytes)
79 SAL_WARN("oox", "OLE stream invalid content");
80 throw io::IOException("OLE stream invalid content for " + sStreamName + "!");
83 aStreamsData[sStreamName] <<= oData;
85 maStreamsSequence = aStreamsData.getAsConstNamedValueList();
88 bool DocumentDecryption::generateEncryptionKey(const OUString& rPassword)
90 if (mxPackageEncryption.is())
91 return mxPackageEncryption->generateEncryptionKey(rPassword);
92 return false;
95 bool DocumentDecryption::readEncryptionInfo()
97 if (!mrOleStorage.isStorage())
98 return false;
100 // Read 0x6DataSpaces/DataSpaceMap
101 uno::Reference<io::XInputStream> xDataSpaceMap
102 = mrOleStorage.openInputStream(u"\006DataSpaces/DataSpaceMap"_ustr);
103 OUString sDataSpaceName;
105 if (xDataSpaceMap.is())
107 bool bBroken = false;
109 BinaryXInputStream aDataSpaceStream(xDataSpaceMap, true);
110 sal_uInt32 aHeaderLength = aDataSpaceStream.readuInt32();
111 SAL_WARN_IF(aHeaderLength != 8, "oox",
112 "DataSpaceMap length != 8 is not supported. Some content may be skipped");
113 sal_uInt32 aEntryCount = aDataSpaceStream.readuInt32();
114 SAL_WARN_IF(aEntryCount != 1, "oox",
115 "DataSpaceMap contains more than one entry. Some content may be skipped");
117 // Read each DataSpaceMapEntry (MS-OFFCRYPTO 2.1.6.1)
118 for (sal_uInt32 i = 0; i < aEntryCount && !bBroken; i++)
120 // entryLen unused for the moment
121 aDataSpaceStream.skip(sizeof(sal_uInt32));
123 // Read each DataSpaceReferenceComponent (MS-OFFCRYPTO 2.1.6.2)
124 sal_uInt32 aReferenceComponentCount = aDataSpaceStream.readuInt32();
125 for (sal_uInt32 j = 0; j < aReferenceComponentCount && !bBroken; j++)
127 // Read next reference component
128 // refComponentType unused for the moment
129 aDataSpaceStream.skip(sizeof(sal_uInt32));
130 sal_uInt32 aReferenceComponentNameLength = aDataSpaceStream.readuInt32();
131 // sReferenceComponentName unused for the moment
132 if (aDataSpaceStream.getRemaining() < aReferenceComponentNameLength)
134 bBroken = true;
135 break;
137 aDataSpaceStream.readUnicodeArray(aReferenceComponentNameLength / 2);
138 aDataSpaceStream.skip((4 - (aReferenceComponentNameLength & 3))
139 & 3); // Skip padding
141 bBroken |= aDataSpaceStream.isEof();
144 sal_uInt32 aDataSpaceNameLength = aDataSpaceStream.readuInt32();
145 if (aDataSpaceStream.getRemaining() < aDataSpaceNameLength)
147 bBroken = true;
148 break;
150 sDataSpaceName = aDataSpaceStream.readUnicodeArray(aDataSpaceNameLength / 2);
151 aDataSpaceStream.skip((4 - (aDataSpaceNameLength & 3)) & 3); // Skip padding
153 bBroken |= aDataSpaceStream.isEof();
156 if (bBroken)
158 SAL_WARN("oox", "EOF on parsing DataSpaceMapEntry table");
159 return false;
162 else
164 // Fallback for documents generated by LO: they sometimes do not have all
165 // required by MS-OFFCRYPTO specification streams (0x6DataSpaces/DataSpaceMap and others)
166 SAL_WARN("oox", "Encrypted package does not contain DataSpaceMap");
167 sDataSpaceName = "StrongEncryptionDataSpace";
170 uno::Sequence<uno::Any> aArguments;
171 mxPackageEncryption.set(
172 mxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
173 "com.sun.star.comp.oox.crypto." + sDataSpaceName, aArguments, mxContext),
174 css::uno::UNO_QUERY);
176 if (!mxPackageEncryption.is())
178 // we do not know how to decrypt this document
179 return false;
182 return mxPackageEncryption->readEncryptionInfo(maStreamsSequence);
185 uno::Sequence<beans::NamedValue> DocumentDecryption::createEncryptionData(const OUString& rPassword)
187 if (!mxPackageEncryption.is())
188 return uno::Sequence<beans::NamedValue>();
190 return mxPackageEncryption->createEncryptionData(rPassword);
193 bool DocumentDecryption::decrypt(const uno::Reference<io::XStream>& xDocumentStream)
195 bool bResult = false;
197 if (!mrOleStorage.isStorage())
198 return false;
200 if (!mxPackageEncryption.is())
201 return false;
203 // open the required input streams in the encrypted package
204 uno::Reference<io::XInputStream> xEncryptedPackage
205 = mrOleStorage.openInputStream(u"EncryptedPackage"_ustr);
207 // create temporary file for unencrypted package
208 uno::Reference<io::XOutputStream> xDecryptedPackage = xDocumentStream->getOutputStream();
210 bResult = mxPackageEncryption->decrypt(xEncryptedPackage, xDecryptedPackage);
212 css::uno::Reference<io::XSeekable> xSeekable(xDecryptedPackage, css::uno::UNO_QUERY);
213 xSeekable->seek(0);
215 if (bResult)
216 return mxPackageEncryption->checkDataIntegrity();
218 return bResult;
221 } // namespace oox::crypto
223 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */