GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / oox / source / core / binarycodec.cxx
blobf4d6b1641b128df1c400e359ebf9da833846f001
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "oox/core/binarycodec.hxx"
22 #include <algorithm>
23 #include <string.h>
24 #include "oox/helper/attributelist.hxx"
26 #include <comphelper/sequenceashashmap.hxx>
27 #include <comphelper/docpasswordhelper.hxx>
29 using namespace ::com::sun::star;
31 namespace oox {
32 namespace core {
34 // ============================================================================
36 namespace {
38 /** Rotates rnValue left by nBits bits. */
39 template< typename Type >
40 inline void lclRotateLeft( Type& rnValue, size_t nBits )
42 OSL_ENSURE( nBits < sizeof( Type ) * 8, "lclRotateLeft - rotation count overflow" );
43 rnValue = static_cast< Type >( (rnValue << nBits) | (rnValue >> (sizeof( Type ) * 8 - nBits)) );
46 /** Rotates the lower nWidth bits of rnValue left by nBits bits. */
47 template< typename Type >
48 inline void lclRotateLeft( Type& rnValue, size_t nBits, size_t nWidth )
50 OSL_ENSURE( (nBits < nWidth) && (nWidth < sizeof( Type ) * 8), "lclRotateLeft - rotation count overflow" );
51 Type nMask = static_cast< Type >( (1UL << nWidth) - 1 );
52 rnValue = static_cast< Type >(
53 ((rnValue << nBits) | ((rnValue & nMask) >> (nWidth - nBits))) & nMask );
56 sal_Int32 lclGetLen( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
58 sal_Int32 nLen = 0;
59 while( (nLen < nBufferSize) && pnPassData[ nLen ] ) ++nLen;
60 return nLen;
63 sal_uInt16 lclGetKey( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
65 sal_Int32 nLen = lclGetLen( pnPassData, nBufferSize );
66 if( nLen <= 0 ) return 0;
68 sal_uInt16 nKey = 0;
69 sal_uInt16 nKeyBase = 0x8000;
70 sal_uInt16 nKeyEnd = 0xFFFF;
71 const sal_uInt8* pnChar = pnPassData + nLen - 1;
72 for( sal_Int32 nIndex = 0; nIndex < nLen; ++nIndex, --pnChar )
74 sal_uInt8 cChar = *pnChar & 0x7F;
75 for( size_t nBit = 0; nBit < 8; ++nBit )
77 lclRotateLeft( nKeyBase, 1 );
78 if( nKeyBase & 1 ) nKeyBase ^= 0x1020;
79 if( cChar & 1 ) nKey ^= nKeyBase;
80 cChar >>= 1;
81 lclRotateLeft( nKeyEnd, 1 );
82 if( nKeyEnd & 1 ) nKeyEnd ^= 0x1020;
85 return nKey ^ nKeyEnd;
88 sal_uInt16 lclGetHash( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
90 sal_Int32 nLen = lclGetLen( pnPassData, nBufferSize );
92 sal_uInt16 nHash = static_cast< sal_uInt16 >( nLen );
93 if( nLen > 0 )
94 nHash ^= 0xCE4B;
96 const sal_uInt8* pnChar = pnPassData;
97 for( sal_Int32 nIndex = 0; nIndex < nLen; ++nIndex, ++pnChar )
99 sal_uInt16 cChar = *pnChar;
100 size_t nRot = static_cast< size_t >( (nIndex + 1) % 15 );
101 lclRotateLeft( cChar, nRot, 15 );
102 nHash ^= cChar;
104 return nHash;
107 } // namespace
109 // ============================================================================
111 sal_uInt16 CodecHelper::getPasswordHash( const AttributeList& rAttribs, sal_Int32 nElement )
113 sal_Int32 nPasswordHash = rAttribs.getIntegerHex( nElement, 0 );
114 OSL_ENSURE( (0 <= nPasswordHash) && (nPasswordHash <= SAL_MAX_UINT16), "CodecHelper::getPasswordHash - invalid password hash" );
115 return static_cast< sal_uInt16 >( ((0 <= nPasswordHash) && (nPasswordHash <= SAL_MAX_UINT16)) ? nPasswordHash : 0 );
118 // ============================================================================
120 BinaryCodec_XOR::BinaryCodec_XOR( CodecType eCodecType ) :
121 meCodecType( eCodecType ),
122 mnOffset( 0 ),
123 mnBaseKey( 0 ),
124 mnHash( 0 )
126 (void)memset( mpnKey, 0, sizeof( mpnKey ) );
129 BinaryCodec_XOR::~BinaryCodec_XOR()
131 (void)memset( mpnKey, 0, sizeof( mpnKey ) );
132 mnBaseKey = mnHash = 0;
135 void BinaryCodec_XOR::initKey( const sal_uInt8 pnPassData[ 16 ] )
137 // calculate base key and hash from passed password
138 mnBaseKey = lclGetKey( pnPassData, 16 );
139 mnHash = lclGetHash( pnPassData, 16 );
141 static const sal_uInt8 spnFillChars[] =
143 0xBB, 0xFF, 0xFF, 0xBA,
144 0xFF, 0xFF, 0xB9, 0x80,
145 0x00, 0xBE, 0x0F, 0x00,
146 0xBF, 0x0F, 0x00
149 (void)memcpy( mpnKey, pnPassData, 16 );
150 sal_Int32 nIndex;
151 sal_Int32 nLen = lclGetLen( pnPassData, 16 );
152 const sal_uInt8* pnFillChar = spnFillChars;
153 for( nIndex = nLen; nIndex < static_cast< sal_Int32 >( sizeof( mpnKey ) ); ++nIndex, ++pnFillChar )
154 mpnKey[ nIndex ] = *pnFillChar;
156 // rotation of key values is application dependent
157 size_t nRotateSize = 0;
158 switch( meCodecType )
160 case CODEC_WORD: nRotateSize = 7; break;
161 case CODEC_EXCEL: nRotateSize = 2; break;
162 // compiler will warn, if new codec type is introduced and not handled here
165 // use little-endian base key to create key array
166 sal_uInt8 pnBaseKeyLE[ 2 ];
167 pnBaseKeyLE[ 0 ] = static_cast< sal_uInt8 >( mnBaseKey );
168 pnBaseKeyLE[ 1 ] = static_cast< sal_uInt8 >( mnBaseKey >> 8 );
169 sal_uInt8* pnKeyChar = mpnKey;
170 for( nIndex = 0; nIndex < static_cast< sal_Int32 >( sizeof( mpnKey ) ); ++nIndex, ++pnKeyChar )
172 *pnKeyChar ^= pnBaseKeyLE[ nIndex & 1 ];
173 lclRotateLeft( *pnKeyChar, nRotateSize );
177 bool BinaryCodec_XOR::initCodec( const uno::Sequence< beans::NamedValue >& aData )
179 bool bResult = sal_False;
181 ::comphelper::SequenceAsHashMap aHashData( aData );
182 uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("XOR95EncryptionKey", uno::Sequence< sal_Int8 >() );
184 if ( aKey.getLength() == 16 )
186 (void)memcpy( mpnKey, aKey.getConstArray(), 16 );
187 bResult = sal_True;
189 mnBaseKey = (sal_uInt16)aHashData.getUnpackedValueOrDefault("XOR95BaseKey", (sal_Int16)0 );
190 mnHash = (sal_uInt16)aHashData.getUnpackedValueOrDefault("XOR95PasswordHash", (sal_Int16)0 );
192 else
193 OSL_FAIL( "Unexpected key size!\n" );
195 return bResult;
198 uno::Sequence< beans::NamedValue > BinaryCodec_XOR::getEncryptionData()
200 ::comphelper::SequenceAsHashMap aHashData;
201 aHashData[ OUString("XOR95EncryptionKey") ] <<= uno::Sequence<sal_Int8>( (sal_Int8*)mpnKey, 16 );
202 aHashData[ OUString("XOR95BaseKey") ] <<= (sal_Int16)mnBaseKey;
203 aHashData[ OUString("XOR95PasswordHash") ] <<= (sal_Int16)mnHash;
205 return aHashData.getAsConstNamedValueList();
208 bool BinaryCodec_XOR::verifyKey( sal_uInt16 nKey, sal_uInt16 nHash ) const
210 return (nKey == mnBaseKey) && (nHash == mnHash);
213 void BinaryCodec_XOR::startBlock()
215 mnOffset = 0;
218 bool BinaryCodec_XOR::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int32 nBytes )
220 const sal_uInt8* pnCurrKey = mpnKey + mnOffset;
221 const sal_uInt8* pnKeyLast = mpnKey + 0x0F;
223 // switch/case outside of the for loop (performance)
224 const sal_uInt8* pnSrcDataEnd = pnSrcData + nBytes;
225 switch( meCodecType )
227 case CODEC_WORD:
229 for( ; pnSrcData < pnSrcDataEnd; ++pnSrcData, ++pnDestData )
231 sal_uInt8 nData = *pnSrcData ^ *pnCurrKey;
232 if( (*pnSrcData != 0) && (nData != 0) )
233 *pnDestData = nData;
234 if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
237 break;
238 case CODEC_EXCEL:
240 for( ; pnSrcData < pnSrcDataEnd; ++pnSrcData, ++pnDestData )
242 *pnDestData = *pnSrcData;
243 lclRotateLeft( *pnDestData, 3 );
244 *pnDestData ^= *pnCurrKey;
245 if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
248 break;
249 // compiler will warn, if new codec type is introduced and not handled here
252 // update offset and leave
253 return skip( nBytes );
256 bool BinaryCodec_XOR::skip( sal_Int32 nBytes )
258 mnOffset = static_cast< sal_Int32 >( (mnOffset + nBytes) & 0x0F );
259 return true;
262 // ============================================================================
264 BinaryCodec_RCF::BinaryCodec_RCF()
266 mhCipher = rtl_cipher_create( rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream );
267 OSL_ENSURE( mhCipher != 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create cipher" );
269 mhDigest = rtl_digest_create( rtl_Digest_AlgorithmMD5 );
270 OSL_ENSURE( mhDigest != 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create digest" );
272 (void)memset( mpnDigestValue, 0, sizeof( mpnDigestValue ) );
273 (void)memset (mpnUnique, 0, sizeof(mpnUnique));
276 BinaryCodec_RCF::~BinaryCodec_RCF()
278 (void)memset( mpnDigestValue, 0, sizeof( mpnDigestValue ) );
279 (void)memset (mpnUnique, 0, sizeof(mpnUnique));
280 rtl_digest_destroy( mhDigest );
281 rtl_cipher_destroy( mhCipher );
284 bool BinaryCodec_RCF::initCodec( const uno::Sequence< beans::NamedValue >& aData )
286 bool bResult = sal_False;
288 ::comphelper::SequenceAsHashMap aHashData( aData );
289 uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("STD97EncryptionKey", uno::Sequence< sal_Int8 >() );
291 if ( aKey.getLength() == RTL_DIGEST_LENGTH_MD5 )
293 (void)memcpy( mpnDigestValue, aKey.getConstArray(), RTL_DIGEST_LENGTH_MD5 );
294 uno::Sequence< sal_Int8 > aUniqueID = aHashData.getUnpackedValueOrDefault("STD97UniqueID", uno::Sequence< sal_Int8 >() );
295 if ( aUniqueID.getLength() == 16 )
297 (void)memcpy( mpnUnique, aUniqueID.getConstArray(), 16 );
298 bResult = sal_False;
300 else
301 OSL_FAIL( "Unexpected document ID!\n" );
303 else
304 OSL_FAIL( "Unexpected key size!\n" );
306 return bResult;
309 uno::Sequence< beans::NamedValue > BinaryCodec_RCF::getEncryptionData()
311 ::comphelper::SequenceAsHashMap aHashData;
312 aHashData[ OUString("STD97EncryptionKey") ] <<= uno::Sequence< sal_Int8 >( (sal_Int8*)mpnDigestValue, RTL_DIGEST_LENGTH_MD5 );
313 aHashData[ OUString("STD97UniqueID") ] <<= uno::Sequence< sal_Int8 >( (sal_Int8*)mpnUnique, 16 );
315 return aHashData.getAsConstNamedValueList();
318 void BinaryCodec_RCF::initKey( const sal_uInt16 pnPassData[ 16 ], const sal_uInt8 pnSalt[ 16 ] )
320 uno::Sequence< sal_Int8 > aKey = ::comphelper::DocPasswordHelper::GenerateStd97Key( pnPassData, uno::Sequence< sal_Int8 >( (sal_Int8*)pnSalt, 16 ) );
321 // Fill raw digest of above updates into DigestValue.
323 if ( aKey.getLength() == sizeof(mpnDigestValue) )
324 (void)memcpy ( mpnDigestValue, (const sal_uInt8*)aKey.getConstArray(), sizeof(mpnDigestValue) );
325 else
326 memset( mpnDigestValue, 0, sizeof(mpnDigestValue) );
328 (void)memcpy( mpnUnique, pnSalt, 16 );
331 bool BinaryCodec_RCF::verifyKey( const sal_uInt8 pnVerifier[ 16 ], const sal_uInt8 pnVerifierHash[ 16 ] )
333 if( !startBlock( 0 ) )
334 return false;
336 sal_uInt8 pnDigest[ RTL_DIGEST_LENGTH_MD5 ];
337 sal_uInt8 pnBuffer[ 64 ];
339 // decode salt data into buffer
340 rtl_cipher_decode( mhCipher, pnVerifier, 16, pnBuffer, sizeof( pnBuffer ) );
342 pnBuffer[ 16 ] = 0x80;
343 (void)memset( pnBuffer + 17, 0, sizeof( pnBuffer ) - 17 );
344 pnBuffer[ 56 ] = 0x80;
346 // fill raw digest of buffer into digest
347 rtl_digest_updateMD5( mhDigest, pnBuffer, sizeof( pnBuffer ) );
348 rtl_digest_rawMD5( mhDigest, pnDigest, sizeof( pnDigest ) );
350 // decode original salt digest into buffer
351 rtl_cipher_decode( mhCipher, pnVerifierHash, 16, pnBuffer, sizeof( pnBuffer ) );
353 // compare buffer with computed digest
354 bool bResult = memcmp( pnBuffer, pnDigest, sizeof( pnDigest ) ) == 0;
356 // erase buffer and digest arrays and leave
357 (void)memset( pnBuffer, 0, sizeof( pnBuffer ) );
358 (void)memset( pnDigest, 0, sizeof( pnDigest ) );
359 return bResult;
362 bool BinaryCodec_RCF::startBlock( sal_Int32 nCounter )
364 // initialize key data array
365 sal_uInt8 pnKeyData[ 64 ];
366 (void)memset( pnKeyData, 0, sizeof( pnKeyData ) );
368 // fill 40 bit of digest value into [0..4]
369 (void)memcpy( pnKeyData, mpnDigestValue, 5 );
371 // fill little-endian counter into [5..8], static_cast masks out unneeded bits
372 pnKeyData[ 5 ] = static_cast< sal_uInt8 >( nCounter );
373 pnKeyData[ 6 ] = static_cast< sal_uInt8 >( nCounter >> 8 );
374 pnKeyData[ 7 ] = static_cast< sal_uInt8 >( nCounter >> 16 );
375 pnKeyData[ 8 ] = static_cast< sal_uInt8 >( nCounter >> 24 );
377 pnKeyData[ 9 ] = 0x80;
378 pnKeyData[ 56 ] = 0x48;
380 // fill raw digest of key data into key data
381 (void)rtl_digest_updateMD5( mhDigest, pnKeyData, sizeof( pnKeyData ) );
382 (void)rtl_digest_rawMD5( mhDigest, pnKeyData, RTL_DIGEST_LENGTH_MD5 );
384 // initialize cipher with key data (for decoding)
385 rtlCipherError eResult =
386 rtl_cipher_init( mhCipher, rtl_Cipher_DirectionDecode, pnKeyData, RTL_DIGEST_LENGTH_MD5, 0, 0 );
388 // rrase key data array and leave
389 (void)memset( pnKeyData, 0, sizeof( pnKeyData ) );
390 return eResult == rtl_Cipher_E_None;
393 bool BinaryCodec_RCF::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int32 nBytes )
395 rtlCipherError eResult = rtl_cipher_decode( mhCipher,
396 pnSrcData, static_cast< sal_Size >( nBytes ),
397 pnDestData, static_cast< sal_Size >( nBytes ) );
398 return eResult == rtl_Cipher_E_None;
401 bool BinaryCodec_RCF::skip( sal_Int32 nBytes )
403 // decode dummy data in memory to update internal state of RC4 cipher
404 sal_uInt8 pnDummy[ 1024 ];
405 sal_Int32 nBytesLeft = nBytes;
406 bool bResult = true;
407 while( bResult && (nBytesLeft > 0) )
409 sal_Int32 nBlockLen = ::std::min( nBytesLeft, static_cast< sal_Int32 >( sizeof( pnDummy ) ) );
410 bResult = decode( pnDummy, pnDummy, nBlockLen );
411 nBytesLeft -= nBlockLen;
413 return bResult;
416 // ============================================================================
418 } // namespace core
419 } // namespace oox
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */