update dev300-m57
[ooovba.git] / oox / source / core / binarycodec.cxx
blob6e465fb39cb79f9be2a98d7bc3a8a361f000ff9d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: binarycodec.cxx,v $
10 * $Revision: 1.4 $
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/core/binarycodec.hxx"
32 #include <algorithm>
33 #include <string.h>
34 #include <osl/diagnose.h>
36 namespace oox {
37 namespace core {
39 // ============================================================================
41 namespace {
43 /** Rotates rnValue left by nBits bits. */
44 template< typename Type >
45 inline void lclRotateLeft( Type& rnValue, size_t nBits )
47 OSL_ENSURE( nBits < sizeof( Type ) * 8, "lclRotateLeft - rotation count overflow" );
48 rnValue = static_cast< Type >( (rnValue << nBits) | (rnValue >> (sizeof( Type ) * 8 - nBits)) );
51 /** Rotates the lower nWidth bits of rnValue left by nBits bits. */
52 template< typename Type >
53 inline void lclRotateLeft( Type& rnValue, size_t nBits, size_t nWidth )
55 OSL_ENSURE( (nBits < nWidth) && (nWidth < sizeof( Type ) * 8), "lclRotateLeft - rotation count overflow" );
56 Type nMask = static_cast< Type >( (1UL << nWidth) - 1 );
57 rnValue = static_cast< Type >(
58 ((rnValue << nBits) | ((rnValue & nMask) >> (nWidth - nBits))) & nMask );
61 sal_Int32 lclGetLen( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
63 sal_Int32 nLen = 0;
64 while( (nLen < nBufferSize) && pnPassData[ nLen ] ) ++nLen;
65 return nLen;
68 sal_uInt16 lclGetKey( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
70 sal_Int32 nLen = lclGetLen( pnPassData, nBufferSize );
71 if( nLen <= 0 ) return 0;
73 sal_uInt16 nKey = 0;
74 sal_uInt16 nKeyBase = 0x8000;
75 sal_uInt16 nKeyEnd = 0xFFFF;
76 const sal_uInt8* pnChar = pnPassData + nLen - 1;
77 for( sal_Int32 nIndex = 0; nIndex < nLen; ++nIndex, --pnChar )
79 sal_uInt8 cChar = *pnChar & 0x7F;
80 for( size_t nBit = 0; nBit < 8; ++nBit )
82 lclRotateLeft( nKeyBase, 1 );
83 if( nKeyBase & 1 ) nKeyBase ^= 0x1020;
84 if( cChar & 1 ) nKey ^= nKeyBase;
85 cChar >>= 1;
86 lclRotateLeft( nKeyEnd, 1 );
87 if( nKeyEnd & 1 ) nKeyEnd ^= 0x1020;
90 return nKey ^ nKeyEnd;
93 sal_uInt16 lclGetHash( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
95 sal_Int32 nLen = lclGetLen( pnPassData, nBufferSize );
97 sal_uInt16 nHash = static_cast< sal_uInt16 >( nLen );
98 if( nLen > 0 )
99 nHash ^= 0xCE4B;
101 const sal_uInt8* pnChar = pnPassData;
102 for( sal_Int32 nIndex = 0; nIndex < nLen; ++nIndex, ++pnChar )
104 sal_uInt16 cChar = *pnChar;
105 size_t nRot = static_cast< size_t >( (nIndex + 1) % 15 );
106 lclRotateLeft( cChar, nRot, 15 );
107 nHash ^= cChar;
109 return nHash;
112 } // namespace
114 // ============================================================================
116 BinaryCodec_XOR::BinaryCodec_XOR( CodecType eCodecType ) :
117 meCodecType( eCodecType ),
118 mnOffset( 0 ),
119 mnBaseKey( 0 ),
120 mnHash( 0 )
122 (void)memset( mpnKey, 0, sizeof( mpnKey ) );
125 BinaryCodec_XOR::~BinaryCodec_XOR()
127 (void)memset( mpnKey, 0, sizeof( mpnKey ) );
128 mnBaseKey = mnHash = 0;
131 void BinaryCodec_XOR::initKey( const sal_uInt8 pnPassData[ 16 ] )
133 // calculate base key and hash from passed password
134 mnBaseKey = lclGetKey( pnPassData, 16 );
135 mnHash = lclGetHash( pnPassData, 16 );
137 static const sal_uInt8 spnFillChars[] =
139 0xBB, 0xFF, 0xFF, 0xBA,
140 0xFF, 0xFF, 0xB9, 0x80,
141 0x00, 0xBE, 0x0F, 0x00,
142 0xBF, 0x0F, 0x00
145 (void)memcpy( mpnKey, pnPassData, 16 );
146 sal_Int32 nIndex;
147 sal_Int32 nLen = lclGetLen( pnPassData, 16 );
148 const sal_uInt8* pnFillChar = spnFillChars;
149 for( nIndex = nLen; nIndex < static_cast< sal_Int32 >( sizeof( mpnKey ) ); ++nIndex, ++pnFillChar )
150 mpnKey[ nIndex ] = *pnFillChar;
152 // rotation of key values is application dependent
153 size_t nRotateSize = 0;
154 switch( meCodecType )
156 case CODEC_WORD: nRotateSize = 7; break;
157 case CODEC_EXCEL: nRotateSize = 2; break;
158 // compiler will warn, if new codec type is introduced and not handled here
161 // use little-endian base key to create key array
162 sal_uInt8 pnBaseKeyLE[ 2 ];
163 pnBaseKeyLE[ 0 ] = static_cast< sal_uInt8 >( mnBaseKey );
164 pnBaseKeyLE[ 1 ] = static_cast< sal_uInt8 >( mnBaseKey >> 8 );
165 sal_uInt8* pnKeyChar = mpnKey;
166 for( nIndex = 0; nIndex < static_cast< sal_Int32 >( sizeof( mpnKey ) ); ++nIndex, ++pnKeyChar )
168 *pnKeyChar ^= pnBaseKeyLE[ nIndex & 1 ];
169 lclRotateLeft( *pnKeyChar, nRotateSize );
173 bool BinaryCodec_XOR::verifyKey( sal_uInt16 nKey, sal_uInt16 nHash ) const
175 return (nKey == mnBaseKey) && (nHash == mnHash);
178 void BinaryCodec_XOR::startBlock()
180 mnOffset = 0;
183 bool BinaryCodec_XOR::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int32 nBytes )
185 const sal_uInt8* pnCurrKey = mpnKey + mnOffset;
186 const sal_uInt8* pnKeyLast = mpnKey + 0x0F;
188 // switch/case outside of the for loop (performance)
189 const sal_uInt8* pnSrcDataEnd = pnSrcData + nBytes;
190 switch( meCodecType )
192 case CODEC_WORD:
194 for( ; pnSrcData < pnSrcDataEnd; ++pnSrcData, ++pnDestData )
196 sal_uInt8 nData = *pnSrcData ^ *pnCurrKey;
197 if( (*pnSrcData != 0) && (nData != 0) )
198 *pnDestData = nData;
199 if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
202 break;
203 case CODEC_EXCEL:
205 for( ; pnSrcData < pnSrcDataEnd; ++pnSrcData, ++pnDestData )
207 *pnDestData = *pnSrcData;
208 lclRotateLeft( *pnDestData, 3 );
209 *pnDestData ^= *pnCurrKey;
210 if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
213 break;
214 // compiler will warn, if new codec type is introduced and not handled here
217 // update offset and leave
218 return skip( nBytes );
221 bool BinaryCodec_XOR::skip( sal_Int32 nBytes )
223 mnOffset = static_cast< sal_Int32 >( (mnOffset + nBytes) & 0x0F );
224 return true;
227 sal_uInt16 BinaryCodec_XOR::getHash( const sal_uInt8* pnPassData, sal_Int32 nSize )
229 return lclGetHash( pnPassData, nSize );
232 // ============================================================================
234 BinaryCodec_RCF::BinaryCodec_RCF()
236 mhCipher = rtl_cipher_create( rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream );
237 OSL_ENSURE( mhCipher != 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create cipher" );
239 mhDigest = rtl_digest_create( rtl_Digest_AlgorithmMD5 );
240 OSL_ENSURE( mhDigest != 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create digest" );
242 (void)memset( mpnDigestValue, 0, sizeof( mpnDigestValue ) );
245 BinaryCodec_RCF::~BinaryCodec_RCF()
247 (void)memset( mpnDigestValue, 0, sizeof( mpnDigestValue ) );
248 rtl_digest_destroy( mhDigest );
249 rtl_cipher_destroy( mhCipher );
252 void BinaryCodec_RCF::initKey( const sal_uInt16 pnPassData[ 16 ], const sal_uInt8 pnUnique[ 16 ] )
254 // create little-endian key data array from password data
255 sal_uInt8 pnKeyData[ 64 ];
256 (void)memset( pnKeyData, 0, sizeof( pnKeyData ) );
258 const sal_uInt16* pnCurrPass = pnPassData;
259 const sal_uInt16* pnPassEnd = pnPassData + 16;
260 sal_uInt8* pnCurrKey = pnKeyData;
261 size_t nPassSize = 0;
262 for( ; (pnCurrPass < pnPassEnd) && (*pnCurrPass != 0); ++pnCurrPass, ++nPassSize )
264 *pnCurrKey++ = static_cast< sal_uInt8 >( *pnCurrPass );
265 *pnCurrKey++ = static_cast< sal_uInt8 >( *pnCurrPass >> 8 );
267 pnKeyData[ 2 * nPassSize ] = 0x80;
268 pnKeyData[ 56 ] = static_cast< sal_uInt8 >( nPassSize << 4 );
270 // fill raw digest of key data into key data
271 (void)rtl_digest_updateMD5( mhDigest, pnKeyData, sizeof( pnKeyData ) );
272 (void)rtl_digest_rawMD5( mhDigest, pnKeyData, RTL_DIGEST_LENGTH_MD5 );
274 // update digest with key data and passed unique data
275 for( size_t nIndex = 0; nIndex < 16; ++nIndex )
277 rtl_digest_updateMD5( mhDigest, pnKeyData, 5 );
278 rtl_digest_updateMD5( mhDigest, pnUnique, 16 );
281 // update digest with padding
282 pnKeyData[ 16 ] = 0x80;
283 (void)memset( pnKeyData + 17, 0, sizeof( pnKeyData ) - 17 );
284 pnKeyData[ 56 ] = 0x80;
285 pnKeyData[ 57 ] = 0x0A;
286 rtl_digest_updateMD5( mhDigest, pnKeyData + 16, sizeof( pnKeyData ) - 16 );
288 // fill raw digest of above updates into digest value
289 rtl_digest_rawMD5( mhDigest, mpnDigestValue, sizeof( mpnDigestValue ) );
291 // erase key data array and leave
292 (void)memset( pnKeyData, 0, sizeof( pnKeyData ) );
295 bool BinaryCodec_RCF::verifyKey( const sal_uInt8 pnSaltData[ 16 ], const sal_uInt8 pnSaltDigest[ 16 ] )
297 if( !startBlock( 0 ) )
298 return false;
300 sal_uInt8 pnDigest[ RTL_DIGEST_LENGTH_MD5 ];
301 sal_uInt8 pnBuffer[ 64 ];
303 // decode salt data into buffer
304 rtl_cipher_decode( mhCipher, pnSaltData, 16, pnBuffer, sizeof( pnBuffer ) );
306 pnBuffer[ 16 ] = 0x80;
307 (void)memset( pnBuffer + 17, 0, sizeof( pnBuffer ) - 17 );
308 pnBuffer[ 56 ] = 0x80;
310 // fill raw digest of buffer into digest
311 rtl_digest_updateMD5( mhDigest, pnBuffer, sizeof( pnBuffer ) );
312 rtl_digest_rawMD5( mhDigest, pnDigest, sizeof( pnDigest ) );
314 // decode original salt digest into buffer
315 rtl_cipher_decode( mhCipher, pnSaltDigest, 16, pnBuffer, sizeof( pnBuffer ) );
317 // compare buffer with computed digest
318 bool bResult = memcmp( pnBuffer, pnDigest, sizeof( pnDigest ) ) == 0;
320 // erase buffer and digest arrays and leave
321 (void)memset( pnBuffer, 0, sizeof( pnBuffer ) );
322 (void)memset( pnDigest, 0, sizeof( pnDigest ) );
323 return bResult;
326 bool BinaryCodec_RCF::startBlock( sal_Int32 nCounter )
328 // initialize key data array
329 sal_uInt8 pnKeyData[ 64 ];
330 (void)memset( pnKeyData, 0, sizeof( pnKeyData ) );
332 // fill 40 bit of digest value into [0..4]
333 (void)memcpy( pnKeyData, mpnDigestValue, 5 );
335 // fill little-endian counter into [5..8], static_cast masks out unneeded bits
336 pnKeyData[ 5 ] = static_cast< sal_uInt8 >( nCounter );
337 pnKeyData[ 6 ] = static_cast< sal_uInt8 >( nCounter >> 8 );
338 pnKeyData[ 7 ] = static_cast< sal_uInt8 >( nCounter >> 16 );
339 pnKeyData[ 8 ] = static_cast< sal_uInt8 >( nCounter >> 24 );
341 pnKeyData[ 9 ] = 0x80;
342 pnKeyData[ 56 ] = 0x48;
344 // fill raw digest of key data into key data
345 (void)rtl_digest_updateMD5( mhDigest, pnKeyData, sizeof( pnKeyData ) );
346 (void)rtl_digest_rawMD5( mhDigest, pnKeyData, RTL_DIGEST_LENGTH_MD5 );
348 // initialize cipher with key data (for decoding)
349 rtlCipherError eResult =
350 rtl_cipher_init( mhCipher, rtl_Cipher_DirectionDecode, pnKeyData, RTL_DIGEST_LENGTH_MD5, 0, 0 );
352 // rrase key data array and leave
353 (void)memset( pnKeyData, 0, sizeof( pnKeyData ) );
354 return eResult == rtl_Cipher_E_None;
357 bool BinaryCodec_RCF::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int32 nBytes )
359 rtlCipherError eResult = rtl_cipher_decode( mhCipher,
360 pnSrcData, static_cast< sal_Size >( nBytes ),
361 pnDestData, static_cast< sal_Size >( nBytes ) );
362 return eResult == rtl_Cipher_E_None;
365 bool BinaryCodec_RCF::skip( sal_Int32 nBytes )
367 // decode dummy data in memory to update internal state of RC4 cipher
368 sal_uInt8 pnDummy[ 1024 ];
369 sal_Int32 nBytesLeft = nBytes;
370 bool bResult = true;
371 while( bResult && (nBytesLeft > 0) )
373 sal_Int32 nBlockLen = ::std::min( nBytesLeft, static_cast< sal_Int32 >( sizeof( pnDummy ) ) );
374 bResult = decode( pnDummy, pnDummy, nBlockLen );
375 nBytesLeft -= nBlockLen;
377 return bResult;
380 // ============================================================================
382 } // namespace core
383 } // namespace oox