bump product version to 4.1.6.2
[LibreOffice.git] / filter / source / msfilter / mscodec.cxx
blob4eb15f7d081ba296875bee118872a2ca4cf4009b
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 "filter/msfilter/mscodec.hxx"
22 #include <osl/diagnose.h>
23 #include <algorithm>
24 #include <string.h>
25 #include <tools/solar.h>
27 #include <comphelper/sequenceashashmap.hxx>
28 #include <comphelper/docpasswordhelper.hxx>
30 #define DEBUG_MSO_ENCRYPTION_STD97 0
32 #if DEBUG_MSO_ENCRYPTION_STD97
33 #include <stdio.h>
34 #endif
36 using namespace ::com::sun::star;
38 namespace msfilter {
40 // ============================================================================
42 namespace {
44 /** Rotates rnValue left by nBits bits. */
45 template< typename Type >
46 inline void lclRotateLeft( Type& rnValue, int nBits )
48 OSL_ASSERT(
49 nBits >= 0 &&
50 sal::static_int_cast< unsigned int >(nBits) < sizeof( Type ) * 8 );
51 rnValue = static_cast< Type >( (rnValue << nBits) | (rnValue >> (sizeof( Type ) * 8 - nBits)) );
54 /** Rotates the lower nWidth bits of rnValue left by nBits bits. */
55 template< typename Type >
56 inline void lclRotateLeft( Type& rnValue, sal_uInt8 nBits, sal_uInt8 nWidth )
58 OSL_ASSERT( (nBits < nWidth) && (nWidth < sizeof( Type ) * 8) );
59 Type nMask = static_cast< Type >( (1UL << nWidth) - 1 );
60 rnValue = static_cast< Type >(
61 ((rnValue << nBits) | ((rnValue & nMask) >> (nWidth - nBits))) & nMask );
64 sal_Size lclGetLen( const sal_uInt8* pnPassData, sal_Size nBufferSize )
66 sal_Size nLen = 0;
67 while( (nLen < nBufferSize) && pnPassData[ nLen ] ) ++nLen;
68 return nLen;
71 sal_uInt16 lclGetKey( const sal_uInt8* pnPassData, sal_Size nBufferSize )
73 sal_Size nLen = lclGetLen( pnPassData, nBufferSize );
74 if( !nLen ) return 0;
76 sal_uInt16 nKey = 0;
77 sal_uInt16 nKeyBase = 0x8000;
78 sal_uInt16 nKeyEnd = 0xFFFF;
79 const sal_uInt8* pnChar = pnPassData + nLen - 1;
80 for( sal_Size nIndex = 0; nIndex < nLen; ++nIndex, --pnChar )
82 sal_uInt8 cChar = *pnChar & 0x7F;
83 for( sal_uInt8 nBit = 0; nBit < 8; ++nBit )
85 lclRotateLeft( nKeyBase, 1 );
86 if( nKeyBase & 1 ) nKeyBase ^= 0x1020;
87 if( cChar & 1 ) nKey ^= nKeyBase;
88 cChar >>= 1;
89 lclRotateLeft( nKeyEnd, 1 );
90 if( nKeyEnd & 1 ) nKeyEnd ^= 0x1020;
93 return nKey ^ nKeyEnd;
96 sal_uInt16 lclGetHash( const sal_uInt8* pnPassData, sal_Size nBufferSize )
98 sal_Size nLen = lclGetLen( pnPassData, nBufferSize );
100 sal_uInt16 nHash = static_cast< sal_uInt16 >( nLen );
101 if( nLen )
102 nHash ^= 0xCE4B;
104 const sal_uInt8* pnChar = pnPassData;
105 for( sal_Size nIndex = 0; nIndex < nLen; ++nIndex, ++pnChar )
107 sal_uInt16 cChar = *pnChar;
108 sal_uInt8 nRot = static_cast< sal_uInt8 >( (nIndex + 1) % 15 );
109 lclRotateLeft( cChar, nRot, 15 );
110 nHash ^= cChar;
112 return nHash;
116 } // namespace
118 // ============================================================================
120 MSCodec_Xor95::MSCodec_Xor95(int nRotateDistance) :
121 mnOffset( 0 ),
122 mnKey( 0 ),
123 mnHash( 0 ),
124 mnRotateDistance( nRotateDistance )
126 (void)memset( mpnKey, 0, sizeof( mpnKey ) );
129 MSCodec_Xor95::~MSCodec_Xor95()
131 (void)memset( mpnKey, 0, sizeof( mpnKey ) );
132 mnKey = mnHash = 0;
135 void MSCodec_Xor95::InitKey( const sal_uInt8 pnPassData[ 16 ] )
137 mnKey = lclGetKey( pnPassData, 16 );
138 mnHash = lclGetHash( pnPassData, 16 );
140 (void)memcpy( mpnKey, pnPassData, 16 );
142 static const sal_uInt8 spnFillChars[] =
144 0xBB, 0xFF, 0xFF, 0xBA,
145 0xFF, 0xFF, 0xB9, 0x80,
146 0x00, 0xBE, 0x0F, 0x00,
147 0xBF, 0x0F, 0x00
150 sal_Size nIndex;
151 sal_Size nLen = lclGetLen( pnPassData, 16 );
152 const sal_uInt8* pnFillChar = spnFillChars;
153 for( nIndex = nLen; nIndex < sizeof( mpnKey ); ++nIndex, ++pnFillChar )
154 mpnKey[ nIndex ] = *pnFillChar;
156 SVBT16 pnOrigKey;
157 ShortToSVBT16( mnKey, pnOrigKey );
158 sal_uInt8* pnKeyChar = mpnKey;
159 for( nIndex = 0; nIndex < sizeof( mpnKey ); ++nIndex, ++pnKeyChar )
161 *pnKeyChar ^= pnOrigKey[ nIndex & 0x01 ];
162 lclRotateLeft( *pnKeyChar, mnRotateDistance );
166 sal_Bool MSCodec_Xor95::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
168 sal_Bool bResult = sal_False;
170 ::comphelper::SequenceAsHashMap aHashData( aData );
171 uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( OUString( "XOR95EncryptionKey" ), uno::Sequence< sal_Int8 >() );
173 if ( aKey.getLength() == 16 )
175 (void)memcpy( mpnKey, aKey.getConstArray(), 16 );
176 bResult = sal_True;
178 mnKey = (sal_uInt16)aHashData.getUnpackedValueOrDefault( OUString( "XOR95BaseKey" ), (sal_Int16)0 );
179 mnHash = (sal_uInt16)aHashData.getUnpackedValueOrDefault( OUString( "XOR95PasswordHash" ), (sal_Int16)0 );
181 else
182 OSL_FAIL( "Unexpected key size!\n" );
184 return bResult;
187 uno::Sequence< beans::NamedValue > MSCodec_Xor95::GetEncryptionData()
189 ::comphelper::SequenceAsHashMap aHashData;
190 aHashData[ OUString( "XOR95EncryptionKey" ) ] <<= uno::Sequence<sal_Int8>( (sal_Int8*)mpnKey, 16 );
191 aHashData[ OUString( "XOR95BaseKey" ) ] <<= (sal_Int16)mnKey;
192 aHashData[ OUString( "XOR95PasswordHash" ) ] <<= (sal_Int16)mnHash;
194 return aHashData.getAsConstNamedValueList();
197 bool MSCodec_Xor95::VerifyKey( sal_uInt16 nKey, sal_uInt16 nHash ) const
199 return (nKey == mnKey) && (nHash == mnHash);
202 void MSCodec_Xor95::InitCipher()
204 mnOffset = 0;
207 void MSCodec_XorXLS95::Decode( sal_uInt8* pnData, sal_Size nBytes )
209 const sal_uInt8* pnCurrKey = mpnKey + mnOffset;
210 const sal_uInt8* pnKeyLast = mpnKey + 0x0F;
212 for( const sal_uInt8* pnDataEnd = pnData + nBytes; pnData < pnDataEnd; ++pnData )
214 lclRotateLeft( *pnData, 3 );
215 *pnData ^= *pnCurrKey;
216 if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
219 // update mnOffset
220 Skip( nBytes );
223 void MSCodec_XorWord95::Decode( sal_uInt8* pnData, sal_Size nBytes )
225 const sal_uInt8* pnCurrKey = mpnKey + mnOffset;
226 const sal_uInt8* pnKeyLast = mpnKey + 0x0F;
228 for( const sal_uInt8* pnDataEnd = pnData + nBytes; pnData < pnDataEnd; ++pnData )
230 const sal_uInt8 cChar = *pnData ^ *pnCurrKey;
231 if (*pnData && cChar)
232 *pnData = cChar;
234 if( pnCurrKey < pnKeyLast )
235 ++pnCurrKey;
236 else
237 pnCurrKey = mpnKey;
240 // update mnOffset
241 Skip( nBytes );
245 void MSCodec_Xor95::Skip( sal_Size nBytes )
247 mnOffset = (mnOffset + nBytes) & 0x0F;
250 // ============================================================================
252 MSCodec_Std97::MSCodec_Std97 ()
254 m_hCipher = rtl_cipher_create (
255 rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream);
256 OSL_ASSERT(m_hCipher != 0);
258 m_hDigest = rtl_digest_create (
259 rtl_Digest_AlgorithmMD5);
260 OSL_ASSERT(m_hDigest != 0);
262 (void)memset (m_pDigestValue, 0, sizeof(m_pDigestValue));
263 (void)memset (m_pDocId, 0, sizeof(m_pDocId));
266 MSCodec_Std97::~MSCodec_Std97 ()
268 (void)memset (m_pDigestValue, 0, sizeof(m_pDigestValue));
269 (void)memset (m_pDocId, 0, sizeof(m_pDocId));
270 rtl_digest_destroy (m_hDigest);
271 rtl_cipher_destroy (m_hCipher);
274 #if DEBUG_MSO_ENCRYPTION_STD97
275 static void lcl_PrintDigest(const sal_uInt8* pDigest, const char* msg)
277 printf("digest: (%s)\n", msg);
278 for (int i = 0; i < 16; ++i)
279 printf("%2.2x ", pDigest[i]);
280 printf("\n");
282 #else
283 static void lcl_PrintDigest(const sal_uInt8* /*pDigest*/, const char* /*msg*/)
286 #endif
288 sal_Bool MSCodec_Std97::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
290 #if DEBUG_MSO_ENCRYPTION_STD97
291 fprintf(stdout, "MSCodec_Std97::InitCodec: --begin\n");fflush(stdout);
292 #endif
293 sal_Bool bResult = sal_False;
295 ::comphelper::SequenceAsHashMap aHashData( aData );
296 uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( OUString( "STD97EncryptionKey" ), uno::Sequence< sal_Int8 >() );
298 if ( aKey.getLength() == RTL_DIGEST_LENGTH_MD5 )
300 (void)memcpy( m_pDigestValue, aKey.getConstArray(), RTL_DIGEST_LENGTH_MD5 );
301 uno::Sequence< sal_Int8 > aUniqueID = aHashData.getUnpackedValueOrDefault( OUString( "STD97UniqueID" ), uno::Sequence< sal_Int8 >() );
302 if ( aUniqueID.getLength() == 16 )
304 (void)memcpy( m_pDocId, aUniqueID.getConstArray(), 16 );
305 bResult = sal_True;
306 lcl_PrintDigest(m_pDigestValue, "digest value");
307 lcl_PrintDigest(m_pDocId, "DocId value");
309 else
310 OSL_FAIL( "Unexpected document ID!\n" );
312 else
313 OSL_FAIL( "Unexpected key size!\n" );
315 return bResult;
318 uno::Sequence< beans::NamedValue > MSCodec_Std97::GetEncryptionData()
320 ::comphelper::SequenceAsHashMap aHashData;
321 aHashData[ OUString( "STD97EncryptionKey" ) ] <<= uno::Sequence< sal_Int8 >( (sal_Int8*)m_pDigestValue, RTL_DIGEST_LENGTH_MD5 );
322 aHashData[ OUString( "STD97UniqueID" ) ] <<= uno::Sequence< sal_Int8 >( (sal_Int8*)m_pDocId, 16 );
324 return aHashData.getAsConstNamedValueList();
327 void MSCodec_Std97::InitKey (
328 const sal_uInt16 pPassData[16],
329 const sal_uInt8 pDocId[16])
331 #if DEBUG_MSO_ENCRYPTION_STD97
332 fprintf(stdout, "MSCodec_Std97::InitKey: --begin\n");fflush(stdout);
333 #endif
334 uno::Sequence< sal_Int8 > aKey = ::comphelper::DocPasswordHelper::GenerateStd97Key( pPassData, uno::Sequence< sal_Int8 >( (sal_Int8*)pDocId, 16 ) );
335 // Fill raw digest of above updates into DigestValue.
337 if ( aKey.getLength() == sizeof(m_pDigestValue) )
338 (void)memcpy ( m_pDigestValue, aKey.getConstArray(), sizeof(m_pDigestValue) );
339 else
340 memset( m_pDigestValue, 0, sizeof(m_pDigestValue) );
342 lcl_PrintDigest(m_pDigestValue, "digest value");
344 (void)memcpy (m_pDocId, pDocId, 16);
346 lcl_PrintDigest(m_pDocId, "DocId value");
349 bool MSCodec_Std97::VerifyKey (
350 const sal_uInt8 pSaltData[16],
351 const sal_uInt8 pSaltDigest[16])
353 // both the salt data and salt digest (hash) come from the document being imported.
355 #if DEBUG_MSO_ENCRYPTION_STD97
356 fprintf(stdout, "MSCodec_Std97::VerifyKey: \n");
357 lcl_PrintDigest(pSaltData, "salt data");
358 lcl_PrintDigest(pSaltDigest, "salt hash");
359 #endif
360 bool result = false;
362 if (InitCipher(0))
364 sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
365 GetDigestFromSalt(pSaltData, pDigest);
367 sal_uInt8 pBuffer[16];
368 // Decode original SaltDigest into Buffer.
369 rtl_cipher_decode (
370 m_hCipher, pSaltDigest, 16, pBuffer, sizeof(pBuffer));
372 // Compare Buffer with computed Digest.
373 result = (memcmp (pBuffer, pDigest, sizeof(pDigest)) == 0);
375 // Erase Buffer and Digest arrays.
376 (void)memset (pBuffer, 0, sizeof(pBuffer));
377 (void)memset (pDigest, 0, sizeof(pDigest));
380 return (result);
383 bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter)
385 rtlCipherError result;
386 sal_uInt8 pKeyData[64]; // 512-bit message block
388 // Initialize KeyData array.
389 (void)memset (pKeyData, 0, sizeof(pKeyData));
391 // Fill 40 bit of DigestValue into [0..4].
392 (void)memcpy (pKeyData, m_pDigestValue, 5);
394 // Fill counter into [5..8].
395 pKeyData[ 5] = sal_uInt8((nCounter >> 0) & 0xff);
396 pKeyData[ 6] = sal_uInt8((nCounter >> 8) & 0xff);
397 pKeyData[ 7] = sal_uInt8((nCounter >> 16) & 0xff);
398 pKeyData[ 8] = sal_uInt8((nCounter >> 24) & 0xff);
400 pKeyData[ 9] = 0x80;
401 pKeyData[56] = 0x48;
403 // Fill raw digest of KeyData into KeyData.
404 (void)rtl_digest_updateMD5 (
405 m_hDigest, pKeyData, sizeof(pKeyData));
406 (void)rtl_digest_rawMD5 (
407 m_hDigest, pKeyData, RTL_DIGEST_LENGTH_MD5);
409 // Initialize Cipher with KeyData (for decoding).
410 result = rtl_cipher_init (
411 m_hCipher, rtl_Cipher_DirectionBoth,
412 pKeyData, RTL_DIGEST_LENGTH_MD5, 0, 0);
414 // Erase KeyData array and leave.
415 (void)memset (pKeyData, 0, sizeof(pKeyData));
417 return (result == rtl_Cipher_E_None);
420 bool MSCodec_Std97::CreateSaltDigest( const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] )
422 #if DEBUG_MSO_ENCRYPTION_STD97
423 lcl_PrintDigest(nSaltData, "salt data");
424 #endif
425 bool result = false;
427 if (InitCipher(0))
429 sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
430 GetDigestFromSalt(nSaltData, pDigest);
432 rtl_cipher_decode (
433 m_hCipher, pDigest, 16, pDigest, sizeof(pDigest));
435 (void)memcpy(nSaltDigest, pDigest, 16);
438 return (result);
441 bool MSCodec_Std97::Encode (
442 const void *pData, sal_Size nDatLen,
443 sal_uInt8 *pBuffer, sal_Size nBufLen)
445 rtlCipherError result;
447 result = rtl_cipher_encode (
448 m_hCipher, pData, nDatLen, pBuffer, nBufLen);
450 return (result == rtl_Cipher_E_None);
453 bool MSCodec_Std97::Decode (
454 const void *pData, sal_Size nDatLen,
455 sal_uInt8 *pBuffer, sal_Size nBufLen)
457 rtlCipherError result;
459 result = rtl_cipher_decode (
460 m_hCipher, pData, nDatLen, pBuffer, nBufLen);
462 return (result == rtl_Cipher_E_None);
465 bool MSCodec_Std97::Skip( sal_Size nDatLen )
467 sal_uInt8 pnDummy[ 1024 ];
468 sal_Size nDatLeft = nDatLen;
469 bool bResult = true;
471 while (bResult && nDatLeft)
473 sal_Size nBlockLen = ::std::min< sal_Size >( nDatLeft, sizeof(pnDummy) );
474 bResult = Decode( pnDummy, nBlockLen, pnDummy, nBlockLen );
475 nDatLeft -= nBlockLen;
478 return bResult;
481 void MSCodec_Std97::GetDigestFromSalt( const sal_uInt8 pSaltData[16], sal_uInt8 pDigest[16] )
483 sal_uInt8 pBuffer[64];
484 sal_uInt8 pDigestLocal[16];
486 // Decode SaltData into Buffer.
487 rtl_cipher_decode (
488 m_hCipher, pSaltData, 16, pBuffer, sizeof(pBuffer));
490 // set the 129th bit to make the buffer 128-bit in length.
491 pBuffer[16] = 0x80;
493 // erase the rest of the buffer with zeros.
494 (void)memset (pBuffer + 17, 0, sizeof(pBuffer) - 17);
496 // set the 441st bit.
497 pBuffer[56] = 0x80;
499 // Fill raw digest of Buffer into Digest.
500 rtl_digest_updateMD5 (
501 m_hDigest, pBuffer, sizeof(pBuffer));
502 rtl_digest_rawMD5 (
503 m_hDigest, pDigestLocal, sizeof(pDigestLocal));
505 memcpy(pDigest, pDigestLocal, 16);
508 void MSCodec_Std97::GetEncryptKey (
509 const sal_uInt8 pSalt[16],
510 sal_uInt8 pSaltData[16],
511 sal_uInt8 pSaltDigest[16])
513 if (InitCipher(0))
515 sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
516 sal_uInt8 pBuffer[64];
518 rtl_cipher_encode (
519 m_hCipher, pSalt, 16, pSaltData, sizeof(pBuffer));
521 (void)memcpy( pBuffer, pSalt, 16 );
523 pBuffer[16] = 0x80;
524 (void)memset (pBuffer + 17, 0, sizeof(pBuffer) - 17);
525 pBuffer[56] = 0x80;
527 rtl_digest_updateMD5 (
528 m_hDigest, pBuffer, sizeof(pBuffer));
529 rtl_digest_rawMD5 (
530 m_hDigest, pDigest, sizeof(pDigest));
532 rtl_cipher_encode (
533 m_hCipher, pDigest, 16, pSaltDigest, 16);
535 (void)memset (pBuffer, 0, sizeof(pBuffer));
536 (void)memset (pDigest, 0, sizeof(pDigest));
540 void MSCodec_Std97::GetDocId( sal_uInt8 pDocId[16] )
542 if ( sizeof( m_pDocId ) == 16 )
543 (void)memcpy( pDocId, m_pDocId, 16 );
546 // ============================================================================
548 } // namespace svx
550 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */