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

Generated by: LCOV version 1.10