Branch libreoffice-5-0-4
[LibreOffice.git] / oox / source / core / binarycodec.cxx
blob43eb3dca1dd5d5b727c1fbee61107f785587e353
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 <osl/diagnose.h>
27 #include <comphelper/sequenceashashmap.hxx>
28 #include <comphelper/docpasswordhelper.hxx>
30 using namespace ::com::sun::star;
32 namespace oox {
33 namespace core {
35 namespace {
37 /** Rotates rnValue left by nBits bits. */
38 template< typename Type >
39 inline void lclRotateLeft( Type& rnValue, size_t nBits )
41 OSL_ENSURE( nBits < sizeof( Type ) * 8, "lclRotateLeft - rotation count overflow" );
42 rnValue = static_cast< Type >( (rnValue << nBits) | (rnValue >> (sizeof( Type ) * 8 - nBits)) );
45 /** Rotates the lower nWidth bits of rnValue left by nBits bits. */
46 template< typename Type >
47 inline void lclRotateLeft( Type& rnValue, size_t nBits, size_t nWidth )
49 OSL_ENSURE( (nBits < nWidth) && (nWidth < sizeof( Type ) * 8), "lclRotateLeft - rotation count overflow" );
50 Type nMask = static_cast< Type >( (1UL << nWidth) - 1 );
51 rnValue = static_cast< Type >(
52 ((rnValue << nBits) | ((rnValue & nMask) >> (nWidth - nBits))) & nMask );
55 sal_Int32 lclGetLen( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
57 sal_Int32 nLen = 0;
58 while( (nLen < nBufferSize) && pnPassData[ nLen ] ) ++nLen;
59 return nLen;
62 sal_uInt16 lclGetKey( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
64 sal_Int32 nLen = lclGetLen( pnPassData, nBufferSize );
65 if( nLen <= 0 ) return 0;
67 sal_uInt16 nKey = 0;
68 sal_uInt16 nKeyBase = 0x8000;
69 sal_uInt16 nKeyEnd = 0xFFFF;
70 const sal_uInt8* pnChar = pnPassData + nLen - 1;
71 for( sal_Int32 nIndex = 0; nIndex < nLen; ++nIndex, --pnChar )
73 sal_uInt8 cChar = *pnChar & 0x7F;
74 for( size_t nBit = 0; nBit < 8; ++nBit )
76 lclRotateLeft( nKeyBase, 1 );
77 if( nKeyBase & 1 ) nKeyBase ^= 0x1020;
78 if( cChar & 1 ) nKey ^= nKeyBase;
79 cChar >>= 1;
80 lclRotateLeft( nKeyEnd, 1 );
81 if( nKeyEnd & 1 ) nKeyEnd ^= 0x1020;
84 return nKey ^ nKeyEnd;
87 sal_uInt16 lclGetHash( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
89 sal_Int32 nLen = lclGetLen( pnPassData, nBufferSize );
91 sal_uInt16 nHash = static_cast< sal_uInt16 >( nLen );
92 if( nLen > 0 )
93 nHash ^= 0xCE4B;
95 const sal_uInt8* pnChar = pnPassData;
96 for( sal_Int32 nIndex = 0; nIndex < nLen; ++nIndex, ++pnChar )
98 sal_uInt16 cChar = *pnChar;
99 size_t nRot = static_cast< size_t >( (nIndex + 1) % 15 );
100 lclRotateLeft( cChar, nRot, 15 );
101 nHash ^= cChar;
103 return nHash;
106 } // namespace
108 sal_uInt16 CodecHelper::getPasswordHash( const AttributeList& rAttribs, sal_Int32 nElement )
110 sal_Int32 nPasswordHash = rAttribs.getIntegerHex( nElement, 0 );
111 OSL_ENSURE( (0 <= nPasswordHash) && (nPasswordHash <= SAL_MAX_UINT16), "CodecHelper::getPasswordHash - invalid password hash" );
112 return static_cast< sal_uInt16 >( ((0 <= nPasswordHash) && (nPasswordHash <= SAL_MAX_UINT16)) ? nPasswordHash : 0 );
115 BinaryCodec_XOR::BinaryCodec_XOR( CodecType eCodecType ) :
116 meCodecType( eCodecType ),
117 mnOffset( 0 ),
118 mnBaseKey( 0 ),
119 mnHash( 0 )
121 (void)memset( mpnKey, 0, sizeof( mpnKey ) );
124 BinaryCodec_XOR::~BinaryCodec_XOR()
126 (void)memset( mpnKey, 0, sizeof( mpnKey ) );
127 mnBaseKey = mnHash = 0;
130 void BinaryCodec_XOR::initKey( const sal_uInt8 pnPassData[ 16 ] )
132 // calculate base key and hash from passed password
133 mnBaseKey = lclGetKey( pnPassData, 16 );
134 mnHash = lclGetHash( pnPassData, 16 );
136 static const sal_uInt8 spnFillChars[] =
138 0xBB, 0xFF, 0xFF, 0xBA,
139 0xFF, 0xFF, 0xB9, 0x80,
140 0x00, 0xBE, 0x0F, 0x00,
141 0xBF, 0x0F, 0x00
144 (void)memcpy( mpnKey, pnPassData, 16 );
145 sal_Int32 nIndex;
146 sal_Int32 nLen = lclGetLen( pnPassData, 16 );
147 const sal_uInt8* pnFillChar = spnFillChars;
148 for( nIndex = nLen; nIndex < static_cast< sal_Int32 >( sizeof( mpnKey ) ); ++nIndex, ++pnFillChar )
149 mpnKey[ nIndex ] = *pnFillChar;
151 // rotation of key values is application dependent
152 size_t nRotateSize = 0;
153 switch( meCodecType )
155 case CODEC_WORD: nRotateSize = 7; break;
156 case CODEC_EXCEL: nRotateSize = 2; break;
157 // compiler will warn, if new codec type is introduced and not handled here
160 // use little-endian base key to create key array
161 sal_uInt8 pnBaseKeyLE[ 2 ];
162 pnBaseKeyLE[ 0 ] = static_cast< sal_uInt8 >( mnBaseKey );
163 pnBaseKeyLE[ 1 ] = static_cast< sal_uInt8 >( mnBaseKey >> 8 );
164 sal_uInt8* pnKeyChar = mpnKey;
165 for( nIndex = 0; nIndex < static_cast< sal_Int32 >( sizeof( mpnKey ) ); ++nIndex, ++pnKeyChar )
167 *pnKeyChar ^= pnBaseKeyLE[ nIndex & 1 ];
168 lclRotateLeft( *pnKeyChar, nRotateSize );
172 bool BinaryCodec_XOR::initCodec( const uno::Sequence< beans::NamedValue >& aData )
174 bool bResult = false;
176 ::comphelper::SequenceAsHashMap aHashData( aData );
177 uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("XOR95EncryptionKey", uno::Sequence< sal_Int8 >() );
179 if ( aKey.getLength() == 16 )
181 (void)memcpy( mpnKey, aKey.getConstArray(), 16 );
182 bResult = true;
184 mnBaseKey = (sal_uInt16)aHashData.getUnpackedValueOrDefault("XOR95BaseKey", (sal_Int16)0 );
185 mnHash = (sal_uInt16)aHashData.getUnpackedValueOrDefault("XOR95PasswordHash", (sal_Int16)0 );
187 else
188 OSL_FAIL( "Unexpected key size!\n" );
190 return bResult;
193 uno::Sequence< beans::NamedValue > BinaryCodec_XOR::getEncryptionData()
195 ::comphelper::SequenceAsHashMap aHashData;
196 aHashData[ OUString("XOR95EncryptionKey") ] <<= uno::Sequence<sal_Int8>( reinterpret_cast<sal_Int8*>(mpnKey), 16 );
197 aHashData[ OUString("XOR95BaseKey") ] <<= (sal_Int16)mnBaseKey;
198 aHashData[ OUString("XOR95PasswordHash") ] <<= (sal_Int16)mnHash;
200 return aHashData.getAsConstNamedValueList();
203 bool BinaryCodec_XOR::verifyKey( sal_uInt16 nKey, sal_uInt16 nHash ) const
205 return (nKey == mnBaseKey) && (nHash == mnHash);
208 void BinaryCodec_XOR::startBlock()
210 mnOffset = 0;
213 bool BinaryCodec_XOR::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int32 nBytes )
215 const sal_uInt8* pnCurrKey = mpnKey + mnOffset;
216 const sal_uInt8* pnKeyLast = mpnKey + 0x0F;
218 // switch/case outside of the for loop (performance)
219 const sal_uInt8* pnSrcDataEnd = pnSrcData + nBytes;
220 switch( meCodecType )
222 case CODEC_WORD:
224 for( ; pnSrcData < pnSrcDataEnd; ++pnSrcData, ++pnDestData )
226 sal_uInt8 nData = *pnSrcData ^ *pnCurrKey;
227 if( (*pnSrcData != 0) && (nData != 0) )
228 *pnDestData = nData;
229 if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
232 break;
233 case CODEC_EXCEL:
235 for( ; pnSrcData < pnSrcDataEnd; ++pnSrcData, ++pnDestData )
237 *pnDestData = *pnSrcData;
238 lclRotateLeft( *pnDestData, 3 );
239 *pnDestData ^= *pnCurrKey;
240 if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
243 break;
244 // compiler will warn, if new codec type is introduced and not handled here
247 // update offset and leave
248 return skip( nBytes );
251 bool BinaryCodec_XOR::skip( sal_Int32 nBytes )
253 mnOffset = static_cast< sal_Int32 >( (mnOffset + nBytes) & 0x0F );
254 return true;
257 BinaryCodec_RCF::BinaryCodec_RCF()
259 mhCipher = rtl_cipher_create( rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream );
260 OSL_ENSURE( mhCipher != 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create cipher" );
262 mhDigest = rtl_digest_create( rtl_Digest_AlgorithmMD5 );
263 OSL_ENSURE( mhDigest != 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create digest" );
265 (void)memset( mpnDigestValue, 0, sizeof( mpnDigestValue ) );
266 (void)memset (mpnUnique, 0, sizeof(mpnUnique));
269 BinaryCodec_RCF::~BinaryCodec_RCF()
271 (void)memset( mpnDigestValue, 0, sizeof( mpnDigestValue ) );
272 (void)memset (mpnUnique, 0, sizeof(mpnUnique));
273 rtl_digest_destroy( mhDigest );
274 rtl_cipher_destroy( mhCipher );
277 bool BinaryCodec_RCF::initCodec( const uno::Sequence< beans::NamedValue >& aData )
279 bool bResult = false;
281 ::comphelper::SequenceAsHashMap aHashData( aData );
282 uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("STD97EncryptionKey", uno::Sequence< sal_Int8 >() );
284 if ( aKey.getLength() == RTL_DIGEST_LENGTH_MD5 )
286 (void)memcpy( mpnDigestValue, aKey.getConstArray(), RTL_DIGEST_LENGTH_MD5 );
287 uno::Sequence< sal_Int8 > aUniqueID = aHashData.getUnpackedValueOrDefault("STD97UniqueID", uno::Sequence< sal_Int8 >() );
288 if ( aUniqueID.getLength() == 16 )
290 (void)memcpy( mpnUnique, aUniqueID.getConstArray(), 16 );
291 bResult = false;
293 else
294 OSL_FAIL( "Unexpected document ID!\n" );
296 else
297 OSL_FAIL( "Unexpected key size!\n" );
299 return bResult;
302 uno::Sequence< beans::NamedValue > BinaryCodec_RCF::getEncryptionData()
304 ::comphelper::SequenceAsHashMap aHashData;
305 aHashData[ OUString("STD97EncryptionKey") ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8*>(mpnDigestValue), RTL_DIGEST_LENGTH_MD5 );
306 aHashData[ OUString("STD97UniqueID") ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8*>(mpnUnique), 16 );
308 return aHashData.getAsConstNamedValueList();
311 void BinaryCodec_RCF::initKey( const sal_uInt16 pnPassData[ 16 ], const sal_uInt8 pnSalt[ 16 ] )
313 uno::Sequence< sal_Int8 > aKey = ::comphelper::DocPasswordHelper::GenerateStd97Key( pnPassData, uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8 const *>(pnSalt), 16 ) );
314 // Fill raw digest of above updates into DigestValue.
316 if ( aKey.getLength() == sizeof(mpnDigestValue) )
317 (void)memcpy ( mpnDigestValue, aKey.getConstArray(), sizeof(mpnDigestValue) );
318 else
319 memset( mpnDigestValue, 0, sizeof(mpnDigestValue) );
321 (void)memcpy( mpnUnique, pnSalt, 16 );
324 bool BinaryCodec_RCF::verifyKey( const sal_uInt8 pnVerifier[ 16 ], const sal_uInt8 pnVerifierHash[ 16 ] )
326 if( !startBlock( 0 ) )
327 return false;
329 sal_uInt8 pnDigest[ RTL_DIGEST_LENGTH_MD5 ];
330 sal_uInt8 pnBuffer[ 64 ];
332 // decode salt data into buffer
333 rtl_cipher_decode( mhCipher, pnVerifier, 16, pnBuffer, sizeof( pnBuffer ) );
335 pnBuffer[ 16 ] = 0x80;
336 (void)memset( pnBuffer + 17, 0, sizeof( pnBuffer ) - 17 );
337 pnBuffer[ 56 ] = 0x80;
339 // fill raw digest of buffer into digest
340 rtl_digest_updateMD5( mhDigest, pnBuffer, sizeof( pnBuffer ) );
341 rtl_digest_rawMD5( mhDigest, pnDigest, sizeof( pnDigest ) );
343 // decode original salt digest into buffer
344 rtl_cipher_decode( mhCipher, pnVerifierHash, 16, pnBuffer, sizeof( pnBuffer ) );
346 // compare buffer with computed digest
347 bool bResult = memcmp( pnBuffer, pnDigest, sizeof( pnDigest ) ) == 0;
349 // erase buffer and digest arrays and leave
350 rtl_secureZeroMemory (pnBuffer, sizeof(pnBuffer));
351 rtl_secureZeroMemory (pnDigest, sizeof(pnDigest));
352 return bResult;
355 bool BinaryCodec_RCF::startBlock( sal_Int32 nCounter )
357 // initialize key data array
358 sal_uInt8 pnKeyData[ 64 ];
359 (void)memset( pnKeyData, 0, sizeof( pnKeyData ) );
361 // fill 40 bit of digest value into [0..4]
362 (void)memcpy( pnKeyData, mpnDigestValue, 5 );
364 // fill little-endian counter into [5..8], static_cast masks out unneeded bits
365 pnKeyData[ 5 ] = static_cast< sal_uInt8 >( nCounter );
366 pnKeyData[ 6 ] = static_cast< sal_uInt8 >( nCounter >> 8 );
367 pnKeyData[ 7 ] = static_cast< sal_uInt8 >( nCounter >> 16 );
368 pnKeyData[ 8 ] = static_cast< sal_uInt8 >( nCounter >> 24 );
370 pnKeyData[ 9 ] = 0x80;
371 pnKeyData[ 56 ] = 0x48;
373 // fill raw digest of key data into key data
374 (void)rtl_digest_updateMD5( mhDigest, pnKeyData, sizeof( pnKeyData ) );
375 (void)rtl_digest_rawMD5( mhDigest, pnKeyData, RTL_DIGEST_LENGTH_MD5 );
377 // initialize cipher with key data (for decoding)
378 rtlCipherError eResult =
379 rtl_cipher_init( mhCipher, rtl_Cipher_DirectionDecode, pnKeyData, RTL_DIGEST_LENGTH_MD5, 0, 0 );
381 // rrase key data array and leave
382 rtl_secureZeroMemory (pnKeyData, sizeof(pnKeyData));
383 return eResult == rtl_Cipher_E_None;
386 bool BinaryCodec_RCF::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int32 nBytes )
388 rtlCipherError eResult = rtl_cipher_decode( mhCipher,
389 pnSrcData, static_cast< sal_Size >( nBytes ),
390 pnDestData, static_cast< sal_Size >( nBytes ) );
391 return eResult == rtl_Cipher_E_None;
394 bool BinaryCodec_RCF::skip( sal_Int32 nBytes )
396 // decode dummy data in memory to update internal state of RC4 cipher
397 sal_uInt8 pnDummy[ 1024 ];
398 sal_Int32 nBytesLeft = nBytes;
399 bool bResult = true;
400 while( bResult && (nBytesLeft > 0) )
402 sal_Int32 nBlockLen = ::std::min( nBytesLeft, static_cast< sal_Int32 >( sizeof( pnDummy ) ) );
403 bResult = decode( pnDummy, pnDummy, nBlockLen );
404 nBytesLeft -= nBlockLen;
406 return bResult;
409 } // namespace core
410 } // namespace oox
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */