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
BiffDecoderBase()46 BiffDecoderBase::BiffDecoderBase() :
47 mbValid( false )
48 {
49 }
50
~BiffDecoderBase()51 BiffDecoderBase::~BiffDecoderBase()
52 {
53 }
54
verifyPassword(const OUString & rPassword,Sequence<NamedValue> & o_rEncryptionData)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
verifyEncryptionData(const Sequence<NamedValue> & rEncryptionData)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
decode(sal_uInt8 * pnDestData,const sal_uInt8 * pnSrcData,sal_Int64 nStreamPos,sal_uInt16 nBytes)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
BiffDecoder_XOR(sal_uInt16 nKey,sal_uInt16 nHash)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
BiffDecoder_XOR(const BiffDecoder_XOR & rDecoder)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
implClone()99 BiffDecoder_XOR* BiffDecoder_XOR::implClone()
100 {
101 return new BiffDecoder_XOR( *this );
102 }
103
implVerifyPassword(const OUString & rPassword)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
implVerifyEncryptionData(const Sequence<NamedValue> & rEncryptionData)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
implDecode(sal_uInt8 * pnDestData,const sal_uInt8 * pnSrcData,sal_Int64 nStreamPos,sal_uInt16 nBytes)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. */
lclGetRcfBlock(sal_Int64 nStreamPos)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. */
lclGetRcfOffset(sal_Int64 nStreamPos)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
BiffDecoder_RCF(sal_uInt8 pnSalt[16],sal_uInt8 pnVerifier[16],sal_uInt8 pnVerifierHash[16])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
BiffDecoder_RCF(const BiffDecoder_RCF & rDecoder)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
implClone()185 BiffDecoder_RCF* BiffDecoder_RCF::implClone()
186 {
187 return new BiffDecoder_RCF( *this );
188 }
189
implVerifyPassword(const OUString & rPassword)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
implVerifyEncryptionData(const Sequence<NamedValue> & rEncryptionData)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
implDecode(sal_uInt8 * pnDestData,const sal_uInt8 * pnSrcData,sal_Int64 nStreamPos,sal_uInt16 nBytes)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
lclReadFilePass_XOR(BiffInputStream & rStrm)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
lclReadFilePass_RCF(BiffInputStream & rStrm)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
lclReadFilePass_CryptoApi(BiffInputStream &)298 BiffDecoderRef lclReadFilePass_CryptoApi( BiffInputStream& /*rStrm*/ )
299 {
300 // not supported
301 return BiffDecoderRef();
302 }
303
lclReadFilePassBiff8(BiffInputStream & rStrm)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
BiffCodecHelper(const WorkbookHelper & rHelper)342 BiffCodecHelper::BiffCodecHelper( const WorkbookHelper& rHelper ) :
343 WorkbookHelper( rHelper )
344 {
345 }
346
implReadFilePass(BiffInputStream & rStrm,BiffType eBiff)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
importFilePass(BiffInputStream & rStrm)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
cloneDecoder(BiffInputStream & rStrm)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