1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: binarycodec.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/core/binarycodec.hxx"
34 #include "oox/helper/attributelist.hxx"
39 // ============================================================================
43 /** Rotates rnValue left by nBits bits. */
44 template< typename Type
>
45 inline void lclRotateLeft( Type
& rnValue
, size_t nBits
)
47 OSL_ENSURE( nBits
< sizeof( Type
) * 8, "lclRotateLeft - rotation count overflow" );
48 rnValue
= static_cast< Type
>( (rnValue
<< nBits
) | (rnValue
>> (sizeof( Type
) * 8 - nBits
)) );
51 /** Rotates the lower nWidth bits of rnValue left by nBits bits. */
52 template< typename Type
>
53 inline void lclRotateLeft( Type
& rnValue
, size_t nBits
, size_t nWidth
)
55 OSL_ENSURE( (nBits
< nWidth
) && (nWidth
< sizeof( Type
) * 8), "lclRotateLeft - rotation count overflow" );
56 Type nMask
= static_cast< Type
>( (1UL << nWidth
) - 1 );
57 rnValue
= static_cast< Type
>(
58 ((rnValue
<< nBits
) | ((rnValue
& nMask
) >> (nWidth
- nBits
))) & nMask
);
61 sal_Int32
lclGetLen( const sal_uInt8
* pnPassData
, sal_Int32 nBufferSize
)
64 while( (nLen
< nBufferSize
) && pnPassData
[ nLen
] ) ++nLen
;
68 sal_uInt16
lclGetKey( const sal_uInt8
* pnPassData
, sal_Int32 nBufferSize
)
70 sal_Int32 nLen
= lclGetLen( pnPassData
, nBufferSize
);
71 if( nLen
<= 0 ) return 0;
74 sal_uInt16 nKeyBase
= 0x8000;
75 sal_uInt16 nKeyEnd
= 0xFFFF;
76 const sal_uInt8
* pnChar
= pnPassData
+ nLen
- 1;
77 for( sal_Int32 nIndex
= 0; nIndex
< nLen
; ++nIndex
, --pnChar
)
79 sal_uInt8 cChar
= *pnChar
& 0x7F;
80 for( size_t nBit
= 0; nBit
< 8; ++nBit
)
82 lclRotateLeft( nKeyBase
, 1 );
83 if( nKeyBase
& 1 ) nKeyBase
^= 0x1020;
84 if( cChar
& 1 ) nKey
^= nKeyBase
;
86 lclRotateLeft( nKeyEnd
, 1 );
87 if( nKeyEnd
& 1 ) nKeyEnd
^= 0x1020;
90 return nKey
^ nKeyEnd
;
93 sal_uInt16
lclGetHash( const sal_uInt8
* pnPassData
, sal_Int32 nBufferSize
)
95 sal_Int32 nLen
= lclGetLen( pnPassData
, nBufferSize
);
97 sal_uInt16 nHash
= static_cast< sal_uInt16
>( nLen
);
101 const sal_uInt8
* pnChar
= pnPassData
;
102 for( sal_Int32 nIndex
= 0; nIndex
< nLen
; ++nIndex
, ++pnChar
)
104 sal_uInt16 cChar
= *pnChar
;
105 size_t nRot
= static_cast< size_t >( (nIndex
+ 1) % 15 );
106 lclRotateLeft( cChar
, nRot
, 15 );
114 // ============================================================================
116 /*static*/ sal_uInt16
CodecHelper::getPasswordHash( const AttributeList
& rAttribs
, sal_Int32 nElement
)
118 sal_Int32 nPasswordHash
= rAttribs
.getIntegerHex( nElement
, 0 );
119 OSL_ENSURE( (0 <= nPasswordHash
) && (nPasswordHash
<= SAL_MAX_UINT16
), "CodecHelper::getPasswordHash - invalid password hash" );
120 return static_cast< sal_uInt16
>( ((0 <= nPasswordHash
) && (nPasswordHash
<= SAL_MAX_UINT16
)) ? nPasswordHash
: 0 );
123 // ============================================================================
125 BinaryCodec_XOR::BinaryCodec_XOR( CodecType eCodecType
) :
126 meCodecType( eCodecType
),
131 (void)memset( mpnKey
, 0, sizeof( mpnKey
) );
134 BinaryCodec_XOR::~BinaryCodec_XOR()
136 (void)memset( mpnKey
, 0, sizeof( mpnKey
) );
137 mnBaseKey
= mnHash
= 0;
140 void BinaryCodec_XOR::initKey( const sal_uInt8 pnPassData
[ 16 ] )
142 // calculate base key and hash from passed password
143 mnBaseKey
= lclGetKey( pnPassData
, 16 );
144 mnHash
= lclGetHash( pnPassData
, 16 );
146 static const sal_uInt8 spnFillChars
[] =
148 0xBB, 0xFF, 0xFF, 0xBA,
149 0xFF, 0xFF, 0xB9, 0x80,
150 0x00, 0xBE, 0x0F, 0x00,
154 (void)memcpy( mpnKey
, pnPassData
, 16 );
156 sal_Int32 nLen
= lclGetLen( pnPassData
, 16 );
157 const sal_uInt8
* pnFillChar
= spnFillChars
;
158 for( nIndex
= nLen
; nIndex
< static_cast< sal_Int32
>( sizeof( mpnKey
) ); ++nIndex
, ++pnFillChar
)
159 mpnKey
[ nIndex
] = *pnFillChar
;
161 // rotation of key values is application dependent
162 size_t nRotateSize
= 0;
163 switch( meCodecType
)
165 case CODEC_WORD
: nRotateSize
= 7; break;
166 case CODEC_EXCEL
: nRotateSize
= 2; break;
167 // compiler will warn, if new codec type is introduced and not handled here
170 // use little-endian base key to create key array
171 sal_uInt8 pnBaseKeyLE
[ 2 ];
172 pnBaseKeyLE
[ 0 ] = static_cast< sal_uInt8
>( mnBaseKey
);
173 pnBaseKeyLE
[ 1 ] = static_cast< sal_uInt8
>( mnBaseKey
>> 8 );
174 sal_uInt8
* pnKeyChar
= mpnKey
;
175 for( nIndex
= 0; nIndex
< static_cast< sal_Int32
>( sizeof( mpnKey
) ); ++nIndex
, ++pnKeyChar
)
177 *pnKeyChar
^= pnBaseKeyLE
[ nIndex
& 1 ];
178 lclRotateLeft( *pnKeyChar
, nRotateSize
);
182 bool BinaryCodec_XOR::verifyKey( sal_uInt16 nKey
, sal_uInt16 nHash
) const
184 return (nKey
== mnBaseKey
) && (nHash
== mnHash
);
187 void BinaryCodec_XOR::startBlock()
192 bool BinaryCodec_XOR::decode( sal_uInt8
* pnDestData
, const sal_uInt8
* pnSrcData
, sal_Int32 nBytes
)
194 const sal_uInt8
* pnCurrKey
= mpnKey
+ mnOffset
;
195 const sal_uInt8
* pnKeyLast
= mpnKey
+ 0x0F;
197 // switch/case outside of the for loop (performance)
198 const sal_uInt8
* pnSrcDataEnd
= pnSrcData
+ nBytes
;
199 switch( meCodecType
)
203 for( ; pnSrcData
< pnSrcDataEnd
; ++pnSrcData
, ++pnDestData
)
205 sal_uInt8 nData
= *pnSrcData
^ *pnCurrKey
;
206 if( (*pnSrcData
!= 0) && (nData
!= 0) )
208 if( pnCurrKey
< pnKeyLast
) ++pnCurrKey
; else pnCurrKey
= mpnKey
;
214 for( ; pnSrcData
< pnSrcDataEnd
; ++pnSrcData
, ++pnDestData
)
216 *pnDestData
= *pnSrcData
;
217 lclRotateLeft( *pnDestData
, 3 );
218 *pnDestData
^= *pnCurrKey
;
219 if( pnCurrKey
< pnKeyLast
) ++pnCurrKey
; else pnCurrKey
= mpnKey
;
223 // compiler will warn, if new codec type is introduced and not handled here
226 // update offset and leave
227 return skip( nBytes
);
230 bool BinaryCodec_XOR::skip( sal_Int32 nBytes
)
232 mnOffset
= static_cast< sal_Int32
>( (mnOffset
+ nBytes
) & 0x0F );
236 sal_uInt16
BinaryCodec_XOR::getHash( const sal_uInt8
* pnPassData
, sal_Int32 nSize
)
238 return lclGetHash( pnPassData
, nSize
);
241 // ============================================================================
243 BinaryCodec_RCF::BinaryCodec_RCF()
245 mhCipher
= rtl_cipher_create( rtl_Cipher_AlgorithmARCFOUR
, rtl_Cipher_ModeStream
);
246 OSL_ENSURE( mhCipher
!= 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create cipher" );
248 mhDigest
= rtl_digest_create( rtl_Digest_AlgorithmMD5
);
249 OSL_ENSURE( mhDigest
!= 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create digest" );
251 (void)memset( mpnDigestValue
, 0, sizeof( mpnDigestValue
) );
254 BinaryCodec_RCF::~BinaryCodec_RCF()
256 (void)memset( mpnDigestValue
, 0, sizeof( mpnDigestValue
) );
257 rtl_digest_destroy( mhDigest
);
258 rtl_cipher_destroy( mhCipher
);
261 void BinaryCodec_RCF::initKey( const sal_uInt16 pnPassData
[ 16 ], const sal_uInt8 pnSalt
[ 16 ] )
263 // create little-endian key data array from password data
264 sal_uInt8 pnKeyData
[ 64 ];
265 (void)memset( pnKeyData
, 0, sizeof( pnKeyData
) );
267 const sal_uInt16
* pnCurrPass
= pnPassData
;
268 const sal_uInt16
* pnPassEnd
= pnPassData
+ 16;
269 sal_uInt8
* pnCurrKey
= pnKeyData
;
270 size_t nPassSize
= 0;
271 for( ; (pnCurrPass
< pnPassEnd
) && (*pnCurrPass
!= 0); ++pnCurrPass
, ++nPassSize
)
273 *pnCurrKey
++ = static_cast< sal_uInt8
>( *pnCurrPass
);
274 *pnCurrKey
++ = static_cast< sal_uInt8
>( *pnCurrPass
>> 8 );
276 pnKeyData
[ 2 * nPassSize
] = 0x80;
277 pnKeyData
[ 56 ] = static_cast< sal_uInt8
>( nPassSize
<< 4 );
279 // fill raw digest of key data into key data
280 (void)rtl_digest_updateMD5( mhDigest
, pnKeyData
, sizeof( pnKeyData
) );
281 (void)rtl_digest_rawMD5( mhDigest
, pnKeyData
, RTL_DIGEST_LENGTH_MD5
);
283 // update digest with key data and passed salt data
284 for( size_t nIndex
= 0; nIndex
< 16; ++nIndex
)
286 rtl_digest_updateMD5( mhDigest
, pnKeyData
, 5 );
287 rtl_digest_updateMD5( mhDigest
, pnSalt
, 16 );
290 // update digest with padding
291 pnKeyData
[ 16 ] = 0x80;
292 (void)memset( pnKeyData
+ 17, 0, sizeof( pnKeyData
) - 17 );
293 pnKeyData
[ 56 ] = 0x80;
294 pnKeyData
[ 57 ] = 0x0A;
295 rtl_digest_updateMD5( mhDigest
, pnKeyData
+ 16, sizeof( pnKeyData
) - 16 );
297 // fill raw digest of above updates into digest value
298 rtl_digest_rawMD5( mhDigest
, mpnDigestValue
, sizeof( mpnDigestValue
) );
300 // erase key data array and leave
301 (void)memset( pnKeyData
, 0, sizeof( pnKeyData
) );
304 bool BinaryCodec_RCF::verifyKey( const sal_uInt8 pnVerifier
[ 16 ], const sal_uInt8 pnVerifierHash
[ 16 ] )
306 if( !startBlock( 0 ) )
309 sal_uInt8 pnDigest
[ RTL_DIGEST_LENGTH_MD5
];
310 sal_uInt8 pnBuffer
[ 64 ];
312 // decode salt data into buffer
313 rtl_cipher_decode( mhCipher
, pnVerifier
, 16, pnBuffer
, sizeof( pnBuffer
) );
315 pnBuffer
[ 16 ] = 0x80;
316 (void)memset( pnBuffer
+ 17, 0, sizeof( pnBuffer
) - 17 );
317 pnBuffer
[ 56 ] = 0x80;
319 // fill raw digest of buffer into digest
320 rtl_digest_updateMD5( mhDigest
, pnBuffer
, sizeof( pnBuffer
) );
321 rtl_digest_rawMD5( mhDigest
, pnDigest
, sizeof( pnDigest
) );
323 // decode original salt digest into buffer
324 rtl_cipher_decode( mhCipher
, pnVerifierHash
, 16, pnBuffer
, sizeof( pnBuffer
) );
326 // compare buffer with computed digest
327 bool bResult
= memcmp( pnBuffer
, pnDigest
, sizeof( pnDigest
) ) == 0;
329 // erase buffer and digest arrays and leave
330 (void)memset( pnBuffer
, 0, sizeof( pnBuffer
) );
331 (void)memset( pnDigest
, 0, sizeof( pnDigest
) );
335 bool BinaryCodec_RCF::startBlock( sal_Int32 nCounter
)
337 // initialize key data array
338 sal_uInt8 pnKeyData
[ 64 ];
339 (void)memset( pnKeyData
, 0, sizeof( pnKeyData
) );
341 // fill 40 bit of digest value into [0..4]
342 (void)memcpy( pnKeyData
, mpnDigestValue
, 5 );
344 // fill little-endian counter into [5..8], static_cast masks out unneeded bits
345 pnKeyData
[ 5 ] = static_cast< sal_uInt8
>( nCounter
);
346 pnKeyData
[ 6 ] = static_cast< sal_uInt8
>( nCounter
>> 8 );
347 pnKeyData
[ 7 ] = static_cast< sal_uInt8
>( nCounter
>> 16 );
348 pnKeyData
[ 8 ] = static_cast< sal_uInt8
>( nCounter
>> 24 );
350 pnKeyData
[ 9 ] = 0x80;
351 pnKeyData
[ 56 ] = 0x48;
353 // fill raw digest of key data into key data
354 (void)rtl_digest_updateMD5( mhDigest
, pnKeyData
, sizeof( pnKeyData
) );
355 (void)rtl_digest_rawMD5( mhDigest
, pnKeyData
, RTL_DIGEST_LENGTH_MD5
);
357 // initialize cipher with key data (for decoding)
358 rtlCipherError eResult
=
359 rtl_cipher_init( mhCipher
, rtl_Cipher_DirectionDecode
, pnKeyData
, RTL_DIGEST_LENGTH_MD5
, 0, 0 );
361 // rrase key data array and leave
362 (void)memset( pnKeyData
, 0, sizeof( pnKeyData
) );
363 return eResult
== rtl_Cipher_E_None
;
366 bool BinaryCodec_RCF::decode( sal_uInt8
* pnDestData
, const sal_uInt8
* pnSrcData
, sal_Int32 nBytes
)
368 rtlCipherError eResult
= rtl_cipher_decode( mhCipher
,
369 pnSrcData
, static_cast< sal_Size
>( nBytes
),
370 pnDestData
, static_cast< sal_Size
>( nBytes
) );
371 return eResult
== rtl_Cipher_E_None
;
374 bool BinaryCodec_RCF::skip( sal_Int32 nBytes
)
376 // decode dummy data in memory to update internal state of RC4 cipher
377 sal_uInt8 pnDummy
[ 1024 ];
378 sal_Int32 nBytesLeft
= nBytes
;
380 while( bResult
&& (nBytesLeft
> 0) )
382 sal_Int32 nBlockLen
= ::std::min( nBytesLeft
, static_cast< sal_Int32
>( sizeof( pnDummy
) ) );
383 bResult
= decode( pnDummy
, pnDummy
, nBlockLen
);
384 nBytesLeft
-= nBlockLen
;
389 // ============================================================================