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