summaryrefslogtreecommitdiff
path: root/oox/source/xls/biffcodec.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/xls/biffcodec.cxx')
-rw-r--r--oox/source/xls/biffcodec.cxx379
1 files changed, 379 insertions, 0 deletions
diff --git a/oox/source/xls/biffcodec.cxx b/oox/source/xls/biffcodec.cxx
new file mode 100644
index 000000000000..cb4829973fcc
--- /dev/null
+++ b/oox/source/xls/biffcodec.cxx
@@ -0,0 +1,379 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffcodec.hxx"
+
+#include <osl/thread.h>
+#include <string.h>
+#include "oox/core/filterbase.hxx"
+#include "oox/xls/biffinputstream.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+
+using ::oox::core::FilterBase;
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OStringToOUString;
+
+// ============================================================================
+
+BiffDecoderBase::BiffDecoderBase() :
+ mbValid( false )
+{
+}
+
+BiffDecoderBase::~BiffDecoderBase()
+{
+}
+
+::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData )
+{
+ o_rEncryptionData = implVerifyPassword( rPassword );
+ mbValid = o_rEncryptionData.hasElements();
+ return mbValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+}
+
+::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData )
+{
+ mbValid = implVerifyEncryptionData( rEncryptionData );
+ return mbValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+}
+
+void BiffDecoderBase::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes )
+{
+ if( pnDestData && pnSrcData && (nBytes > 0) )
+ {
+ if( mbValid )
+ implDecode( pnDestData, pnSrcData, nStreamPos, nBytes );
+ else
+ memcpy( pnDestData, pnSrcData, nBytes );
+ }
+}
+
+// ============================================================================
+
+BiffDecoder_XOR::BiffDecoder_XOR( sal_uInt16 nKey, sal_uInt16 nHash ) :
+ maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL ),
+ mnKey( nKey ),
+ mnHash( nHash )
+{
+}
+
+BiffDecoder_XOR::BiffDecoder_XOR( const BiffDecoder_XOR& rDecoder ) :
+ BiffDecoderBase(), // must be called to prevent compiler warning
+ maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL ),
+ maEncryptionData( rDecoder.maEncryptionData ),
+ mnKey( rDecoder.mnKey ),
+ mnHash( rDecoder.mnHash )
+{
+ if( isValid() )
+ maCodec.initCodec( maEncryptionData );
+}
+
+BiffDecoder_XOR* BiffDecoder_XOR::implClone()
+{
+ return new BiffDecoder_XOR( *this );
+}
+
+Sequence< NamedValue > BiffDecoder_XOR::implVerifyPassword( const OUString& rPassword )
+{
+ maEncryptionData.realloc( 0 );
+
+ /* Convert password to a byte string. TODO: this needs some finetuning
+ according to the spec... */
+ OString aBytePassword = OUStringToOString( rPassword, osl_getThreadTextEncoding() );
+ sal_Int32 nLen = aBytePassword.getLength();
+ if( (0 < nLen) && (nLen < 16) )
+ {
+ // init codec
+ maCodec.initKey( reinterpret_cast< const sal_uInt8* >( aBytePassword.getStr() ) );
+
+ if( maCodec.verifyKey( mnKey, mnHash ) )
+ maEncryptionData = maCodec.getEncryptionData();
+ }
+
+ return maEncryptionData;
+}
+
+bool BiffDecoder_XOR::implVerifyEncryptionData( const Sequence< NamedValue >& rEncryptionData )
+{
+ maEncryptionData.realloc( 0 );
+
+ if( rEncryptionData.hasElements() )
+ {
+ // init codec
+ maCodec.initCodec( rEncryptionData );
+
+ if( maCodec.verifyKey( mnKey, mnHash ) )
+ maEncryptionData = rEncryptionData;
+ }
+
+ return maEncryptionData.hasElements();
+}
+
+void BiffDecoder_XOR::implDecode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes )
+{
+ maCodec.startBlock();
+ maCodec.skip( static_cast< sal_Int32 >( (nStreamPos + nBytes) & 0x0F ) );
+ maCodec.decode( pnDestData, pnSrcData, nBytes );
+}
+
+// ============================================================================
+
+namespace {
+
+/** Returns the block index of the passed stream position for RCF decryption. */
+sal_Int32 lclGetRcfBlock( sal_Int64 nStreamPos )
+{
+ return static_cast< sal_Int32 >( nStreamPos / BIFF_RCF_BLOCKSIZE );
+}
+
+/** Returns the offset of the passed stream position in a block for RCF decryption. */
+sal_Int32 lclGetRcfOffset( sal_Int64 nStreamPos )
+{
+ return static_cast< sal_Int32 >( nStreamPos % BIFF_RCF_BLOCKSIZE );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+BiffDecoder_RCF::BiffDecoder_RCF( sal_uInt8 pnSalt[ 16 ], sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] ) :
+ maSalt( pnSalt, pnSalt + 16 ),
+ maVerifier( pnVerifier, pnVerifier + 16 ),
+ maVerifierHash( pnVerifierHash, pnVerifierHash + 16 )
+{
+}
+
+BiffDecoder_RCF::BiffDecoder_RCF( const BiffDecoder_RCF& rDecoder ) :
+ BiffDecoderBase(), // must be called to prevent compiler warning
+ maEncryptionData( rDecoder.maEncryptionData ),
+ maSalt( rDecoder.maSalt ),
+ maVerifier( rDecoder.maVerifier ),
+ maVerifierHash( rDecoder.maVerifierHash )
+{
+ if( isValid() )
+ maCodec.initCodec( maEncryptionData );
+}
+
+BiffDecoder_RCF* BiffDecoder_RCF::implClone()
+{
+ return new BiffDecoder_RCF( *this );
+}
+
+Sequence< NamedValue > BiffDecoder_RCF::implVerifyPassword( const OUString& rPassword )
+{
+ maEncryptionData.realloc( 0 );
+
+ sal_Int32 nLen = rPassword.getLength();
+ if( (0 < nLen) && (nLen < 16) )
+ {
+ // copy string to sal_uInt16 array
+ ::std::vector< sal_uInt16 > aPassVect( 16 );
+ const sal_Unicode* pcChar = rPassword.getStr();
+ const sal_Unicode* pcCharEnd = pcChar + nLen;
+ ::std::vector< sal_uInt16 >::iterator aIt = aPassVect.begin();
+ for( ; pcChar < pcCharEnd; ++pcChar, ++aIt )
+ *aIt = static_cast< sal_uInt16 >( *pcChar );
+
+ // init codec
+ maCodec.initKey( &aPassVect.front(), &maSalt.front() );
+ if( maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
+ maEncryptionData = maCodec.getEncryptionData();
+ }
+
+ return maEncryptionData;
+}
+
+bool BiffDecoder_RCF::implVerifyEncryptionData( const Sequence< NamedValue >& rEncryptionData )
+{
+ maEncryptionData.realloc( 0 );
+
+ if( rEncryptionData.hasElements() )
+ {
+ // init codec
+ maCodec.initCodec( rEncryptionData );
+
+ if( maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
+ maEncryptionData = rEncryptionData;
+ }
+
+ return maEncryptionData.hasElements();
+}
+
+void BiffDecoder_RCF::implDecode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes )
+{
+ sal_uInt8* pnCurrDest = pnDestData;
+ const sal_uInt8* pnCurrSrc = pnSrcData;
+ sal_Int64 nCurrPos = nStreamPos;
+ sal_uInt16 nBytesLeft = nBytes;
+ while( nBytesLeft > 0 )
+ {
+ // initialize codec for current stream position
+ maCodec.startBlock( lclGetRcfBlock( nCurrPos ) );
+ maCodec.skip( lclGetRcfOffset( nCurrPos ) );
+
+ // decode the block
+ sal_uInt16 nBlockLeft = static_cast< sal_uInt16 >( BIFF_RCF_BLOCKSIZE - lclGetRcfOffset( nCurrPos ) );
+ sal_uInt16 nDecBytes = ::std::min( nBytesLeft, nBlockLeft );
+ maCodec.decode( pnCurrDest, pnCurrSrc, static_cast< sal_Int32 >( nDecBytes ) );
+
+ // prepare for next block
+ pnCurrDest += nDecBytes;
+ pnCurrSrc += nDecBytes;
+ nCurrPos += nDecBytes;
+ nBytesLeft = nBytesLeft - nDecBytes;
+ }
+}
+
+// ============================================================================
+
+namespace {
+
+const sal_uInt16 BIFF_FILEPASS_XOR = 0;
+const sal_uInt16 BIFF_FILEPASS_RCF = 1;
+
+const sal_uInt16 BIFF_FILEPASS_BIFF8_RCF = 1;
+const sal_uInt16 BIFF_FILEPASS_BIFF8_CRYPTOAPI_2003 = 2;
+const sal_uInt16 BIFF_FILEPASS_BIFF8_CRYPTOAPI_2007 = 3;
+
+// ----------------------------------------------------------------------------
+
+BiffDecoderRef lclReadFilePass_XOR( BiffInputStream& rStrm )
+{
+ BiffDecoderRef xDecoder;
+ OSL_ENSURE( rStrm.getRemaining() == 4, "lclReadFilePass_XOR - wrong record size" );
+ if( rStrm.getRemaining() == 4 )
+ {
+ sal_uInt16 nBaseKey, nHash;
+ rStrm >> nBaseKey >> nHash;
+ xDecoder.reset( new BiffDecoder_XOR( nBaseKey, nHash ) );
+ }
+ return xDecoder;
+}
+
+BiffDecoderRef lclReadFilePass_RCF( BiffInputStream& rStrm )
+{
+ BiffDecoderRef xDecoder;
+ OSL_ENSURE( rStrm.getRemaining() == 48, "lclReadFilePass_RCF - wrong record size" );
+ if( rStrm.getRemaining() == 48 )
+ {
+ sal_uInt8 pnSalt[ 16 ];
+ sal_uInt8 pnVerifier[ 16 ];
+ sal_uInt8 pnVerifierHash[ 16 ];
+ rStrm.readMemory( pnSalt, 16 );
+ rStrm.readMemory( pnVerifier, 16 );
+ rStrm.readMemory( pnVerifierHash, 16 );
+ xDecoder.reset( new BiffDecoder_RCF( pnSalt, pnVerifier, pnVerifierHash ) );
+ }
+ return xDecoder;
+}
+
+BiffDecoderRef lclReadFilePass_CryptoApi( BiffInputStream& /*rStrm*/ )
+{
+ // not supported
+ return BiffDecoderRef();
+}
+
+BiffDecoderRef lclReadFilePassBiff8( BiffInputStream& rStrm )
+{
+ BiffDecoderRef xDecoder;
+ switch( rStrm.readuInt16() )
+ {
+ case BIFF_FILEPASS_XOR:
+ xDecoder = lclReadFilePass_XOR( rStrm );
+ break;
+
+ case BIFF_FILEPASS_RCF:
+ {
+ sal_uInt16 nMajor = rStrm.readuInt16();
+ rStrm.skip( 2 );
+ switch( nMajor )
+ {
+ case BIFF_FILEPASS_BIFF8_RCF:
+ xDecoder = lclReadFilePass_RCF( rStrm );
+ break;
+ case BIFF_FILEPASS_BIFF8_CRYPTOAPI_2003:
+ case BIFF_FILEPASS_BIFF8_CRYPTOAPI_2007:
+ xDecoder = lclReadFilePass_CryptoApi( rStrm );
+ break;
+ default:
+ OSL_ENSURE( false, "lclReadFilePassBiff8 - unknown BIFF8 encryption sub mode" );
+ }
+ }
+ break;
+
+ default:
+ OSL_ENSURE( false, "lclReadFilePassBiff8 - unknown encryption mode" );
+ }
+ return xDecoder;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+BiffCodecHelper::BiffCodecHelper( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper )
+{
+}
+
+/*static*/ BiffDecoderRef BiffCodecHelper::implReadFilePass( BiffInputStream& rStrm, BiffType eBiff )
+{
+ rStrm.enableDecoder( false );
+ BiffDecoderRef xDecoder = (eBiff == BIFF8) ? lclReadFilePassBiff8( rStrm ) : lclReadFilePass_XOR( rStrm );
+ rStrm.setDecoder( xDecoder );
+ return xDecoder;
+}
+
+bool BiffCodecHelper::importFilePass( BiffInputStream& rStrm )
+{
+ OSL_ENSURE( !mxDecoder, "BiffCodecHelper::importFilePass - multiple FILEPASS records" );
+ mxDecoder = implReadFilePass( rStrm, getBiff() );
+ // request and verify a password (decoder implements IDocPasswordVerifier)
+ if( mxDecoder.get() )
+ getBaseFilter().requestEncryptionData( *mxDecoder );
+ // correct password is indicated by isValid() function of decoder
+ return mxDecoder.get() && mxDecoder->isValid();
+}
+
+void BiffCodecHelper::cloneDecoder( BiffInputStream& rStrm )
+{
+ if( mxDecoder.get() )
+ rStrm.setDecoder( BiffDecoderRef( mxDecoder->clone() ) );
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox