LCOV - code coverage report
Current view: top level - libreoffice/oox/source/core - filterdetect.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 117 305 38.4 %
Date: 2012-12-17 Functions: 25 43 58.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10