Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "oox/core/binarycodec.hxx"
21 :
22 : #include <algorithm>
23 : #include <string.h>
24 : #include "oox/helper/attributelist.hxx"
25 :
26 : #include <osl/diagnose.h>
27 : #include <comphelper/sequenceashashmap.hxx>
28 : #include <comphelper/docpasswordhelper.hxx>
29 :
30 : using namespace ::com::sun::star;
31 :
32 : namespace oox {
33 : namespace core {
34 :
35 : namespace {
36 :
37 : /** Rotates rnValue left by nBits bits. */
38 : template< typename Type >
39 0 : inline void lclRotateLeft( Type& rnValue, size_t nBits )
40 : {
41 : OSL_ENSURE( nBits < sizeof( Type ) * 8, "lclRotateLeft - rotation count overflow" );
42 0 : rnValue = static_cast< Type >( (rnValue << nBits) | (rnValue >> (sizeof( Type ) * 8 - nBits)) );
43 0 : }
44 :
45 : /** Rotates the lower nWidth bits of rnValue left by nBits bits. */
46 : template< typename Type >
47 0 : inline void lclRotateLeft( Type& rnValue, size_t nBits, size_t nWidth )
48 : {
49 : OSL_ENSURE( (nBits < nWidth) && (nWidth < sizeof( Type ) * 8), "lclRotateLeft - rotation count overflow" );
50 0 : Type nMask = static_cast< Type >( (1UL << nWidth) - 1 );
51 0 : rnValue = static_cast< Type >(
52 : ((rnValue << nBits) | ((rnValue & nMask) >> (nWidth - nBits))) & nMask );
53 0 : }
54 :
55 0 : sal_Int32 lclGetLen( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
56 : {
57 0 : sal_Int32 nLen = 0;
58 0 : while( (nLen < nBufferSize) && pnPassData[ nLen ] ) ++nLen;
59 0 : return nLen;
60 : }
61 :
62 0 : sal_uInt16 lclGetKey( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
63 : {
64 0 : sal_Int32 nLen = lclGetLen( pnPassData, nBufferSize );
65 0 : if( nLen <= 0 ) return 0;
66 :
67 0 : sal_uInt16 nKey = 0;
68 0 : sal_uInt16 nKeyBase = 0x8000;
69 0 : sal_uInt16 nKeyEnd = 0xFFFF;
70 0 : const sal_uInt8* pnChar = pnPassData + nLen - 1;
71 0 : for( sal_Int32 nIndex = 0; nIndex < nLen; ++nIndex, --pnChar )
72 : {
73 0 : sal_uInt8 cChar = *pnChar & 0x7F;
74 0 : for( size_t nBit = 0; nBit < 8; ++nBit )
75 : {
76 0 : lclRotateLeft( nKeyBase, 1 );
77 0 : if( nKeyBase & 1 ) nKeyBase ^= 0x1020;
78 0 : if( cChar & 1 ) nKey ^= nKeyBase;
79 0 : cChar >>= 1;
80 0 : lclRotateLeft( nKeyEnd, 1 );
81 0 : if( nKeyEnd & 1 ) nKeyEnd ^= 0x1020;
82 : }
83 : }
84 0 : return nKey ^ nKeyEnd;
85 : }
86 :
87 0 : sal_uInt16 lclGetHash( const sal_uInt8* pnPassData, sal_Int32 nBufferSize )
88 : {
89 0 : sal_Int32 nLen = lclGetLen( pnPassData, nBufferSize );
90 :
91 0 : sal_uInt16 nHash = static_cast< sal_uInt16 >( nLen );
92 0 : if( nLen > 0 )
93 0 : nHash ^= 0xCE4B;
94 :
95 0 : const sal_uInt8* pnChar = pnPassData;
96 0 : for( sal_Int32 nIndex = 0; nIndex < nLen; ++nIndex, ++pnChar )
97 : {
98 0 : sal_uInt16 cChar = *pnChar;
99 0 : size_t nRot = static_cast< size_t >( (nIndex + 1) % 15 );
100 0 : lclRotateLeft( cChar, nRot, 15 );
101 0 : nHash ^= cChar;
102 : }
103 0 : return nHash;
104 : }
105 :
106 : } // namespace
107 :
108 4 : sal_uInt16 CodecHelper::getPasswordHash( const AttributeList& rAttribs, sal_Int32 nElement )
109 : {
110 4 : sal_Int32 nPasswordHash = rAttribs.getIntegerHex( nElement, 0 );
111 : OSL_ENSURE( (0 <= nPasswordHash) && (nPasswordHash <= SAL_MAX_UINT16), "CodecHelper::getPasswordHash - invalid password hash" );
112 4 : return static_cast< sal_uInt16 >( ((0 <= nPasswordHash) && (nPasswordHash <= SAL_MAX_UINT16)) ? nPasswordHash : 0 );
113 : }
114 :
115 0 : BinaryCodec_XOR::BinaryCodec_XOR( CodecType eCodecType ) :
116 : meCodecType( eCodecType ),
117 : mnOffset( 0 ),
118 : mnBaseKey( 0 ),
119 0 : mnHash( 0 )
120 : {
121 0 : (void)memset( mpnKey, 0, sizeof( mpnKey ) );
122 0 : }
123 :
124 0 : BinaryCodec_XOR::~BinaryCodec_XOR()
125 : {
126 0 : (void)memset( mpnKey, 0, sizeof( mpnKey ) );
127 0 : mnBaseKey = mnHash = 0;
128 0 : }
129 :
130 0 : void BinaryCodec_XOR::initKey( const sal_uInt8 pnPassData[ 16 ] )
131 : {
132 : // calculate base key and hash from passed password
133 0 : mnBaseKey = lclGetKey( pnPassData, 16 );
134 0 : mnHash = lclGetHash( pnPassData, 16 );
135 :
136 : static const sal_uInt8 spnFillChars[] =
137 : {
138 : 0xBB, 0xFF, 0xFF, 0xBA,
139 : 0xFF, 0xFF, 0xB9, 0x80,
140 : 0x00, 0xBE, 0x0F, 0x00,
141 : 0xBF, 0x0F, 0x00
142 : };
143 :
144 0 : (void)memcpy( mpnKey, pnPassData, 16 );
145 : sal_Int32 nIndex;
146 0 : sal_Int32 nLen = lclGetLen( pnPassData, 16 );
147 0 : const sal_uInt8* pnFillChar = spnFillChars;
148 0 : for( nIndex = nLen; nIndex < static_cast< sal_Int32 >( sizeof( mpnKey ) ); ++nIndex, ++pnFillChar )
149 0 : mpnKey[ nIndex ] = *pnFillChar;
150 :
151 : // rotation of key values is application dependent
152 0 : size_t nRotateSize = 0;
153 0 : switch( meCodecType )
154 : {
155 0 : case CODEC_WORD: nRotateSize = 7; break;
156 0 : case CODEC_EXCEL: nRotateSize = 2; break;
157 : // compiler will warn, if new codec type is introduced and not handled here
158 : }
159 :
160 : // use little-endian base key to create key array
161 : sal_uInt8 pnBaseKeyLE[ 2 ];
162 0 : pnBaseKeyLE[ 0 ] = static_cast< sal_uInt8 >( mnBaseKey );
163 0 : pnBaseKeyLE[ 1 ] = static_cast< sal_uInt8 >( mnBaseKey >> 8 );
164 0 : sal_uInt8* pnKeyChar = mpnKey;
165 0 : for( nIndex = 0; nIndex < static_cast< sal_Int32 >( sizeof( mpnKey ) ); ++nIndex, ++pnKeyChar )
166 : {
167 0 : *pnKeyChar ^= pnBaseKeyLE[ nIndex & 1 ];
168 0 : lclRotateLeft( *pnKeyChar, nRotateSize );
169 : }
170 0 : }
171 :
172 0 : bool BinaryCodec_XOR::initCodec( const uno::Sequence< beans::NamedValue >& aData )
173 : {
174 0 : bool bResult = false;
175 :
176 0 : ::comphelper::SequenceAsHashMap aHashData( aData );
177 0 : uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("XOR95EncryptionKey", uno::Sequence< sal_Int8 >() );
178 :
179 0 : if ( aKey.getLength() == 16 )
180 : {
181 0 : (void)memcpy( mpnKey, aKey.getConstArray(), 16 );
182 0 : bResult = true;
183 :
184 0 : mnBaseKey = (sal_uInt16)aHashData.getUnpackedValueOrDefault("XOR95BaseKey", (sal_Int16)0 );
185 0 : mnHash = (sal_uInt16)aHashData.getUnpackedValueOrDefault("XOR95PasswordHash", (sal_Int16)0 );
186 : }
187 : else
188 : OSL_FAIL( "Unexpected key size!\n" );
189 :
190 0 : return bResult;
191 : }
192 :
193 0 : uno::Sequence< beans::NamedValue > BinaryCodec_XOR::getEncryptionData()
194 : {
195 0 : ::comphelper::SequenceAsHashMap aHashData;
196 0 : aHashData[ OUString("XOR95EncryptionKey") ] <<= uno::Sequence<sal_Int8>( reinterpret_cast<sal_Int8*>(mpnKey), 16 );
197 0 : aHashData[ OUString("XOR95BaseKey") ] <<= (sal_Int16)mnBaseKey;
198 0 : aHashData[ OUString("XOR95PasswordHash") ] <<= (sal_Int16)mnHash;
199 :
200 0 : return aHashData.getAsConstNamedValueList();
201 : }
202 :
203 0 : bool BinaryCodec_XOR::verifyKey( sal_uInt16 nKey, sal_uInt16 nHash ) const
204 : {
205 0 : return (nKey == mnBaseKey) && (nHash == mnHash);
206 : }
207 :
208 0 : void BinaryCodec_XOR::startBlock()
209 : {
210 0 : mnOffset = 0;
211 0 : }
212 :
213 0 : bool BinaryCodec_XOR::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int32 nBytes )
214 : {
215 0 : const sal_uInt8* pnCurrKey = mpnKey + mnOffset;
216 0 : const sal_uInt8* pnKeyLast = mpnKey + 0x0F;
217 :
218 : // switch/case outside of the for loop (performance)
219 0 : const sal_uInt8* pnSrcDataEnd = pnSrcData + nBytes;
220 0 : switch( meCodecType )
221 : {
222 : case CODEC_WORD:
223 : {
224 0 : for( ; pnSrcData < pnSrcDataEnd; ++pnSrcData, ++pnDestData )
225 : {
226 0 : sal_uInt8 nData = *pnSrcData ^ *pnCurrKey;
227 0 : if( (*pnSrcData != 0) && (nData != 0) )
228 0 : *pnDestData = nData;
229 0 : if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
230 : }
231 : }
232 0 : break;
233 : case CODEC_EXCEL:
234 : {
235 0 : for( ; pnSrcData < pnSrcDataEnd; ++pnSrcData, ++pnDestData )
236 : {
237 0 : *pnDestData = *pnSrcData;
238 0 : lclRotateLeft( *pnDestData, 3 );
239 0 : *pnDestData ^= *pnCurrKey;
240 0 : if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
241 : }
242 : }
243 0 : break;
244 : // compiler will warn, if new codec type is introduced and not handled here
245 : }
246 :
247 : // update offset and leave
248 0 : return skip( nBytes );
249 : }
250 :
251 0 : bool BinaryCodec_XOR::skip( sal_Int32 nBytes )
252 : {
253 0 : mnOffset = static_cast< sal_Int32 >( (mnOffset + nBytes) & 0x0F );
254 0 : return true;
255 : }
256 :
257 0 : BinaryCodec_RCF::BinaryCodec_RCF()
258 : {
259 0 : mhCipher = rtl_cipher_create( rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream );
260 : OSL_ENSURE( mhCipher != 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create cipher" );
261 :
262 0 : mhDigest = rtl_digest_create( rtl_Digest_AlgorithmMD5 );
263 : OSL_ENSURE( mhDigest != 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create digest" );
264 :
265 0 : (void)memset( mpnDigestValue, 0, sizeof( mpnDigestValue ) );
266 0 : (void)memset (mpnUnique, 0, sizeof(mpnUnique));
267 0 : }
268 :
269 0 : BinaryCodec_RCF::~BinaryCodec_RCF()
270 : {
271 0 : (void)memset( mpnDigestValue, 0, sizeof( mpnDigestValue ) );
272 0 : (void)memset (mpnUnique, 0, sizeof(mpnUnique));
273 0 : rtl_digest_destroy( mhDigest );
274 0 : rtl_cipher_destroy( mhCipher );
275 0 : }
276 :
277 0 : bool BinaryCodec_RCF::initCodec( const uno::Sequence< beans::NamedValue >& aData )
278 : {
279 0 : bool bResult = false;
280 :
281 0 : ::comphelper::SequenceAsHashMap aHashData( aData );
282 0 : uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("STD97EncryptionKey", uno::Sequence< sal_Int8 >() );
283 :
284 0 : if ( aKey.getLength() == RTL_DIGEST_LENGTH_MD5 )
285 : {
286 0 : (void)memcpy( mpnDigestValue, aKey.getConstArray(), RTL_DIGEST_LENGTH_MD5 );
287 0 : uno::Sequence< sal_Int8 > aUniqueID = aHashData.getUnpackedValueOrDefault("STD97UniqueID", uno::Sequence< sal_Int8 >() );
288 0 : if ( aUniqueID.getLength() == 16 )
289 : {
290 0 : (void)memcpy( mpnUnique, aUniqueID.getConstArray(), 16 );
291 0 : bResult = false;
292 : }
293 : else
294 0 : OSL_FAIL( "Unexpected document ID!\n" );
295 : }
296 : else
297 : OSL_FAIL( "Unexpected key size!\n" );
298 :
299 0 : return bResult;
300 : }
301 :
302 0 : uno::Sequence< beans::NamedValue > BinaryCodec_RCF::getEncryptionData()
303 : {
304 0 : ::comphelper::SequenceAsHashMap aHashData;
305 0 : aHashData[ OUString("STD97EncryptionKey") ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8*>(mpnDigestValue), RTL_DIGEST_LENGTH_MD5 );
306 0 : aHashData[ OUString("STD97UniqueID") ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8*>(mpnUnique), 16 );
307 :
308 0 : return aHashData.getAsConstNamedValueList();
309 : }
310 :
311 0 : void BinaryCodec_RCF::initKey( const sal_uInt16 pnPassData[ 16 ], const sal_uInt8 pnSalt[ 16 ] )
312 : {
313 0 : 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.
315 :
316 0 : if ( aKey.getLength() == sizeof(mpnDigestValue) )
317 0 : (void)memcpy ( mpnDigestValue, aKey.getConstArray(), sizeof(mpnDigestValue) );
318 : else
319 0 : memset( mpnDigestValue, 0, sizeof(mpnDigestValue) );
320 :
321 0 : (void)memcpy( mpnUnique, pnSalt, 16 );
322 0 : }
323 :
324 0 : bool BinaryCodec_RCF::verifyKey( const sal_uInt8 pnVerifier[ 16 ], const sal_uInt8 pnVerifierHash[ 16 ] )
325 : {
326 0 : if( !startBlock( 0 ) )
327 0 : return false;
328 :
329 : sal_uInt8 pnDigest[ RTL_DIGEST_LENGTH_MD5 ];
330 : sal_uInt8 pnBuffer[ 64 ];
331 :
332 : // decode salt data into buffer
333 0 : rtl_cipher_decode( mhCipher, pnVerifier, 16, pnBuffer, sizeof( pnBuffer ) );
334 :
335 0 : pnBuffer[ 16 ] = 0x80;
336 0 : (void)memset( pnBuffer + 17, 0, sizeof( pnBuffer ) - 17 );
337 0 : pnBuffer[ 56 ] = 0x80;
338 :
339 : // fill raw digest of buffer into digest
340 0 : rtl_digest_updateMD5( mhDigest, pnBuffer, sizeof( pnBuffer ) );
341 0 : rtl_digest_rawMD5( mhDigest, pnDigest, sizeof( pnDigest ) );
342 :
343 : // decode original salt digest into buffer
344 0 : rtl_cipher_decode( mhCipher, pnVerifierHash, 16, pnBuffer, sizeof( pnBuffer ) );
345 :
346 : // compare buffer with computed digest
347 0 : bool bResult = memcmp( pnBuffer, pnDigest, sizeof( pnDigest ) ) == 0;
348 :
349 : // erase buffer and digest arrays and leave
350 0 : rtl_secureZeroMemory (pnBuffer, sizeof(pnBuffer));
351 0 : rtl_secureZeroMemory (pnDigest, sizeof(pnDigest));
352 0 : return bResult;
353 : }
354 :
355 0 : bool BinaryCodec_RCF::startBlock( sal_Int32 nCounter )
356 : {
357 : // initialize key data array
358 : sal_uInt8 pnKeyData[ 64 ];
359 0 : (void)memset( pnKeyData, 0, sizeof( pnKeyData ) );
360 :
361 : // fill 40 bit of digest value into [0..4]
362 0 : (void)memcpy( pnKeyData, mpnDigestValue, 5 );
363 :
364 : // fill little-endian counter into [5..8], static_cast masks out unneeded bits
365 0 : pnKeyData[ 5 ] = static_cast< sal_uInt8 >( nCounter );
366 0 : pnKeyData[ 6 ] = static_cast< sal_uInt8 >( nCounter >> 8 );
367 0 : pnKeyData[ 7 ] = static_cast< sal_uInt8 >( nCounter >> 16 );
368 0 : pnKeyData[ 8 ] = static_cast< sal_uInt8 >( nCounter >> 24 );
369 :
370 0 : pnKeyData[ 9 ] = 0x80;
371 0 : pnKeyData[ 56 ] = 0x48;
372 :
373 : // fill raw digest of key data into key data
374 0 : (void)rtl_digest_updateMD5( mhDigest, pnKeyData, sizeof( pnKeyData ) );
375 0 : (void)rtl_digest_rawMD5( mhDigest, pnKeyData, RTL_DIGEST_LENGTH_MD5 );
376 :
377 : // initialize cipher with key data (for decoding)
378 : rtlCipherError eResult =
379 0 : rtl_cipher_init( mhCipher, rtl_Cipher_DirectionDecode, pnKeyData, RTL_DIGEST_LENGTH_MD5, 0, 0 );
380 :
381 : // rrase key data array and leave
382 0 : rtl_secureZeroMemory (pnKeyData, sizeof(pnKeyData));
383 0 : return eResult == rtl_Cipher_E_None;
384 : }
385 :
386 0 : bool BinaryCodec_RCF::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int32 nBytes )
387 : {
388 : rtlCipherError eResult = rtl_cipher_decode( mhCipher,
389 : pnSrcData, static_cast< sal_Size >( nBytes ),
390 0 : pnDestData, static_cast< sal_Size >( nBytes ) );
391 0 : return eResult == rtl_Cipher_E_None;
392 : }
393 :
394 0 : bool BinaryCodec_RCF::skip( sal_Int32 nBytes )
395 : {
396 : // decode dummy data in memory to update internal state of RC4 cipher
397 : sal_uInt8 pnDummy[ 1024 ];
398 0 : sal_Int32 nBytesLeft = nBytes;
399 0 : bool bResult = true;
400 0 : while( bResult && (nBytesLeft > 0) )
401 : {
402 0 : sal_Int32 nBlockLen = ::std::min( nBytesLeft, static_cast< sal_Int32 >( sizeof( pnDummy ) ) );
403 0 : bResult = decode( pnDummy, pnDummy, nBlockLen );
404 0 : nBytesLeft -= nBlockLen;
405 : }
406 0 : return bResult;
407 : }
408 :
409 : } // namespace core
410 : } // namespace oox
411 :
412 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|