1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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
;
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
)
58 while( (nLen
< nBufferSize
) && pnPassData
[ nLen
] ) ++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;
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
;
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
);
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 );
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
),
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,
144 (void)memcpy( mpnKey
, pnPassData
, 16 );
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 );
184 mnBaseKey
= (sal_uInt16
)aHashData
.getUnpackedValueOrDefault("XOR95BaseKey", (sal_Int16
)0 );
185 mnHash
= (sal_uInt16
)aHashData
.getUnpackedValueOrDefault("XOR95PasswordHash", (sal_Int16
)0 );
188 OSL_FAIL( "Unexpected key size!\n" );
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()
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
)
224 for( ; pnSrcData
< pnSrcDataEnd
; ++pnSrcData
, ++pnDestData
)
226 sal_uInt8 nData
= *pnSrcData
^ *pnCurrKey
;
227 if( (*pnSrcData
!= 0) && (nData
!= 0) )
229 if( pnCurrKey
< pnKeyLast
) ++pnCurrKey
; else pnCurrKey
= mpnKey
;
235 for( ; pnSrcData
< pnSrcDataEnd
; ++pnSrcData
, ++pnDestData
)
237 *pnDestData
= *pnSrcData
;
238 lclRotateLeft( *pnDestData
, 3 );
239 *pnDestData
^= *pnCurrKey
;
240 if( pnCurrKey
< pnKeyLast
) ++pnCurrKey
; else pnCurrKey
= mpnKey
;
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 );
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 );
294 OSL_FAIL( "Unexpected document ID!\n" );
297 OSL_FAIL( "Unexpected key size!\n" );
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
) );
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 ) )
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
));
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
;
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
;
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */