xref: /trunk/main/filter/source/msfilter/mscodec.cxx (revision 9e0fc027)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26 #include "filter/msfilter/mscodec.hxx"
27 
28 #include <osl/diagnose.h>
29 #include <algorithm>
30 #include <string.h>
31 #include <tools/solar.h>
32 
33 #include <comphelper/sequenceashashmap.hxx>
34 #include <comphelper/docpasswordhelper.hxx>
35 
36 #define DEBUG_MSO_ENCRYPTION_STD97 0
37 
38 #if DEBUG_MSO_ENCRYPTION_STD97
39 #include <stdio.h>
40 #endif
41 
42 using namespace ::com::sun::star;
43 
44 namespace msfilter {
45 
46 // ============================================================================
47 
48 namespace {
49 
50 /** Rotates rnValue left by nBits bits. */
51 template< typename Type >
lclRotateLeft(Type & rnValue,int nBits)52 inline void lclRotateLeft( Type& rnValue, int nBits )
53 {
54     OSL_ASSERT(
55         nBits >= 0 &&
56         sal::static_int_cast< unsigned int >(nBits) < sizeof( Type ) * 8 );
57     rnValue = static_cast< Type >( (rnValue << nBits) | (rnValue >> (sizeof( Type ) * 8 - nBits)) );
58 }
59 
60 /** Rotates the lower nWidth bits of rnValue left by nBits bits. */
61 template< typename Type >
lclRotateLeft(Type & rnValue,sal_uInt8 nBits,sal_uInt8 nWidth)62 inline void lclRotateLeft( Type& rnValue, sal_uInt8 nBits, sal_uInt8 nWidth )
63 {
64     OSL_ASSERT( (nBits < nWidth) && (nWidth < sizeof( Type ) * 8) );
65     Type nMask = static_cast< Type >( (1UL << nWidth) - 1 );
66     rnValue = static_cast< Type >(
67         ((rnValue << nBits) | ((rnValue & nMask) >> (nWidth - nBits))) & nMask );
68 }
69 
lclGetLen(const sal_uInt8 * pnPassData,sal_Size nBufferSize)70 sal_Size lclGetLen( const sal_uInt8* pnPassData, sal_Size nBufferSize )
71 {
72     sal_Size nLen = 0;
73     while( (nLen < nBufferSize) && pnPassData[ nLen ] ) ++nLen;
74     return nLen;
75 }
76 
lclGetKey(const sal_uInt8 * pnPassData,sal_Size nBufferSize)77 sal_uInt16 lclGetKey( const sal_uInt8* pnPassData, sal_Size nBufferSize )
78 {
79     sal_Size nLen = lclGetLen( pnPassData, nBufferSize );
80     if( !nLen ) return 0;
81 
82     sal_uInt16 nKey = 0;
83     sal_uInt16 nKeyBase = 0x8000;
84     sal_uInt16 nKeyEnd = 0xFFFF;
85     const sal_uInt8* pnChar = pnPassData + nLen - 1;
86     for( sal_Size nIndex = 0; nIndex < nLen; ++nIndex, --pnChar )
87     {
88         sal_uInt8 cChar = *pnChar & 0x7F;
89         for( sal_uInt8 nBit = 0; nBit < 8; ++nBit )
90         {
91             lclRotateLeft( nKeyBase, 1 );
92             if( nKeyBase & 1 ) nKeyBase ^= 0x1020;
93             if( cChar & 1 ) nKey ^= nKeyBase;
94             cChar >>= 1;
95             lclRotateLeft( nKeyEnd, 1 );
96             if( nKeyEnd & 1 ) nKeyEnd ^= 0x1020;
97         }
98     }
99     return nKey ^ nKeyEnd;
100 }
101 
lclGetHash(const sal_uInt8 * pnPassData,sal_Size nBufferSize)102 sal_uInt16 lclGetHash( const sal_uInt8* pnPassData, sal_Size nBufferSize )
103 {
104     sal_Size nLen = lclGetLen( pnPassData, nBufferSize );
105 
106     sal_uInt16 nHash = static_cast< sal_uInt16 >( nLen );
107     if( nLen )
108         nHash ^= 0xCE4B;
109 
110     const sal_uInt8* pnChar = pnPassData;
111     for( sal_Size nIndex = 0; nIndex < nLen; ++nIndex, ++pnChar )
112     {
113         sal_uInt16 cChar = *pnChar;
114         sal_uInt8 nRot = static_cast< sal_uInt8 >( (nIndex + 1) % 15 );
115         lclRotateLeft( cChar, nRot, 15 );
116         nHash ^= cChar;
117     }
118     return nHash;
119 }
120 
121 
122 } // namespace
123 
124 // ============================================================================
125 
MSCodec_Xor95(int nRotateDistance)126 MSCodec_Xor95::MSCodec_Xor95(int nRotateDistance) :
127     mnOffset( 0 ),
128     mnKey( 0 ),
129     mnHash( 0 ),
130     mnRotateDistance( nRotateDistance )
131 {
132     (void)memset( mpnKey, 0, sizeof( mpnKey ) );
133 }
134 
~MSCodec_Xor95()135 MSCodec_Xor95::~MSCodec_Xor95()
136 {
137     (void)memset( mpnKey, 0, sizeof( mpnKey ) );
138     mnKey = mnHash = 0;
139 }
140 
InitKey(const sal_uInt8 pnPassData[16])141 void MSCodec_Xor95::InitKey( const sal_uInt8 pnPassData[ 16 ] )
142 {
143     mnKey = lclGetKey( pnPassData, 16 );
144     mnHash = lclGetHash( pnPassData, 16 );
145 
146     (void)memcpy( mpnKey, pnPassData, 16 );
147 
148     static const sal_uInt8 spnFillChars[] =
149     {
150         0xBB, 0xFF, 0xFF, 0xBA,
151         0xFF, 0xFF, 0xB9, 0x80,
152         0x00, 0xBE, 0x0F, 0x00,
153         0xBF, 0x0F, 0x00
154     };
155 
156     sal_Size nIndex;
157     sal_Size nLen = lclGetLen( pnPassData, 16 );
158     const sal_uInt8* pnFillChar = spnFillChars;
159     for( nIndex = nLen; nIndex < sizeof( mpnKey ); ++nIndex, ++pnFillChar )
160         mpnKey[ nIndex ] = *pnFillChar;
161 
162     SVBT16 pnOrigKey;
163     ShortToSVBT16( mnKey, pnOrigKey );
164     sal_uInt8* pnKeyChar = mpnKey;
165     for( nIndex = 0; nIndex < sizeof( mpnKey ); ++nIndex, ++pnKeyChar )
166     {
167         *pnKeyChar ^= pnOrigKey[ nIndex & 0x01 ];
168         lclRotateLeft( *pnKeyChar, mnRotateDistance );
169     }
170 }
171 
InitCodec(const uno::Sequence<beans::NamedValue> & aData)172 sal_Bool MSCodec_Xor95::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
173 {
174     sal_Bool bResult = sal_False;
175 
176 	::comphelper::SequenceAsHashMap aHashData( aData );
177     uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95EncryptionKey" ) ), uno::Sequence< sal_Int8 >() );
178 
179     if ( aKey.getLength() == 16 )
180     {
181         (void)memcpy( mpnKey, aKey.getConstArray(), 16 );
182         bResult = sal_True;
183 
184         mnKey = (sal_uInt16)aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95BaseKey" ) ), (sal_Int16)0 );
185         mnHash = (sal_uInt16)aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95PasswordHash" ) ), (sal_Int16)0 );
186     }
187     else
188         OSL_ENSURE( sal_False, "Unexpected key size!\n" );
189 
190     return bResult;
191 }
192 
GetEncryptionData()193 uno::Sequence< beans::NamedValue > MSCodec_Xor95::GetEncryptionData()
194 {
195     ::comphelper::SequenceAsHashMap aHashData;
196     aHashData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95EncryptionKey" ) ) ] <<= uno::Sequence<sal_Int8>( (sal_Int8*)mpnKey, 16 );
197     aHashData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95BaseKey" ) ) ] <<= (sal_Int16)mnKey;
198     aHashData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95PasswordHash" ) ) ] <<= (sal_Int16)mnHash;
199 
200     return aHashData.getAsConstNamedValueList();
201 }
202 
VerifyKey(sal_uInt16 nKey,sal_uInt16 nHash) const203 bool MSCodec_Xor95::VerifyKey( sal_uInt16 nKey, sal_uInt16 nHash ) const
204 {
205     return (nKey == mnKey) && (nHash == mnHash);
206 }
207 
InitCipher()208 void MSCodec_Xor95::InitCipher()
209 {
210     mnOffset = 0;
211 }
212 
Decode(sal_uInt8 * pnData,sal_Size nBytes)213 void MSCodec_XorXLS95::Decode( sal_uInt8* pnData, sal_Size nBytes )
214 {
215     const sal_uInt8* pnCurrKey = mpnKey + mnOffset;
216     const sal_uInt8* pnKeyLast = mpnKey + 0x0F;
217 
218     for( const sal_uInt8* pnDataEnd = pnData + nBytes; pnData < pnDataEnd; ++pnData )
219     {
220         lclRotateLeft( *pnData, 3 );
221         *pnData ^= *pnCurrKey;
222         if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
223     }
224 
225     // update mnOffset
226     Skip( nBytes );
227 }
228 
Decode(sal_uInt8 * pnData,sal_Size nBytes)229 void MSCodec_XorWord95::Decode( sal_uInt8* pnData, sal_Size nBytes )
230 {
231     const sal_uInt8* pnCurrKey = mpnKey + mnOffset;
232     const sal_uInt8* pnKeyLast = mpnKey + 0x0F;
233 
234     for( const sal_uInt8* pnDataEnd = pnData + nBytes; pnData < pnDataEnd; ++pnData )
235     {
236     	const sal_uInt8 cChar = *pnData ^ *pnCurrKey;
237 	if (*pnData && cChar)
238 	    *pnData = cChar;
239         if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
240     }
241 
242     // update mnOffset
243     Skip( nBytes );
244 }
245 
246 
Skip(sal_Size nBytes)247 void MSCodec_Xor95::Skip( sal_Size nBytes )
248 {
249     mnOffset = (mnOffset + nBytes) & 0x0F;
250 }
251 
252 // ============================================================================
253 
MSCodec_Std97()254 MSCodec_Std97::MSCodec_Std97 ()
255 {
256     m_hCipher = rtl_cipher_create (
257         rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream);
258     OSL_ASSERT(m_hCipher != 0);
259 
260     m_hDigest = rtl_digest_create (
261         rtl_Digest_AlgorithmMD5);
262     OSL_ASSERT(m_hDigest != 0);
263 
264     (void)memset (m_pDigestValue, 0, sizeof(m_pDigestValue));
265     (void)memset (m_pDocId, 0, sizeof(m_pDocId));
266 }
267 
~MSCodec_Std97()268 MSCodec_Std97::~MSCodec_Std97 ()
269 {
270     (void)memset (m_pDigestValue, 0, sizeof(m_pDigestValue));
271     (void)memset (m_pDocId, 0, sizeof(m_pDocId));
272     rtl_digest_destroy (m_hDigest);
273     rtl_cipher_destroy (m_hCipher);
274 }
275 
276 #if 0
277 #if DEBUG_MSO_ENCRYPTION_STD97
278 static void lcl_PrintKeyData(const sal_uInt8* pKeyData, const char* msg)
279 {
280     printf("pKeyData: (%s)\n", msg);
281     for (int j = 0; j < 4; ++j)
282     {
283         for (int i = 0; i < 16; ++i)
284             printf("%2.2x ", pKeyData[j*16+i]);
285         printf("\n");
286     }
287 }
288 #else
289 static void lcl_PrintKeyData(const sal_uInt8* /*pKeyData*/, const char* /*msg*/)
290 {
291 }
292 #endif
293 #endif
294 
295 #if DEBUG_MSO_ENCRYPTION_STD97
lcl_PrintDigest(const sal_uInt8 * pDigest,const char * msg)296 static void lcl_PrintDigest(const sal_uInt8* pDigest, const char* msg)
297 {
298     printf("digest: (%s)\n", msg);
299     for (int i = 0; i < 16; ++i)
300         printf("%2.2x ", pDigest[i]);
301     printf("\n");
302 }
303 #else
lcl_PrintDigest(const sal_uInt8 *,const char *)304 static void lcl_PrintDigest(const sal_uInt8* /*pDigest*/, const char* /*msg*/)
305 {
306 }
307 #endif
308 
InitCodec(const uno::Sequence<beans::NamedValue> & aData)309 sal_Bool MSCodec_Std97::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
310 {
311 #if DEBUG_MSO_ENCRYPTION_STD97
312     fprintf(stdout, "MSCodec_Std97::InitCodec: --begin\n");fflush(stdout);
313 #endif
314     sal_Bool bResult = sal_False;
315 
316 	::comphelper::SequenceAsHashMap aHashData( aData );
317     uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "STD97EncryptionKey" ) ), uno::Sequence< sal_Int8 >() );
318 
319     if ( aKey.getLength() == RTL_DIGEST_LENGTH_MD5 )
320     {
321         (void)memcpy( m_pDigestValue, aKey.getConstArray(), RTL_DIGEST_LENGTH_MD5 );
322         uno::Sequence< sal_Int8 > aUniqueID = aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "STD97UniqueID" ) ), uno::Sequence< sal_Int8 >() );
323         if ( aUniqueID.getLength() == 16 )
324         {
325             (void)memcpy( m_pDocId, aUniqueID.getConstArray(), 16 );
326             bResult = sal_True;
327             lcl_PrintDigest(m_pDigestValue, "digest value");
328             lcl_PrintDigest(m_pDocId, "DocId value");
329         }
330         else
331             OSL_ENSURE( sal_False, "Unexpected document ID!\n" );
332     }
333     else
334         OSL_ENSURE( sal_False, "Unexpected key size!\n" );
335 
336     return bResult;
337 }
338 
GetEncryptionData()339 uno::Sequence< beans::NamedValue > MSCodec_Std97::GetEncryptionData()
340 {
341     ::comphelper::SequenceAsHashMap aHashData;
342     aHashData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "STD97EncryptionKey" ) ) ] <<= uno::Sequence< sal_Int8 >( (sal_Int8*)m_pDigestValue, RTL_DIGEST_LENGTH_MD5 );
343     aHashData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "STD97UniqueID" ) ) ] <<= uno::Sequence< sal_Int8 >( (sal_Int8*)m_pDocId, 16 );
344 
345     return aHashData.getAsConstNamedValueList();
346 }
347 
InitKey(const sal_uInt16 pPassData[16],const sal_uInt8 pDocId[16])348 void MSCodec_Std97::InitKey (
349     const sal_uInt16 pPassData[16],
350     const sal_uInt8  pDocId[16])
351 {
352 #if DEBUG_MSO_ENCRYPTION_STD97
353     fprintf(stdout, "MSCodec_Std97::InitKey: --begin\n");fflush(stdout);
354 #endif
355     uno::Sequence< sal_Int8 > aKey = ::comphelper::DocPasswordHelper::GenerateStd97Key( pPassData, uno::Sequence< sal_Int8 >( (sal_Int8*)pDocId, 16 ) );
356     // Fill raw digest of above updates into DigestValue.
357 
358     if ( aKey.getLength() == sizeof(m_pDigestValue) )
359         (void)memcpy ( m_pDigestValue, aKey.getConstArray(), sizeof(m_pDigestValue) );
360     else
361         memset( m_pDigestValue, 0, sizeof(m_pDigestValue) );
362 
363     lcl_PrintDigest(m_pDigestValue, "digest value");
364 
365     (void)memcpy (m_pDocId, pDocId, 16);
366 
367     lcl_PrintDigest(m_pDocId, "DocId value");
368 }
369 
VerifyKey(const sal_uInt8 pSaltData[16],const sal_uInt8 pSaltDigest[16])370 bool MSCodec_Std97::VerifyKey (
371     const sal_uInt8 pSaltData[16],
372     const sal_uInt8 pSaltDigest[16])
373 {
374     // both the salt data and salt digest (hash) come from the document being imported.
375 
376 #if DEBUG_MSO_ENCRYPTION_STD97
377     fprintf(stdout, "MSCodec_Std97::VerifyKey: \n");
378     lcl_PrintDigest(pSaltData, "salt data");
379     lcl_PrintDigest(pSaltDigest, "salt hash");
380 #endif
381     bool result = false;
382 
383     if (InitCipher(0))
384     {
385         sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
386         GetDigestFromSalt(pSaltData, pDigest);
387 
388         sal_uInt8 pBuffer[16];
389         // Decode original SaltDigest into Buffer.
390         rtl_cipher_decode (
391             m_hCipher, pSaltDigest, 16, pBuffer, sizeof(pBuffer));
392 
393         // Compare Buffer with computed Digest.
394         result = (memcmp (pBuffer, pDigest, sizeof(pDigest)) == 0);
395 
396         // Erase Buffer and Digest arrays.
397         (void)memset (pBuffer, 0, sizeof(pBuffer));
398         (void)memset (pDigest, 0, sizeof(pDigest));
399     }
400 
401     return (result);
402 }
403 
InitCipher(sal_uInt32 nCounter)404 bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter)
405 {
406     rtlCipherError result;
407     sal_uInt8      pKeyData[64]; // 512-bit message block
408 
409     // Initialize KeyData array.
410     (void)memset (pKeyData, 0, sizeof(pKeyData));
411 
412     // Fill 40 bit of DigestValue into [0..4].
413     (void)memcpy (pKeyData, m_pDigestValue, 5);
414 
415     // Fill counter into [5..8].
416     pKeyData[ 5] = sal_uInt8((nCounter >>  0) & 0xff);
417     pKeyData[ 6] = sal_uInt8((nCounter >>  8) & 0xff);
418     pKeyData[ 7] = sal_uInt8((nCounter >> 16) & 0xff);
419     pKeyData[ 8] = sal_uInt8((nCounter >> 24) & 0xff);
420 
421     pKeyData[ 9] = 0x80;
422     pKeyData[56] = 0x48;
423 
424     // Fill raw digest of KeyData into KeyData.
425     (void)rtl_digest_updateMD5 (
426         m_hDigest, pKeyData, sizeof(pKeyData));
427     (void)rtl_digest_rawMD5 (
428         m_hDigest, pKeyData, RTL_DIGEST_LENGTH_MD5);
429 
430     // Initialize Cipher with KeyData (for decoding).
431     result = rtl_cipher_init (
432         m_hCipher, rtl_Cipher_DirectionBoth,
433         pKeyData, RTL_DIGEST_LENGTH_MD5, 0, 0);
434 
435     // Erase KeyData array and leave.
436     (void)memset (pKeyData, 0, sizeof(pKeyData));
437 
438     return (result == rtl_Cipher_E_None);
439 }
440 
CreateSaltDigest(const sal_uInt8 nSaltData[16],sal_uInt8 nSaltDigest[16])441 bool MSCodec_Std97::CreateSaltDigest( const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] )
442 {
443 #if DEBUG_MSO_ENCRYPTION_STD97
444     lcl_PrintDigest(nSaltData, "salt data");
445 #endif
446     bool result = false;
447 
448     if (InitCipher(0))
449     {
450         sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
451         GetDigestFromSalt(nSaltData, pDigest);
452 
453         rtl_cipher_decode (
454             m_hCipher, pDigest, 16, pDigest, sizeof(pDigest));
455 
456         (void)memcpy(nSaltDigest, pDigest, 16);
457     }
458 
459     return (result);
460 }
461 
Encode(const void * pData,sal_Size nDatLen,sal_uInt8 * pBuffer,sal_Size nBufLen)462 bool MSCodec_Std97::Encode (
463     const void *pData,   sal_Size nDatLen,
464     sal_uInt8  *pBuffer, sal_Size nBufLen)
465 {
466     rtlCipherError result;
467 
468     result = rtl_cipher_encode (
469         m_hCipher, pData, nDatLen, pBuffer, nBufLen);
470 
471     return (result == rtl_Cipher_E_None);
472 }
473 
Decode(const void * pData,sal_Size nDatLen,sal_uInt8 * pBuffer,sal_Size nBufLen)474 bool MSCodec_Std97::Decode (
475     const void *pData,   sal_Size nDatLen,
476     sal_uInt8  *pBuffer, sal_Size nBufLen)
477 {
478     rtlCipherError result;
479 
480     result = rtl_cipher_decode (
481         m_hCipher, pData, nDatLen, pBuffer, nBufLen);
482 
483     return (result == rtl_Cipher_E_None);
484 }
485 
Skip(sal_Size nDatLen)486 bool MSCodec_Std97::Skip( sal_Size nDatLen )
487 {
488     sal_uInt8 pnDummy[ 1024 ];
489     sal_Size nDatLeft = nDatLen;
490     bool bResult = true;
491 
492     while (bResult && nDatLeft)
493     {
494         sal_Size nBlockLen = ::std::min< sal_Size >( nDatLeft, sizeof(pnDummy) );
495         bResult = Decode( pnDummy, nBlockLen, pnDummy, nBlockLen );
496         nDatLeft -= nBlockLen;
497     }
498 
499     return bResult;
500 }
501 
GetDigestFromSalt(const sal_uInt8 pSaltData[16],sal_uInt8 pDigest[16])502 void MSCodec_Std97::GetDigestFromSalt( const sal_uInt8 pSaltData[16], sal_uInt8 pDigest[16] )
503 {
504     sal_uInt8 pBuffer[64];
505     sal_uInt8 pDigestLocal[16];
506 
507     // Decode SaltData into Buffer.
508     rtl_cipher_decode (
509         m_hCipher, pSaltData, 16, pBuffer, sizeof(pBuffer));
510 
511     // set the 129th bit to make the buffer 128-bit in length.
512     pBuffer[16] = 0x80;
513 
514     // erase the rest of the buffer with zeros.
515     (void)memset (pBuffer + 17, 0, sizeof(pBuffer) - 17);
516 
517     // set the 441st bit.
518     pBuffer[56] = 0x80;
519 
520     // Fill raw digest of Buffer into Digest.
521     rtl_digest_updateMD5 (
522         m_hDigest, pBuffer, sizeof(pBuffer));
523     rtl_digest_rawMD5 (
524         m_hDigest, pDigestLocal, sizeof(pDigestLocal));
525 
526     memcpy(pDigest, pDigestLocal, 16);
527 }
528 
GetEncryptKey(const sal_uInt8 pSalt[16],sal_uInt8 pSaltData[16],sal_uInt8 pSaltDigest[16])529 void MSCodec_Std97::GetEncryptKey (
530 	const sal_uInt8 pSalt[16],
531     sal_uInt8 pSaltData[16],
532     sal_uInt8 pSaltDigest[16])
533 {
534     if (InitCipher(0))
535     {
536         sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
537         sal_uInt8 pBuffer[64];
538 
539         rtl_cipher_encode (
540             m_hCipher, pSalt, 16, pSaltData, sizeof(pBuffer));
541 
542 		(void)memcpy( pBuffer, pSalt, 16 );
543 
544         pBuffer[16] = 0x80;
545         (void)memset (pBuffer + 17, 0, sizeof(pBuffer) - 17);
546         pBuffer[56] = 0x80;
547 
548         rtl_digest_updateMD5 (
549             m_hDigest, pBuffer, sizeof(pBuffer));
550         rtl_digest_rawMD5 (
551             m_hDigest, pDigest, sizeof(pDigest));
552 
553         rtl_cipher_encode (
554             m_hCipher, pDigest, 16, pSaltDigest, 16);
555 
556         (void)memset (pBuffer, 0, sizeof(pBuffer));
557         (void)memset (pDigest, 0, sizeof(pDigest));
558     }
559 }
560 
GetDocId(sal_uInt8 pDocId[16])561 void MSCodec_Std97::GetDocId( sal_uInt8 pDocId[16] )
562 {
563     if ( sizeof( m_pDocId ) == 16 )
564         (void)memcpy( pDocId, m_pDocId, 16 );
565 }
566 
567 // ============================================================================
568 
569 } // namespace svx
570 
571