xref: /aoo41x/main/oox/source/xls/biffcodec.cxx (revision cdf0e10c)
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