1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: biffcodec.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/xls/biffcodec.hxx"
32 #include <osl/thread.h>
34 #include "oox/core/filterbase.hxx"
35 #include "oox/xls/biffinputstream.hxx"
38 using ::rtl::OUString
;
39 using ::rtl::OStringToOUString
;
40 using ::oox::core::FilterBase
;
45 // ============================================================================
47 BiffDecoderBase::BiffDecoderBase() :
52 BiffDecoderBase::~BiffDecoderBase()
56 ::comphelper::DocPasswordVerifierResult
BiffDecoderBase::verifyPassword( const OUString
& rPassword
)
58 mbValid
= implVerify( rPassword
);
59 return mbValid
? ::comphelper::DocPasswordVerifierResult_OK
: ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD
;
62 void BiffDecoderBase::decode( sal_uInt8
* pnDestData
, const sal_uInt8
* pnSrcData
, sal_Int64 nStreamPos
, sal_uInt16 nBytes
)
64 if( pnDestData
&& pnSrcData
&& (nBytes
> 0) )
67 implDecode( pnDestData
, pnSrcData
, nStreamPos
, nBytes
);
69 memcpy( pnDestData
, pnSrcData
, nBytes
);
73 // ============================================================================
75 BiffDecoder_XOR::BiffDecoder_XOR( sal_uInt16 nKey
, sal_uInt16 nHash
) :
76 maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL
),
83 BiffDecoder_XOR::BiffDecoder_XOR( const BiffDecoder_XOR
& rDecoder
) :
84 BiffDecoderBase(), // must be called to prevent compiler warning
85 maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL
),
86 maPassword( rDecoder
.maPassword
),
87 mnKey( rDecoder
.mnKey
),
88 mnHash( rDecoder
.mnHash
)
91 maCodec
.initKey( &maPassword
.front() );
94 BiffDecoder_XOR
* BiffDecoder_XOR::implClone()
96 return new BiffDecoder_XOR( *this );
99 bool BiffDecoder_XOR::implVerify( const OUString
& rPassword
)
101 /* Convert password to a byte string. TODO: this needs some finetuning
102 according to the spec... */
103 OString aBytePassword
= OUStringToOString( rPassword
, osl_getThreadTextEncoding() );
104 sal_Int32 nLen
= aBytePassword
.getLength();
105 if( (0 < nLen
) && (nLen
< 16) )
107 // copy byte string to sal_uInt8 array
109 maPassword
.resize( 16, 0 );
110 memcpy( &maPassword
.front(), aBytePassword
.getStr(), static_cast< size_t >( nLen
) );
113 maCodec
.initKey( &maPassword
.front() );
114 return maCodec
.verifyKey( mnKey
, mnHash
);
119 void BiffDecoder_XOR::implDecode( sal_uInt8
* pnDestData
, const sal_uInt8
* pnSrcData
, sal_Int64 nStreamPos
, sal_uInt16 nBytes
)
121 maCodec
.startBlock();
122 maCodec
.skip( static_cast< sal_Int32
>( (nStreamPos
+ nBytes
) & 0x0F ) );
123 maCodec
.decode( pnDestData
, pnSrcData
, nBytes
);
126 // ============================================================================
130 /** Returns the block index of the passed stream position for RCF decryption. */
131 sal_Int32
lclGetRcfBlock( sal_Int64 nStreamPos
)
133 return static_cast< sal_Int32
>( nStreamPos
/ BIFF_RCF_BLOCKSIZE
);
136 /** Returns the offset of the passed stream position in a block for RCF decryption. */
137 sal_Int32
lclGetRcfOffset( sal_Int64 nStreamPos
)
139 return static_cast< sal_Int32
>( nStreamPos
% BIFF_RCF_BLOCKSIZE
);
144 // ----------------------------------------------------------------------------
146 BiffDecoder_RCF::BiffDecoder_RCF( sal_uInt8 pnSalt
[ 16 ], sal_uInt8 pnVerifier
[ 16 ], sal_uInt8 pnVerifierHash
[ 16 ] ) :
148 maSalt( pnSalt
, pnSalt
+ 16 ),
149 maVerifier( pnVerifier
, pnVerifier
+ 16 ),
150 maVerifierHash( pnVerifierHash
, pnVerifierHash
+ 16 )
154 BiffDecoder_RCF::BiffDecoder_RCF( const BiffDecoder_RCF
& rDecoder
) :
155 BiffDecoderBase(), // must be called to prevent compiler warning
156 maPassword( rDecoder
.maPassword
),
157 maSalt( rDecoder
.maSalt
),
158 maVerifier( rDecoder
.maVerifier
),
159 maVerifierHash( rDecoder
.maVerifierHash
)
162 maCodec
.initKey( &maPassword
.front(), &maSalt
.front() );
165 BiffDecoder_RCF
* BiffDecoder_RCF::implClone()
167 return new BiffDecoder_RCF( *this );
170 bool BiffDecoder_RCF::implVerify( const OUString
& rPassword
)
172 sal_Int32 nLen
= rPassword
.getLength();
173 if( (0 < nLen
) && (nLen
< 16) )
175 // copy string to sal_uInt16 array
177 maPassword
.resize( 16, 0 );
178 const sal_Unicode
* pcChar
= rPassword
.getStr();
179 const sal_Unicode
* pcCharEnd
= pcChar
+ nLen
;
180 ::std::vector
< sal_uInt16
>::iterator aIt
= maPassword
.begin();
181 for( ; pcChar
< pcCharEnd
; ++pcChar
, ++aIt
)
182 *aIt
= static_cast< sal_uInt16
>( *pcChar
);
185 maCodec
.initKey( &maPassword
.front(), &maSalt
.front() );
186 return maCodec
.verifyKey( &maVerifier
.front(), &maVerifierHash
.front() );
191 void BiffDecoder_RCF::implDecode( sal_uInt8
* pnDestData
, const sal_uInt8
* pnSrcData
, sal_Int64 nStreamPos
, sal_uInt16 nBytes
)
193 sal_uInt8
* pnCurrDest
= pnDestData
;
194 const sal_uInt8
* pnCurrSrc
= pnSrcData
;
195 sal_Int64 nCurrPos
= nStreamPos
;
196 sal_uInt16 nBytesLeft
= nBytes
;
197 while( nBytesLeft
> 0 )
199 // initialize codec for current stream position
200 maCodec
.startBlock( lclGetRcfBlock( nCurrPos
) );
201 maCodec
.skip( lclGetRcfOffset( nCurrPos
) );
204 sal_uInt16 nBlockLeft
= static_cast< sal_uInt16
>( BIFF_RCF_BLOCKSIZE
- lclGetRcfOffset( nCurrPos
) );
205 sal_uInt16 nDecBytes
= ::std::min( nBytesLeft
, nBlockLeft
);
206 maCodec
.decode( pnCurrDest
, pnCurrSrc
, static_cast< sal_Int32
>( nDecBytes
) );
208 // prepare for next block
209 pnCurrDest
+= nDecBytes
;
210 pnCurrSrc
+= nDecBytes
;
211 nCurrPos
+= nDecBytes
;
212 nBytesLeft
= nBytesLeft
- nDecBytes
;
216 // ============================================================================
220 const sal_uInt16 BIFF_FILEPASS_XOR
= 0;
221 const sal_uInt16 BIFF_FILEPASS_RCF
= 1;
223 const sal_uInt16 BIFF_FILEPASS_BIFF8_RCF
= 1;
224 const sal_uInt16 BIFF_FILEPASS_BIFF8_CRYPTOAPI_2003
= 2;
225 const sal_uInt16 BIFF_FILEPASS_BIFF8_CRYPTOAPI_2007
= 3;
227 // ----------------------------------------------------------------------------
229 BiffDecoderRef
lclReadFilePass_XOR( BiffInputStream
& rStrm
)
231 BiffDecoderRef xDecoder
;
232 OSL_ENSURE( rStrm
.getRemaining() == 4, "lclReadFilePass_XOR - wrong record size" );
233 if( rStrm
.getRemaining() == 4 )
235 sal_uInt16 nBaseKey
, nHash
;
236 rStrm
>> nBaseKey
>> nHash
;
237 xDecoder
.reset( new BiffDecoder_XOR( nBaseKey
, nHash
) );
242 BiffDecoderRef
lclReadFilePass_RCF( BiffInputStream
& rStrm
)
244 BiffDecoderRef xDecoder
;
245 OSL_ENSURE( rStrm
.getRemaining() == 48, "lclReadFilePass_RCF - wrong record size" );
246 if( rStrm
.getRemaining() == 48 )
248 sal_uInt8 pnSalt
[ 16 ];
249 sal_uInt8 pnVerifier
[ 16 ];
250 sal_uInt8 pnVerifierHash
[ 16 ];
251 rStrm
.readMemory( pnSalt
, 16 );
252 rStrm
.readMemory( pnVerifier
, 16 );
253 rStrm
.readMemory( pnVerifierHash
, 16 );
254 xDecoder
.reset( new BiffDecoder_RCF( pnSalt
, pnVerifier
, pnVerifierHash
) );
259 BiffDecoderRef
lclReadFilePass_CryptoApi( BiffInputStream
& /*rStrm*/ )
262 return BiffDecoderRef();
265 BiffDecoderRef
lclReadFilePassBiff8( BiffInputStream
& rStrm
)
267 BiffDecoderRef xDecoder
;
268 switch( rStrm
.readuInt16() )
270 case BIFF_FILEPASS_XOR
:
271 xDecoder
= lclReadFilePass_XOR( rStrm
);
274 case BIFF_FILEPASS_RCF
:
276 sal_uInt16 nMajor
= rStrm
.readuInt16();
280 case BIFF_FILEPASS_BIFF8_RCF
:
281 xDecoder
= lclReadFilePass_RCF( rStrm
);
283 case BIFF_FILEPASS_BIFF8_CRYPTOAPI_2003
:
284 case BIFF_FILEPASS_BIFF8_CRYPTOAPI_2007
:
285 xDecoder
= lclReadFilePass_CryptoApi( rStrm
);
288 OSL_ENSURE( false, "lclReadFilePassBiff8 - unknown BIFF8 encryption sub mode" );
294 OSL_ENSURE( false, "lclReadFilePassBiff8 - unknown encryption mode" );
301 // ----------------------------------------------------------------------------
303 BiffCodecHelper::BiffCodecHelper( const WorkbookHelper
& rHelper
) :
304 WorkbookHelper( rHelper
)
308 /*static*/ BiffDecoderRef
BiffCodecHelper::implReadFilePass( BiffInputStream
& rStrm
, BiffType eBiff
)
310 rStrm
.enableDecoder( false );
311 BiffDecoderRef xDecoder
= (eBiff
== BIFF8
) ? lclReadFilePassBiff8( rStrm
) : lclReadFilePass_XOR( rStrm
);
312 rStrm
.setDecoder( xDecoder
);
316 bool BiffCodecHelper::importFilePass( BiffInputStream
& rStrm
)
318 OSL_ENSURE( !mxDecoder
, "BiffCodecHelper::importFilePass - multiple FILEPASS records" );
319 mxDecoder
= implReadFilePass( rStrm
, getBiff() );
320 // request and verify a password (decoder implements IDocPasswordVerifier)
321 if( mxDecoder
.get() )
322 getBaseFilter().requestPassword( *mxDecoder
);
323 // correct password is indicated by isValid() function of decoder
324 return mxDecoder
.get() && mxDecoder
->isValid();
327 void BiffCodecHelper::cloneDecoder( BiffInputStream
& rStrm
)
329 if( mxDecoder
.get() )
330 rStrm
.setDecoder( BiffDecoderRef( mxDecoder
->clone() ) );
333 // ============================================================================