xref: /aoo4110/main/oox/source/core/filterdetect.cxx (revision b1cdbd2c)
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