1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  */
10 
11 #include <oox/crypto/StrongEncryptionDataSpace.hxx>
12 #include <oox/crypto/AgileEngine.hxx>
13 #include <oox/crypto/Standard2007Engine.hxx>
14 #include <oox/helper/binaryoutputstream.hxx>
15 #include <oox/helper/binaryinputstream.hxx>
16 #include <com/sun/star/io/SequenceInputStream.hpp>
17 #include <com/sun/star/io/XSequenceOutputStream.hpp>
18 
19 #include <comphelper/sequenceashashmap.hxx>
20 #include <cppuhelper/supportsservice.hxx>
21 
22 using namespace css;
23 using namespace css::beans;
24 using namespace css::io;
25 using namespace css::lang;
26 using namespace css::uno;
27 
28 namespace oox::crypto
29 {
StrongEncryptionDataSpace(const Reference<XComponentContext> & rxContext)30 StrongEncryptionDataSpace::StrongEncryptionDataSpace(const Reference<XComponentContext>& rxContext)
31     : mxContext(rxContext)
32     , mCryptoEngine(new Standard2007Engine)
33 {
34 }
35 
generateEncryptionKey(const OUString & rPassword)36 sal_Bool StrongEncryptionDataSpace::generateEncryptionKey(const OUString& rPassword)
37 {
38     if (!mCryptoEngine)
39         return false;
40 
41     return mCryptoEngine->generateEncryptionKey(rPassword);
42 }
43 
checkDataIntegrity()44 sal_Bool StrongEncryptionDataSpace::checkDataIntegrity()
45 {
46     if (!mCryptoEngine)
47         return false;
48 
49     return mCryptoEngine->checkDataIntegrity();
50 }
51 
decrypt(const Reference<XInputStream> & rxInputStream,Reference<XOutputStream> & rxOutputStream)52 sal_Bool StrongEncryptionDataSpace::decrypt(const Reference<XInputStream>& rxInputStream,
53                                             Reference<XOutputStream>& rxOutputStream)
54 {
55     if (!mCryptoEngine)
56         return false;
57 
58     BinaryXInputStream aInputStream(rxInputStream, true);
59     BinaryXOutputStream aOutputStream(rxOutputStream, true);
60 
61     mCryptoEngine->decrypt(aInputStream, aOutputStream);
62 
63     rxOutputStream->flush();
64     return true;
65 }
66 
getStream(const Sequence<NamedValue> & rStreams,std::u16string_view sStreamName)67 Reference<XInputStream> StrongEncryptionDataSpace::getStream(const Sequence<NamedValue>& rStreams,
68                                                              std::u16string_view sStreamName)
69 {
70     for (const auto& aStream : rStreams)
71     {
72         if (aStream.Name == sStreamName)
73         {
74             Sequence<sal_Int8> aSeq;
75             aStream.Value >>= aSeq;
76             Reference<XInputStream> aStream2(
77                 io::SequenceInputStream::createStreamFromSequence(mxContext, aSeq),
78                 UNO_QUERY_THROW);
79             return aStream2;
80         }
81     }
82     return nullptr;
83 }
84 
readEncryptionInfo(const Sequence<NamedValue> & aStreams)85 sal_Bool StrongEncryptionDataSpace::readEncryptionInfo(const Sequence<NamedValue>& aStreams)
86 {
87     Reference<XInputStream> xEncryptionInfo = getStream(aStreams, u"EncryptionInfo");
88     if (!xEncryptionInfo.is())
89         return false;
90 
91     BinaryXInputStream aBinaryInputStream(xEncryptionInfo, true);
92     sal_uInt32 aVersion = aBinaryInputStream.readuInt32();
93 
94     switch (aVersion)
95     {
96         case msfilter::VERSION_INFO_2007_FORMAT:
97         case msfilter::VERSION_INFO_2007_FORMAT_SP2:
98             mCryptoEngine.reset(new Standard2007Engine);
99             break;
100         case msfilter::VERSION_INFO_AGILE:
101             mCryptoEngine.reset(new AgileEngine());
102             break;
103         default:
104             break;
105     }
106 
107     if (!mCryptoEngine)
108         return false;
109 
110     return mCryptoEngine->readEncryptionInfo(xEncryptionInfo);
111 }
112 
setupEncryption(const Sequence<NamedValue> & rMediaEncData)113 sal_Bool StrongEncryptionDataSpace::setupEncryption(const Sequence<NamedValue>& rMediaEncData)
114 {
115     if (!mCryptoEngine)
116         return false;
117 
118     OUString sPassword;
119     for (const auto& aParam : rMediaEncData)
120     {
121         if (aParam.Name == "OOXPassword")
122         {
123             aParam.Value >>= sPassword;
124         }
125     }
126 
127     return mCryptoEngine->setupEncryption(sPassword);
128 }
129 
createEncryptionData(const OUString & rPassword)130 Sequence<NamedValue> StrongEncryptionDataSpace::createEncryptionData(const OUString& rPassword)
131 {
132     comphelper::SequenceAsHashMap aEncryptionData;
133     aEncryptionData["OOXPassword"] <<= rPassword;
134     aEncryptionData["CryptoType"] <<= OUString("StrongEncryptionDataSpace");
135 
136     return aEncryptionData.getAsConstNamedValueList();
137 }
138 
139 Sequence<NamedValue>
encrypt(const Reference<XInputStream> & rxInputStream)140 StrongEncryptionDataSpace::encrypt(const Reference<XInputStream>& rxInputStream)
141 {
142     if (!mCryptoEngine)
143         return Sequence<NamedValue>();
144 
145     Reference<XSeekable> xSeekable(rxInputStream, UNO_QUERY);
146     if (!xSeekable.is())
147         return Sequence<NamedValue>();
148 
149     sal_uInt32 aLength = xSeekable->getLength(); // check length of the stream
150 
151     Reference<XOutputStream> xOutputStream(
152         mxContext->getServiceManager()->createInstanceWithContext(
153             "com.sun.star.io.SequenceOutputStream", mxContext),
154         UNO_QUERY);
155 
156     mCryptoEngine->encrypt(rxInputStream, xOutputStream, aLength);
157 
158     comphelper::SequenceAsHashMap aStreams;
159 
160     Reference<XSequenceOutputStream> xEncodedFileSequenceStream(xOutputStream, UNO_QUERY);
161     aStreams["EncryptedPackage"] <<= xEncodedFileSequenceStream->getWrittenBytes();
162 
163     Reference<XOutputStream> aEncryptionInfoStream(
164         mxContext->getServiceManager()->createInstanceWithContext(
165             "com.sun.star.io.SequenceOutputStream", mxContext),
166         UNO_QUERY);
167     BinaryXOutputStream rStream(aEncryptionInfoStream, false);
168     mCryptoEngine->writeEncryptionInfo(rStream);
169     aEncryptionInfoStream->flush();
170     Reference<XSequenceOutputStream> aEncryptionInfoSequenceStream(aEncryptionInfoStream,
171                                                                    UNO_QUERY);
172 
173     aStreams["EncryptionInfo"] <<= aEncryptionInfoSequenceStream->getWrittenBytes();
174 
175     return aStreams.getAsConstNamedValueList();
176 }
177 
getImplementationName()178 OUString SAL_CALL StrongEncryptionDataSpace::getImplementationName()
179 {
180     return "com.sun.star.comp.oox.crypto.StrongEncryptionDataSpace";
181 }
182 
supportsService(const OUString & rServiceName)183 sal_Bool SAL_CALL StrongEncryptionDataSpace::supportsService(const OUString& rServiceName)
184 {
185     return cppu::supportsService(this, rServiceName);
186 }
187 
getSupportedServiceNames()188 css::uno::Sequence<OUString> SAL_CALL StrongEncryptionDataSpace::getSupportedServiceNames()
189 {
190     Sequence<OUString> aServices{ "com.sun.star.packages.PackageEncryption" };
191     return aServices;
192 }
193 
194 } // namespace oox::crypto
195 
196 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
com_sun_star_comp_oox_crypto_StrongEncryptionDataSpace_get_implementation(uno::XComponentContext * pCtx,uno::Sequence<uno::Any> const &)197 com_sun_star_comp_oox_crypto_StrongEncryptionDataSpace_get_implementation(
198     uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
199 {
200     return cppu::acquire(new oox::crypto::StrongEncryptionDataSpace(pCtx));
201 }
202 
203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
204