1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "oox/xls/biffcodec.hxx" 29 30 #include <osl/thread.h> 31 #include <string.h> 32 #include "oox/core/filterbase.hxx" 33 #include "oox/xls/biffinputstream.hxx" 34 35 namespace oox { 36 namespace xls { 37 38 // ============================================================================ 39 40 using namespace ::com::sun::star::beans; 41 using namespace ::com::sun::star::uno; 42 43 using ::oox::core::FilterBase; 44 using ::rtl::OString; 45 using ::rtl::OUString; 46 using ::rtl::OStringToOUString; 47 48 // ============================================================================ 49 50 BiffDecoderBase::BiffDecoderBase() : 51 mbValid( false ) 52 { 53 } 54 55 BiffDecoderBase::~BiffDecoderBase() 56 { 57 } 58 59 ::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData ) 60 { 61 o_rEncryptionData = implVerifyPassword( rPassword ); 62 mbValid = o_rEncryptionData.hasElements(); 63 return mbValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; 64 } 65 66 ::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) 67 { 68 mbValid = implVerifyEncryptionData( rEncryptionData ); 69 return mbValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; 70 } 71 72 void BiffDecoderBase::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes ) 73 { 74 if( pnDestData && pnSrcData && (nBytes > 0) ) 75 { 76 if( mbValid ) 77 implDecode( pnDestData, pnSrcData, nStreamPos, nBytes ); 78 else 79 memcpy( pnDestData, pnSrcData, nBytes ); 80 } 81 } 82 83 // ============================================================================ 84 85 BiffDecoder_XOR::BiffDecoder_XOR( sal_uInt16 nKey, sal_uInt16 nHash ) : 86 maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL ), 87 mnKey( nKey ), 88 mnHash( nHash ) 89 { 90 } 91 92 BiffDecoder_XOR::BiffDecoder_XOR( const BiffDecoder_XOR& rDecoder ) : 93 BiffDecoderBase(), // must be called to prevent compiler warning 94 maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL ), 95 maEncryptionData( rDecoder.maEncryptionData ), 96 mnKey( rDecoder.mnKey ), 97 mnHash( rDecoder.mnHash ) 98 { 99 if( isValid() ) 100 maCodec.initCodec( maEncryptionData ); 101 } 102 103 BiffDecoder_XOR* BiffDecoder_XOR::implClone() 104 { 105 return new BiffDecoder_XOR( *this ); 106 } 107 108 Sequence< NamedValue > BiffDecoder_XOR::implVerifyPassword( const OUString& rPassword ) 109 { 110 maEncryptionData.realloc( 0 ); 111 112 /* Convert password to a byte string. TODO: this needs some finetuning 113 according to the spec... */ 114 OString aBytePassword = OUStringToOString( rPassword, osl_getThreadTextEncoding() ); 115 sal_Int32 nLen = aBytePassword.getLength(); 116 if( (0 < nLen) && (nLen < 16) ) 117 { 118 // init codec 119 maCodec.initKey( reinterpret_cast< const sal_uInt8* >( aBytePassword.getStr() ) ); 120 121 if( maCodec.verifyKey( mnKey, mnHash ) ) 122 maEncryptionData = maCodec.getEncryptionData(); 123 } 124 125 return maEncryptionData; 126 } 127 128 bool BiffDecoder_XOR::implVerifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) 129 { 130 maEncryptionData.realloc( 0 ); 131 132 if( rEncryptionData.hasElements() ) 133 { 134 // init codec 135 maCodec.initCodec( rEncryptionData ); 136 137 if( maCodec.verifyKey( mnKey, mnHash ) ) 138 maEncryptionData = rEncryptionData; 139 } 140 141 return maEncryptionData.hasElements(); 142 } 143 144 void BiffDecoder_XOR::implDecode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes ) 145 { 146 maCodec.startBlock(); 147 maCodec.skip( static_cast< sal_Int32 >( (nStreamPos + nBytes) & 0x0F ) ); 148 maCodec.decode( pnDestData, pnSrcData, nBytes ); 149 } 150 151 // ============================================================================ 152 153 namespace { 154 155 /** Returns the block index of the passed stream position for RCF decryption. */ 156 sal_Int32 lclGetRcfBlock( sal_Int64 nStreamPos ) 157 { 158 return static_cast< sal_Int32 >( nStreamPos / BIFF_RCF_BLOCKSIZE ); 159 } 160 161 /** Returns the offset of the passed stream position in a block for RCF decryption. */ 162 sal_Int32 lclGetRcfOffset( sal_Int64 nStreamPos ) 163 { 164 return static_cast< sal_Int32 >( nStreamPos % BIFF_RCF_BLOCKSIZE ); 165 } 166 167 } // namespace 168 169 // ---------------------------------------------------------------------------- 170 171 BiffDecoder_RCF::BiffDecoder_RCF( sal_uInt8 pnSalt[ 16 ], sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] ) : 172 maSalt( pnSalt, pnSalt + 16 ), 173 maVerifier( pnVerifier, pnVerifier + 16 ), 174 maVerifierHash( pnVerifierHash, pnVerifierHash + 16 ) 175 { 176 } 177 178 BiffDecoder_RCF::BiffDecoder_RCF( const BiffDecoder_RCF& rDecoder ) : 179 BiffDecoderBase(), // must be called to prevent compiler warning 180 maEncryptionData( rDecoder.maEncryptionData ), 181 maSalt( rDecoder.maSalt ), 182 maVerifier( rDecoder.maVerifier ), 183 maVerifierHash( rDecoder.maVerifierHash ) 184 { 185 if( isValid() ) 186 maCodec.initCodec( maEncryptionData ); 187 } 188 189 BiffDecoder_RCF* BiffDecoder_RCF::implClone() 190 { 191 return new BiffDecoder_RCF( *this ); 192 } 193 194 Sequence< NamedValue > BiffDecoder_RCF::implVerifyPassword( const OUString& rPassword ) 195 { 196 maEncryptionData.realloc( 0 ); 197 198 sal_Int32 nLen = rPassword.getLength(); 199 if( (0 < nLen) && (nLen < 16) ) 200 { 201 // copy string to sal_uInt16 array 202 ::std::vector< sal_uInt16 > aPassVect( 16 ); 203 const sal_Unicode* pcChar = rPassword.getStr(); 204 const sal_Unicode* pcCharEnd = pcChar + nLen; 205 ::std::vector< sal_uInt16 >::iterator aIt = aPassVect.begin(); 206 for( ; pcChar < pcCharEnd; ++pcChar, ++aIt ) 207 *aIt = static_cast< sal_uInt16 >( *pcChar ); 208 209 // init codec 210 maCodec.initKey( &aPassVect.front(), &maSalt.front() ); 211 if( maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() ) ) 212 maEncryptionData = maCodec.getEncryptionData(); 213 } 214 215 return maEncryptionData; 216 } 217 218 bool BiffDecoder_RCF::implVerifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) 219 { 220 maEncryptionData.realloc( 0 ); 221 222 if( rEncryptionData.hasElements() ) 223 { 224 // init codec 225 maCodec.initCodec( rEncryptionData ); 226 227 if( maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() ) ) 228 maEncryptionData = rEncryptionData; 229 } 230 231 return maEncryptionData.hasElements(); 232 } 233 234 void BiffDecoder_RCF::implDecode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes ) 235 { 236 sal_uInt8* pnCurrDest = pnDestData; 237 const sal_uInt8* pnCurrSrc = pnSrcData; 238 sal_Int64 nCurrPos = nStreamPos; 239 sal_uInt16 nBytesLeft = nBytes; 240 while( nBytesLeft > 0 ) 241 { 242 // initialize codec for current stream position 243 maCodec.startBlock( lclGetRcfBlock( nCurrPos ) ); 244 maCodec.skip( lclGetRcfOffset( nCurrPos ) ); 245 246 // decode the block 247 sal_uInt16 nBlockLeft = static_cast< sal_uInt16 >( BIFF_RCF_BLOCKSIZE - lclGetRcfOffset( nCurrPos ) ); 248 sal_uInt16 nDecBytes = ::std::min( nBytesLeft, nBlockLeft ); 249 maCodec.decode( pnCurrDest, pnCurrSrc, static_cast< sal_Int32 >( nDecBytes ) ); 250 251 // prepare for next block 252 pnCurrDest += nDecBytes; 253 pnCurrSrc += nDecBytes; 254 nCurrPos += nDecBytes; 255 nBytesLeft = nBytesLeft - nDecBytes; 256 } 257 } 258 259 // ============================================================================ 260 261 namespace { 262 263 const sal_uInt16 BIFF_FILEPASS_XOR = 0; 264 const sal_uInt16 BIFF_FILEPASS_RCF = 1; 265 266 const sal_uInt16 BIFF_FILEPASS_BIFF8_RCF = 1; 267 const sal_uInt16 BIFF_FILEPASS_BIFF8_CRYPTOAPI_2003 = 2; 268 const sal_uInt16 BIFF_FILEPASS_BIFF8_CRYPTOAPI_2007 = 3; 269 270 // ---------------------------------------------------------------------------- 271 272 BiffDecoderRef lclReadFilePass_XOR( BiffInputStream& rStrm ) 273 { 274 BiffDecoderRef xDecoder; 275 OSL_ENSURE( rStrm.getRemaining() == 4, "lclReadFilePass_XOR - wrong record size" ); 276 if( rStrm.getRemaining() == 4 ) 277 { 278 sal_uInt16 nBaseKey, nHash; 279 rStrm >> nBaseKey >> nHash; 280 xDecoder.reset( new BiffDecoder_XOR( nBaseKey, nHash ) ); 281 } 282 return xDecoder; 283 } 284 285 BiffDecoderRef lclReadFilePass_RCF( BiffInputStream& rStrm ) 286 { 287 BiffDecoderRef xDecoder; 288 OSL_ENSURE( rStrm.getRemaining() == 48, "lclReadFilePass_RCF - wrong record size" ); 289 if( rStrm.getRemaining() == 48 ) 290 { 291 sal_uInt8 pnSalt[ 16 ]; 292 sal_uInt8 pnVerifier[ 16 ]; 293 sal_uInt8 pnVerifierHash[ 16 ]; 294 rStrm.readMemory( pnSalt, 16 ); 295 rStrm.readMemory( pnVerifier, 16 ); 296 rStrm.readMemory( pnVerifierHash, 16 ); 297 xDecoder.reset( new BiffDecoder_RCF( pnSalt, pnVerifier, pnVerifierHash ) ); 298 } 299 return xDecoder; 300 } 301 302 BiffDecoderRef lclReadFilePass_CryptoApi( BiffInputStream& /*rStrm*/ ) 303 { 304 // not supported 305 return BiffDecoderRef(); 306 } 307 308 BiffDecoderRef lclReadFilePassBiff8( BiffInputStream& rStrm ) 309 { 310 BiffDecoderRef xDecoder; 311 switch( rStrm.readuInt16() ) 312 { 313 case BIFF_FILEPASS_XOR: 314 xDecoder = lclReadFilePass_XOR( rStrm ); 315 break; 316 317 case BIFF_FILEPASS_RCF: 318 { 319 sal_uInt16 nMajor = rStrm.readuInt16(); 320 rStrm.skip( 2 ); 321 switch( nMajor ) 322 { 323 case BIFF_FILEPASS_BIFF8_RCF: 324 xDecoder = lclReadFilePass_RCF( rStrm ); 325 break; 326 case BIFF_FILEPASS_BIFF8_CRYPTOAPI_2003: 327 case BIFF_FILEPASS_BIFF8_CRYPTOAPI_2007: 328 xDecoder = lclReadFilePass_CryptoApi( rStrm ); 329 break; 330 default: 331 OSL_ENSURE( false, "lclReadFilePassBiff8 - unknown BIFF8 encryption sub mode" ); 332 } 333 } 334 break; 335 336 default: 337 OSL_ENSURE( false, "lclReadFilePassBiff8 - unknown encryption mode" ); 338 } 339 return xDecoder; 340 } 341 342 } // namespace 343 344 // ---------------------------------------------------------------------------- 345 346 BiffCodecHelper::BiffCodecHelper( const WorkbookHelper& rHelper ) : 347 WorkbookHelper( rHelper ) 348 { 349 } 350 351 /*static*/ BiffDecoderRef BiffCodecHelper::implReadFilePass( BiffInputStream& rStrm, BiffType eBiff ) 352 { 353 rStrm.enableDecoder( false ); 354 BiffDecoderRef xDecoder = (eBiff == BIFF8) ? lclReadFilePassBiff8( rStrm ) : lclReadFilePass_XOR( rStrm ); 355 rStrm.setDecoder( xDecoder ); 356 return xDecoder; 357 } 358 359 bool BiffCodecHelper::importFilePass( BiffInputStream& rStrm ) 360 { 361 OSL_ENSURE( !mxDecoder, "BiffCodecHelper::importFilePass - multiple FILEPASS records" ); 362 mxDecoder = implReadFilePass( rStrm, getBiff() ); 363 // request and verify a password (decoder implements IDocPasswordVerifier) 364 if( mxDecoder.get() ) 365 getBaseFilter().requestEncryptionData( *mxDecoder ); 366 // correct password is indicated by isValid() function of decoder 367 return mxDecoder.get() && mxDecoder->isValid(); 368 } 369 370 void BiffCodecHelper::cloneDecoder( BiffInputStream& rStrm ) 371 { 372 if( mxDecoder.get() ) 373 rStrm.setDecoder( BiffDecoderRef( mxDecoder->clone() ) ); 374 } 375 376 // ============================================================================ 377 378 } // namespace xls 379 } // namespace oox 380