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 <comphelper/sequenceashashmap.hxx>
27 #include <comphelper/docpasswordhelper.hxx>
29 using namespace ::com::sun::star
;
34 // ============================================================================
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
)
59 while( (nLen
< nBufferSize
) && pnPassData
[ nLen
] ) ++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;
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
;
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
);
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 );
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
),
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,
149 (void)memcpy( mpnKey
, pnPassData
, 16 );
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 );
189 mnBaseKey
= (sal_uInt16
)aHashData
.getUnpackedValueOrDefault("XOR95BaseKey", (sal_Int16
)0 );
190 mnHash
= (sal_uInt16
)aHashData
.getUnpackedValueOrDefault("XOR95PasswordHash", (sal_Int16
)0 );
193 OSL_FAIL( "Unexpected key size!\n" );
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()
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
)
229 for( ; pnSrcData
< pnSrcDataEnd
; ++pnSrcData
, ++pnDestData
)
231 sal_uInt8 nData
= *pnSrcData
^ *pnCurrKey
;
232 if( (*pnSrcData
!= 0) && (nData
!= 0) )
234 if( pnCurrKey
< pnKeyLast
) ++pnCurrKey
; else pnCurrKey
= mpnKey
;
240 for( ; pnSrcData
< pnSrcDataEnd
; ++pnSrcData
, ++pnDestData
)
242 *pnDestData
= *pnSrcData
;
243 lclRotateLeft( *pnDestData
, 3 );
244 *pnDestData
^= *pnCurrKey
;
245 if( pnCurrKey
< pnKeyLast
) ++pnCurrKey
; else pnCurrKey
= mpnKey
;
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 );
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 );
301 OSL_FAIL( "Unexpected document ID!\n" );
304 OSL_FAIL( "Unexpected key size!\n" );
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
) );
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 ) )
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
) );
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
;
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
;
416 // ============================================================================
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */