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