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