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