1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "oox/core/filterdetect.hxx"
25
26 #include <com/sun/star/io/XStream.hpp>
27 #include <comphelper/docpasswordhelper.hxx>
28 #include <comphelper/mediadescriptor.hxx>
29 #include <openssl/evp.h>
30 #include <rtl/digest.h>
31 #include "oox/core/fastparser.hxx"
32 #include "oox/helper/attributelist.hxx"
33 #include "oox/helper/binaryinputstream.hxx"
34 #include "oox/helper/binaryoutputstream.hxx"
35 #include "oox/helper/zipstorage.hxx"
36 #include "oox/ole/olestorage.hxx"
37
38 namespace oox {
39 namespace core {
40
41 // ============================================================================
42
43 using namespace ::com::sun::star::beans;
44 using namespace ::com::sun::star::io;
45 using namespace ::com::sun::star::lang;
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::xml::sax;
48
49 using ::comphelper::MediaDescriptor;
50 using ::comphelper::SequenceAsHashMap;
51 using ::rtl::OUString;
52
53 // ============================================================================
54
FilterDetectDocHandler(OUString & rFilterName)55 FilterDetectDocHandler::FilterDetectDocHandler( OUString& rFilterName ) :
56 mrFilterName( rFilterName )
57 {
58 maContextStack.reserve( 2 );
59 }
60
~FilterDetectDocHandler()61 FilterDetectDocHandler::~FilterDetectDocHandler()
62 {
63 }
64
startDocument()65 void SAL_CALL FilterDetectDocHandler::startDocument()
66 throw (SAXException, RuntimeException)
67 {
68 }
69
endDocument()70 void SAL_CALL FilterDetectDocHandler::endDocument()
71 throw (SAXException, RuntimeException)
72 {
73 }
74
setDocumentLocator(const Reference<XLocator> &)75 void SAL_CALL FilterDetectDocHandler::setDocumentLocator( const Reference<XLocator>& /*xLocator*/ )
76 throw (SAXException, RuntimeException)
77 {
78 }
79
startFastElement(sal_Int32 nElement,const Reference<XFastAttributeList> & rAttribs)80 void SAL_CALL FilterDetectDocHandler::startFastElement(
81 sal_Int32 nElement, const Reference< XFastAttributeList >& rAttribs )
82 throw (SAXException,RuntimeException)
83 {
84 AttributeList aAttribs( rAttribs );
85 switch ( nElement )
86 {
87 // cases for _rels/.rels
88 case PR_TOKEN( Relationships ):
89 break;
90 case PR_TOKEN( Relationship ):
91 if( !maContextStack.empty() && (maContextStack.back() == PR_TOKEN( Relationships )) )
92 parseRelationship( aAttribs );
93 break;
94
95 // cases for [Content_Types].xml
96 case PC_TOKEN( Types ):
97 break;
98 case PC_TOKEN( Default ):
99 if( !maContextStack.empty() && (maContextStack.back() == PC_TOKEN( Types )) )
100 parseContentTypesDefault( aAttribs );
101 break;
102 case PC_TOKEN( Override ):
103 if( !maContextStack.empty() && (maContextStack.back() == PC_TOKEN( Types )) )
104 parseContentTypesOverride( aAttribs );
105 break;
106 }
107 maContextStack.push_back( nElement );
108 }
109
startUnknownElement(const OUString &,const OUString &,const Reference<XFastAttributeList> &)110 void SAL_CALL FilterDetectDocHandler::startUnknownElement(
111 const OUString& /*Namespace*/, const OUString& /*Name*/, const Reference<XFastAttributeList>& /*Attribs*/ )
112 throw (SAXException, RuntimeException)
113 {
114 }
115
endFastElement(sal_Int32)116 void SAL_CALL FilterDetectDocHandler::endFastElement( sal_Int32 /*nElement*/ )
117 throw (SAXException, RuntimeException)
118 {
119 maContextStack.pop_back();
120 }
121
endUnknownElement(const OUString &,const OUString &)122 void SAL_CALL FilterDetectDocHandler::endUnknownElement(
123 const OUString& /*Namespace*/, const OUString& /*Name*/ ) throw (SAXException, RuntimeException)
124 {
125 }
126
createFastChildContext(sal_Int32,const Reference<XFastAttributeList> &)127 Reference<XFastContextHandler> SAL_CALL FilterDetectDocHandler::createFastChildContext(
128 sal_Int32 /*Element*/, const Reference<XFastAttributeList>& /*Attribs*/ )
129 throw (SAXException, RuntimeException)
130 {
131 return this;
132 }
133
createUnknownChildContext(const OUString &,const OUString &,const Reference<XFastAttributeList> &)134 Reference<XFastContextHandler> SAL_CALL FilterDetectDocHandler::createUnknownChildContext(
135 const OUString& /*Namespace*/, const OUString& /*Name*/, const Reference<XFastAttributeList>& /*Attribs*/)
136 throw (SAXException, RuntimeException)
137 {
138 return this;
139 }
140
characters(const OUString &)141 void SAL_CALL FilterDetectDocHandler::characters( const OUString& /*aChars*/ )
142 throw (SAXException, RuntimeException)
143 {
144 }
145
ignorableWhitespace(const OUString &)146 void SAL_CALL FilterDetectDocHandler::ignorableWhitespace( const OUString& /*aWhitespaces*/ )
147 throw (SAXException, RuntimeException)
148 {
149 }
150
processingInstruction(const OUString &,const OUString &)151 void SAL_CALL FilterDetectDocHandler::processingInstruction(
152 const OUString& /*aTarget*/, const OUString& /*aData*/ )
153 throw (SAXException, RuntimeException)
154 {
155 }
156
parseRelationship(const AttributeList & rAttribs)157 void FilterDetectDocHandler::parseRelationship( const AttributeList& rAttribs )
158 {
159 OUString aType = rAttribs.getString( XML_Type, OUString() );
160 if( aType.equalsAscii( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" ) )
161 maTargetPath = OUString( sal_Unicode( '/' ) ) + rAttribs.getString( XML_Target, OUString() );
162 }
163
getFilterNameFromContentType(const OUString & rContentType) const164 OUString FilterDetectDocHandler::getFilterNameFromContentType( const OUString& rContentType ) const
165 {
166 if( rContentType.equalsAscii( "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" ) ||
167 rContentType.equalsAscii( "application/vnd.ms-word.document.macroEnabled.main+xml" ) )
168 return CREATE_OUSTRING( "writer_MS_Word_2007" );
169
170 if( rContentType.equalsAscii( "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml" ) ||
171 rContentType.equalsAscii( "application/vnd.ms-word.template.macroEnabledTemplate.main+xml" ) )
172 return CREATE_OUSTRING( "writer_MS_Word_2007_Template" );
173
174 if( rContentType.equalsAscii( "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" ) ||
175 rContentType.equalsAscii( "application/vnd.ms-excel.sheet.macroEnabled.main+xml" ) )
176 return CREATE_OUSTRING( "MS Excel 2007 XML" );
177
178 if( rContentType.equalsAscii( "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml" ) ||
179 rContentType.equalsAscii( "application/vnd.ms-excel.template.macroEnabled.main+xml" ) )
180 return CREATE_OUSTRING( "MS Excel 2007 XML Template" );
181
182 if( rContentType.equalsAscii( "application/vnd.ms-excel.sheet.binary.macroEnabled.main" ) )
183 return CREATE_OUSTRING( "MS Excel 2007 Binary" );
184
185 if( rContentType.equalsAscii( "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml" ) ||
186 rContentType.equalsAscii( "application/vnd.ms-powerpoint.presentation.macroEnabled.main+xml" ) )
187 return CREATE_OUSTRING( "MS PowerPoint 2007 XML" );
188
189 if( rContentType.equalsAscii( "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml" ) ||
190 rContentType.equalsAscii( "application/vnd.ms-powerpoint.template.macroEnabled.main+xml" ) )
191 return CREATE_OUSTRING( "MS PowerPoint 2007 XML Template" );
192
193 return OUString();
194 }
195
parseContentTypesDefault(const AttributeList & rAttribs)196 void FilterDetectDocHandler::parseContentTypesDefault( const AttributeList& rAttribs )
197 {
198 // only if no overridden part name found
199 if( mrFilterName.getLength() == 0 )
200 {
201 // check if target path ends with extension
202 OUString aExtension = rAttribs.getString( XML_Extension, OUString() );
203 sal_Int32 nExtPos = maTargetPath.getLength() - aExtension.getLength();
204 if( (nExtPos > 0) && (maTargetPath[ nExtPos - 1 ] == '.') && maTargetPath.match( aExtension, nExtPos ) )
205 mrFilterName = getFilterNameFromContentType( rAttribs.getString( XML_ContentType, OUString() ) );
206 }
207 }
208
parseContentTypesOverride(const AttributeList & rAttribs)209 void FilterDetectDocHandler::parseContentTypesOverride( const AttributeList& rAttribs )
210 {
211 if( rAttribs.getString( XML_PartName, OUString() ).equals( maTargetPath ) )
212 mrFilterName = getFilterNameFromContentType( rAttribs.getString( XML_ContentType, OUString() ) );
213 }
214
215 // ============================================================================
216
217 /* Helper for XServiceInfo */
FilterDetect_getSupportedServiceNames()218 Sequence< OUString > FilterDetect_getSupportedServiceNames()
219 {
220 Sequence< OUString > aServiceNames( 1 );
221 aServiceNames[ 0 ] = CREATE_OUSTRING( "com.sun.star.frame.ExtendedTypeDetection" );
222 return aServiceNames;
223 }
224
225 /* Helper for XServiceInfo */
FilterDetect_getImplementationName()226 OUString FilterDetect_getImplementationName()
227 {
228 return CREATE_OUSTRING( "com.sun.star.comp.oox.FormatDetector" );
229 }
230
231 /* Helper for registry */
FilterDetect_createInstance(const Reference<XComponentContext> & rxContext)232 Reference< XInterface > SAL_CALL FilterDetect_createInstance( const Reference< XComponentContext >& rxContext ) throw( Exception )
233 {
234 return static_cast< ::cppu::OWeakObject* >( new FilterDetect( rxContext ) );
235 }
236
237 // ----------------------------------------------------------------------------
238
FilterDetect(const Reference<XComponentContext> & rxContext)239 FilterDetect::FilterDetect( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
240 mxContext( rxContext, UNO_SET_THROW )
241 {
242 }
243
~FilterDetect()244 FilterDetect::~FilterDetect()
245 {
246 }
247
248 /* =========================================================================== */
249 /* Kudos to Caolan McNamara who provided the core decryption implementations. */
250 /* =========================================================================== */
251
252 namespace {
253
254 const sal_uInt32 ENCRYPTINFO_CRYPTOAPI = 0x00000004;
255 const sal_uInt32 ENCRYPTINFO_DOCPROPS = 0x00000008;
256 const sal_uInt32 ENCRYPTINFO_EXTERNAL = 0x00000010;
257 const sal_uInt32 ENCRYPTINFO_AES = 0x00000020;
258
259 const sal_uInt32 ENCRYPT_ALGO_AES128 = 0x0000660E;
260 const sal_uInt32 ENCRYPT_ALGO_AES192 = 0x0000660F;
261 const sal_uInt32 ENCRYPT_ALGO_AES256 = 0x00006610;
262 const sal_uInt32 ENCRYPT_ALGO_RC4 = 0x00006801;
263
264 const sal_uInt32 ENCRYPT_HASH_SHA1 = 0x00008004;
265
266 // ----------------------------------------------------------------------------
267
lclIsZipPackage(const Reference<XComponentContext> & rxContext,const Reference<XInputStream> & rxInStrm)268 bool lclIsZipPackage( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm )
269 {
270 ZipStorage aZipStorage( rxContext, rxInStrm );
271 return aZipStorage.isStorage();
272 }
273
274 // ----------------------------------------------------------------------------
275
276 struct PackageEncryptionInfo
277 {
278 sal_uInt8 mpnSalt[ 16 ];
279 sal_uInt8 mpnEncrVerifier[ 16 ];
280 sal_uInt8 mpnEncrVerifierHash[ 32 ];
281 sal_uInt32 mnFlags;
282 sal_uInt32 mnAlgorithmId;
283 sal_uInt32 mnAlgorithmIdHash;
284 sal_uInt32 mnKeySize;
285 sal_uInt32 mnSaltSize;
286 sal_uInt32 mnVerifierHashSize;
287 };
288
lclReadEncryptionInfo(PackageEncryptionInfo & rEncrInfo,BinaryInputStream & rStrm)289 bool lclReadEncryptionInfo( PackageEncryptionInfo& rEncrInfo, BinaryInputStream& rStrm )
290 {
291 rStrm.skip( 4 );
292 rStrm >> rEncrInfo.mnFlags;
293 if( getFlag( rEncrInfo.mnFlags, ENCRYPTINFO_EXTERNAL ) )
294 return false;
295
296 sal_uInt32 nHeaderSize, nRepeatedFlags;
297 rStrm >> nHeaderSize >> nRepeatedFlags;
298 if( (nHeaderSize < 20) || (nRepeatedFlags != rEncrInfo.mnFlags) )
299 return false;
300
301 rStrm.skip( 4 );
302 rStrm >> rEncrInfo.mnAlgorithmId >> rEncrInfo.mnAlgorithmIdHash >> rEncrInfo.mnKeySize;
303 rStrm.skip( nHeaderSize - 20 );
304 rStrm >> rEncrInfo.mnSaltSize;
305 if( rEncrInfo.mnSaltSize != 16 )
306 return false;
307
308 rStrm.readMemory( rEncrInfo.mpnSalt, 16 );
309 rStrm.readMemory( rEncrInfo.mpnEncrVerifier, 16 );
310 rStrm >> rEncrInfo.mnVerifierHashSize;
311 rStrm.readMemory( rEncrInfo.mpnEncrVerifierHash, 32 );
312 return !rStrm.isEof();
313 }
314
315 // ----------------------------------------------------------------------------
316
lclDeriveKey(const sal_uInt8 * pnHash,sal_uInt32 nHashLen,sal_uInt8 * pnKeyDerived,sal_uInt32 nRequiredKeyLen)317 void lclDeriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKeyDerived, sal_uInt32 nRequiredKeyLen )
318 {
319 sal_uInt8 pnBuffer[ 64 ];
320 memset( pnBuffer, 0x36, sizeof( pnBuffer ) );
321 for( sal_uInt32 i = 0; i < nHashLen; ++i )
322 pnBuffer[ i ] ^= pnHash[ i ];
323
324 rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
325 rtlDigestError aError = rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) );
326 sal_uInt8 pnX1[ RTL_DIGEST_LENGTH_SHA1 ];
327 aError = rtl_digest_get( aDigest, pnX1, RTL_DIGEST_LENGTH_SHA1 );
328 rtl_digest_destroy( aDigest );
329
330 memset( pnBuffer, 0x5C, sizeof( pnBuffer ) );
331 for( sal_uInt32 i = 0; i < nHashLen; ++i )
332 pnBuffer[ i ] ^= pnHash[ i ];
333
334 aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
335 aError = rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) );
336 sal_uInt8 pnX2[ RTL_DIGEST_LENGTH_SHA1 ];
337 aError = rtl_digest_get( aDigest, pnX2, RTL_DIGEST_LENGTH_SHA1 );
338 rtl_digest_destroy( aDigest );
339
340 if( nRequiredKeyLen > RTL_DIGEST_LENGTH_SHA1 )
341 {
342 memcpy( pnKeyDerived + RTL_DIGEST_LENGTH_SHA1, pnX2, nRequiredKeyLen - RTL_DIGEST_LENGTH_SHA1 );
343 nRequiredKeyLen = RTL_DIGEST_LENGTH_SHA1;
344 }
345 memcpy( pnKeyDerived, pnX1, nRequiredKeyLen );
346 }
347
348 // ----------------------------------------------------------------------------
349
lclCheckEncryptionData(const sal_uInt8 * pnKey,sal_uInt32 nKeySize,const sal_uInt8 * pnVerifier,sal_uInt32 nVerifierSize,const sal_uInt8 * pnVerifierHash,sal_uInt32 nVerifierHashSize)350 bool lclCheckEncryptionData( const sal_uInt8* pnKey, sal_uInt32 nKeySize, const sal_uInt8* pnVerifier, sal_uInt32 nVerifierSize, const sal_uInt8* pnVerifierHash, sal_uInt32 nVerifierHashSize )
351 {
352 bool bResult = false;
353
354 // the only currently supported algorithm needs key size 128
355 if ( nKeySize == 16 && nVerifierSize == 16 && nVerifierHashSize == 32 )
356 {
357 // check password
358 EVP_CIPHER_CTX aes_ctx;
359 EVP_CIPHER_CTX_init( &aes_ctx );
360 EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
361 EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
362 int nOutLen = 0;
363 sal_uInt8 pnTmpVerifier[ 16 ];
364 (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) );
365
366 /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifier, &nOutLen, pnVerifier, nVerifierSize );
367 EVP_CIPHER_CTX_cleanup( &aes_ctx );
368
369 EVP_CIPHER_CTX_init( &aes_ctx );
370 EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
371 EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
372 sal_uInt8 pnTmpVerifierHash[ 32 ];
373 (void) memset( pnTmpVerifierHash, 0, sizeof(pnTmpVerifierHash) );
374
375 /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifierHash, &nOutLen, pnVerifierHash, nVerifierHashSize );
376 EVP_CIPHER_CTX_cleanup( &aes_ctx );
377
378 rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
379 rtlDigestError aError = rtl_digest_update( aDigest, pnTmpVerifier, sizeof( pnTmpVerifier ) );
380 sal_uInt8 pnSha1Hash[ RTL_DIGEST_LENGTH_SHA1 ];
381 aError = rtl_digest_get( aDigest, pnSha1Hash, RTL_DIGEST_LENGTH_SHA1 );
382 rtl_digest_destroy( aDigest );
383
384 bResult = ( memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0 );
385 }
386
387 return bResult;
388 }
389
390 // ----------------------------------------------------------------------------
391
lclGenerateEncryptionKey(const PackageEncryptionInfo & rEncrInfo,const OUString & rPassword,sal_uInt8 * pnKey,sal_uInt32 nRequiredKeyLen)392 Sequence< NamedValue > lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncrInfo, const OUString& rPassword, sal_uInt8* pnKey, sal_uInt32 nRequiredKeyLen )
393 {
394 size_t nBufferSize = rEncrInfo.mnSaltSize + 2 * rPassword.getLength();
395 sal_uInt8* pnBuffer = new sal_uInt8[ nBufferSize ];
396 memcpy( pnBuffer, rEncrInfo.mpnSalt, rEncrInfo.mnSaltSize );
397
398 sal_uInt8* pnPasswordLoc = pnBuffer + rEncrInfo.mnSaltSize;
399 const sal_Unicode* pStr = rPassword.getStr();
400 for( sal_Int32 i = 0, nLen = rPassword.getLength(); i < nLen; ++i, ++pStr, pnPasswordLoc += 2 )
401 ByteOrderConverter::writeLittleEndian( pnPasswordLoc, static_cast< sal_uInt16 >( *pStr ) );
402
403 rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
404 rtlDigestError aError = rtl_digest_update( aDigest, pnBuffer, nBufferSize );
405 delete[] pnBuffer;
406
407 size_t nHashSize = RTL_DIGEST_LENGTH_SHA1 + 4;
408 sal_uInt8* pnHash = new sal_uInt8[ nHashSize ];
409 aError = rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
410 rtl_digest_destroy( aDigest );
411
412 for( sal_uInt32 i = 0; i < 50000; ++i )
413 {
414 ByteOrderConverter::writeLittleEndian( pnHash, i );
415 aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
416 aError = rtl_digest_update( aDigest, pnHash, nHashSize );
417 aError = rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
418 rtl_digest_destroy( aDigest );
419 }
420
421 memmove( pnHash, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
422 memset( pnHash + RTL_DIGEST_LENGTH_SHA1, 0, 4 );
423 aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
424 aError = rtl_digest_update( aDigest, pnHash, nHashSize );
425 aError = rtl_digest_get( aDigest, pnHash, RTL_DIGEST_LENGTH_SHA1 );
426 rtl_digest_destroy( aDigest );
427
428 lclDeriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, pnKey, nRequiredKeyLen );
429 delete[] pnHash;
430
431 Sequence< NamedValue > aResult;
432 if( lclCheckEncryptionData( pnKey, nRequiredKeyLen, rEncrInfo.mpnEncrVerifier, sizeof( rEncrInfo.mpnEncrVerifier ), rEncrInfo.mpnEncrVerifierHash, sizeof( rEncrInfo.mpnEncrVerifierHash ) ) )
433 {
434 SequenceAsHashMap aEncryptionData;
435 aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionKey" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pnKey ), nRequiredKeyLen );
436 aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionSalt" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnSalt ), rEncrInfo.mnSaltSize );
437 aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionVerifier" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifier ), sizeof( rEncrInfo.mpnEncrVerifier ) );
438 aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionVerifierHash" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifierHash ), sizeof( rEncrInfo.mpnEncrVerifierHash ) );
439 aResult = aEncryptionData.getAsConstNamedValueList();
440 }
441
442 return aResult;
443 }
444
445 // the password verifier ------------------------------------------------------
446
447 class PasswordVerifier : public ::comphelper::IDocPasswordVerifier
448 {
449 public:
450 explicit PasswordVerifier( const PackageEncryptionInfo& rEncryptInfo );
451
452 virtual ::comphelper::DocPasswordVerifierResult
453 verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData );
454 virtual ::comphelper::DocPasswordVerifierResult
455 verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData );
456
getKey() const457 inline const sal_uInt8* getKey() const { return &maKey.front(); }
458
459 private:
460 const PackageEncryptionInfo& mrEncryptInfo;
461 ::std::vector< sal_uInt8 > maKey;
462 };
463
PasswordVerifier(const PackageEncryptionInfo & rEncryptInfo)464 PasswordVerifier::PasswordVerifier( const PackageEncryptionInfo& rEncryptInfo ) :
465 mrEncryptInfo( rEncryptInfo ),
466 maKey( static_cast< size_t >( rEncryptInfo.mnKeySize / 8 ), 0 )
467 {
468 }
469
verifyPassword(const OUString & rPassword,Sequence<NamedValue> & o_rEncryptionData)470 ::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData )
471 {
472 // verifies the password and writes the related decryption key into maKey
473 o_rEncryptionData = lclGenerateEncryptionKey( mrEncryptInfo, rPassword, &maKey.front(), maKey.size() );
474 return o_rEncryptionData.hasElements() ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
475 }
476
verifyEncryptionData(const Sequence<NamedValue> & rEncryptionData)477 ::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData )
478 {
479 SequenceAsHashMap aHashData( rEncryptionData );
480 Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionKey" ), Sequence< sal_Int8 >() );
481 Sequence< sal_Int8 > aVerifier = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionVerifier" ), Sequence< sal_Int8 >() );
482 Sequence< sal_Int8 > aVerifierHash = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionVerifierHash" ), Sequence< sal_Int8 >() );
483
484 bool bResult = lclCheckEncryptionData(
485 reinterpret_cast< const sal_uInt8* >( aKey.getConstArray() ), aKey.getLength(),
486 reinterpret_cast< const sal_uInt8* >( aVerifier.getConstArray() ), aVerifier.getLength(),
487 reinterpret_cast< const sal_uInt8* >( aVerifierHash.getConstArray() ), aVerifierHash.getLength() );
488
489 return bResult ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
490 }
491
492 } // namespace
493
494 // ----------------------------------------------------------------------------
495
extractUnencryptedPackage(MediaDescriptor & rMediaDesc) const496 Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescriptor& rMediaDesc ) const
497 {
498 // try the plain input stream
499 Reference< XInputStream > xInStrm( rMediaDesc[ MediaDescriptor::PROP_INPUTSTREAM() ], UNO_QUERY );
500 if( !xInStrm.is() || lclIsZipPackage( mxContext, xInStrm ) )
501 return xInStrm;
502
503 // check if a temporary file is passed in the 'ComponentData' property
504 Reference< XStream > xDecrypted( rMediaDesc.getComponentDataEntry( CREATE_OUSTRING( "DecryptedPackage" ) ), UNO_QUERY );
505 if( xDecrypted.is() )
506 {
507 Reference< XInputStream > xDecrInStrm = xDecrypted->getInputStream();
508 if( lclIsZipPackage( mxContext, xDecrInStrm ) )
509 return xDecrInStrm;
510 }
511
512 // try to decrypt an encrypted OLE package
513 ::oox::ole::OleStorage aOleStorage( mxContext, xInStrm, false );
514 if( aOleStorage.isStorage() ) try
515 {
516 // open the required input streams in the encrypted package
517 Reference< XInputStream > xEncryptionInfo( aOleStorage.openInputStream( CREATE_OUSTRING( "EncryptionInfo" ) ), UNO_SET_THROW );
518 Reference< XInputStream > xEncryptedPackage( aOleStorage.openInputStream( CREATE_OUSTRING( "EncryptedPackage" ) ), UNO_SET_THROW );
519
520 // read the encryption info stream
521 PackageEncryptionInfo aEncryptInfo;
522 BinaryXInputStream aInfoStrm( xEncryptionInfo, true );
523 bool bValidInfo = lclReadEncryptionInfo( aEncryptInfo, aInfoStrm );
524
525 // check flags and agorithm IDs, requiered are AES128 and SHA-1
526 bool bImplemented = bValidInfo &&
527 getFlag( aEncryptInfo.mnFlags, ENCRYPTINFO_CRYPTOAPI ) &&
528 getFlag( aEncryptInfo.mnFlags, ENCRYPTINFO_AES ) &&
529 // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set
530 ((aEncryptInfo.mnAlgorithmId == 0) || (aEncryptInfo.mnAlgorithmId == ENCRYPT_ALGO_AES128)) &&
531 // hash algorithm ID 0 defaults to SHA-1 too
532 ((aEncryptInfo.mnAlgorithmIdHash == 0) || (aEncryptInfo.mnAlgorithmIdHash == ENCRYPT_HASH_SHA1)) &&
533 (aEncryptInfo.mnVerifierHashSize == 20);
534
535 if( bImplemented )
536 {
537 /* "VelvetSweatshop" is the built-in default encryption
538 password used by MS Excel for the "workbook protection"
539 feature with password. Try this first before prompting the
540 user for a password. */
541 ::std::vector< OUString > aDefaultPasswords;
542 aDefaultPasswords.push_back( CREATE_OUSTRING( "VelvetSweatshop" ) );
543
544 /* Use the comphelper password helper to request a password.
545 This helper returns either with the correct password
546 (according to the verifier), or with an empty string if
547 user has cancelled the password input dialog. */
548 PasswordVerifier aVerifier( aEncryptInfo );
549 Sequence< NamedValue > aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
550 aVerifier, rMediaDesc, ::comphelper::DocPasswordRequestType_MS, &aDefaultPasswords );
551
552 if( aEncryptionData.getLength() == 0 )
553 {
554 rMediaDesc[ MediaDescriptor::PROP_ABORTED() ] <<= true;
555 }
556 else
557 {
558 // create temporary file for unencrypted package
559 Reference< XMultiServiceFactory > xFactory( mxContext->getServiceManager(), UNO_QUERY_THROW );
560 Reference< XStream > xTempFile( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.io.TempFile" ) ), UNO_QUERY_THROW );
561 Reference< XOutputStream > xDecryptedPackage( xTempFile->getOutputStream(), UNO_SET_THROW );
562 BinaryXOutputStream aDecryptedPackage( xDecryptedPackage, true );
563 BinaryXInputStream aEncryptedPackage( xEncryptedPackage, true );
564
565 EVP_CIPHER_CTX aes_ctx;
566 EVP_CIPHER_CTX_init( &aes_ctx );
567 EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, aVerifier.getKey(), 0 );
568 EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
569
570 sal_uInt8 pnInBuffer[ 1024 ];
571 sal_uInt8 pnOutBuffer[ 1024 ];
572 sal_Int32 nInLen;
573 int nOutLen;
574 aEncryptedPackage.skip( 8 ); // decrypted size
575 while( (nInLen = aEncryptedPackage.readMemory( pnInBuffer, sizeof( pnInBuffer ) )) > 0 )
576 {
577 EVP_DecryptUpdate( &aes_ctx, pnOutBuffer, &nOutLen, pnInBuffer, nInLen );
578 aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen );
579 }
580 EVP_DecryptFinal_ex( &aes_ctx, pnOutBuffer, &nOutLen );
581 aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen );
582
583 EVP_CIPHER_CTX_cleanup( &aes_ctx );
584 xDecryptedPackage->flush();
585 aDecryptedPackage.seekToStart();
586
587 // store temp file in media descriptor to keep it alive
588 rMediaDesc.setComponentDataEntry( CREATE_OUSTRING( "DecryptedPackage" ), Any( xTempFile ) );
589
590 Reference< XInputStream > xDecrInStrm = xTempFile->getInputStream();
591 if( lclIsZipPackage( mxContext, xDecrInStrm ) )
592 return xDecrInStrm;
593 }
594 }
595 }
596 catch( Exception& )
597 {
598 }
599
600 return Reference< XInputStream >();
601 }
602
603 // com.sun.star.lang.XServiceInfo interface -----------------------------------
604
getImplementationName()605 OUString SAL_CALL FilterDetect::getImplementationName() throw( RuntimeException )
606 {
607 return FilterDetect_getImplementationName();
608 }
609
supportsService(const OUString & rServiceName)610 sal_Bool SAL_CALL FilterDetect::supportsService( const OUString& rServiceName ) throw( RuntimeException )
611 {
612 const Sequence< OUString > aServices = FilterDetect_getSupportedServiceNames();
613 const OUString* pArray = aServices.getConstArray();
614 const OUString* pArrayEnd = pArray + aServices.getLength();
615 return ::std::find( pArray, pArrayEnd, rServiceName ) != pArrayEnd;
616 }
617
getSupportedServiceNames()618 Sequence< OUString > SAL_CALL FilterDetect::getSupportedServiceNames() throw( RuntimeException )
619 {
620 return FilterDetect_getSupportedServiceNames();
621 }
622
623 // com.sun.star.document.XExtendedFilterDetection interface -------------------
624
detect(Sequence<PropertyValue> & rMediaDescSeq)625 OUString SAL_CALL FilterDetect::detect( Sequence< PropertyValue >& rMediaDescSeq ) throw( RuntimeException )
626 {
627 OUString aFilterName;
628 MediaDescriptor aMediaDesc( rMediaDescSeq );
629
630 /* Check that the user has not choosen to abort detection, e.g. by hitting
631 'Cancel' in the password input dialog. This may happen because this
632 filter detection is used by different filters. */
633 bool bAborted = aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_ABORTED(), false );
634 if( !bAborted ) try
635 {
636 aMediaDesc.addInputStream();
637
638 /* Get the unencrypted input stream. This may include creation of a
639 temporary file that contains the decrypted package. This temporary
640 file will be stored in the 'ComponentData' property of the media
641 descriptor. */
642 Reference< XInputStream > xInStrm( extractUnencryptedPackage( aMediaDesc ), UNO_SET_THROW );
643
644 // stream must be a ZIP package
645 ZipStorage aZipStorage( mxContext, xInStrm );
646 if( aZipStorage.isStorage() )
647 {
648 // create the fast parser, register the XML namespaces, set document handler
649 FastParser aParser( mxContext );
650 aParser.registerNamespace( NMSP_packageRel );
651 aParser.registerNamespace( NMSP_officeRel );
652 aParser.registerNamespace( NMSP_packageContentTypes );
653 aParser.setDocumentHandler( new FilterDetectDocHandler( aFilterName ) );
654
655 /* Parse '_rels/.rels' to get the target path and '[Content_Types].xml'
656 to determine the content type of the part at the target path. */
657 aParser.parseStream( aZipStorage, CREATE_OUSTRING( "_rels/.rels" ) );
658 aParser.parseStream( aZipStorage, CREATE_OUSTRING( "[Content_Types].xml" ) );
659 }
660 }
661 catch( Exception& )
662 {
663 }
664
665 // write back changed media descriptor members
666 aMediaDesc >> rMediaDescSeq;
667 return aFilterName;
668 }
669
670 // ============================================================================
671
672 } // namespace core
673 } // namespace oox
674