LibreOffice Module package (master) 1
ZipFile.cxx
Go to the documentation of this file.
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 <com/sun/star/io/BufferSizeExceededException.hpp>
21#include <com/sun/star/io/NotConnectedException.hpp>
22#include <com/sun/star/lang/IllegalArgumentException.hpp>
23#include <com/sun/star/packages/NoEncryptionException.hpp>
24#include <com/sun/star/packages/WrongPasswordException.hpp>
25#include <com/sun/star/packages/zip/ZipConstants.hpp>
26#include <com/sun/star/packages/zip/ZipException.hpp>
27#include <com/sun/star/packages/zip/ZipIOException.hpp>
28#include <com/sun/star/xml/crypto/XCipherContext.hpp>
29#include <com/sun/star/xml/crypto/XDigestContext.hpp>
30#include <com/sun/star/xml/crypto/CipherID.hpp>
31#include <com/sun/star/xml/crypto/DigestID.hpp>
32#include <com/sun/star/xml/crypto/NSSInitializer.hpp>
33
37#include <rtl/digest.h>
38#include <sal/log.hxx>
39#include <o3tl/safeint.hxx>
40#include <osl/diagnose.h>
41
42#include <algorithm>
43#include <iterator>
44#include <utility>
45#include <vector>
46
47#include "blowfishcontext.hxx"
48#include "sha1context.hxx"
49#include <ZipFile.hxx>
50#include <ZipEnumeration.hxx>
51#include "XUnbufferedStream.hxx"
53#include <PackageConstants.hxx>
55#include <EncryptionData.hxx>
56#include "MemoryByteGrabber.hxx"
57
58#include <CRC32.hxx>
59
60using namespace com::sun::star;
61using namespace com::sun::star::io;
62using namespace com::sun::star::uno;
63using namespace com::sun::star::lang;
64using namespace com::sun::star::packages;
65using namespace com::sun::star::packages::zip;
66using namespace com::sun::star::packages::zip::ZipConstants;
67
69
70#if OSL_DEBUG_LEVEL > 0
71#define THROW_WHERE SAL_WHERE
72#else
73#define THROW_WHERE ""
74#endif
75
79 uno::Reference < XInputStream > const &xInput,
80 uno::Reference < XComponentContext > xContext,
81 bool bInitialise )
82: m_aMutexHolder(std::move( aMutexHolder ))
83, aGrabber( xInput )
84, aInflater( true )
85, xStream(xInput)
86, m_xContext (std::move( xContext ))
87, bRecoveryMode( false )
88{
89 if (bInitialise && readCEN() == -1 )
90 {
91 aEntries.clear();
92 throw ZipException( "stream data looks to be broken" );
93 }
94}
95
97 uno::Reference < XInputStream > const &xInput,
98 uno::Reference < XComponentContext > xContext,
99 bool bInitialise, bool bForceRecovery)
100: m_aMutexHolder(std::move( aMutexHolder ))
101, aGrabber( xInput )
102, aInflater( true )
103, xStream(xInput)
104, m_xContext (std::move( xContext ))
105, bRecoveryMode( bForceRecovery )
106{
107 if (bInitialise)
108 {
109 if ( bForceRecovery )
110 {
111 recover();
112 }
113 else if ( readCEN() == -1 )
114 {
115 aEntries.clear();
116 throw ZipException("stream data looks to be broken" );
117 }
118 }
119}
120
122{
123 aEntries.clear();
124}
125
126void ZipFile::setInputStream ( const uno::Reference < XInputStream >& xNewStream )
127{
128 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
129
130 xStream = xNewStream;
131 aGrabber.setInputStream ( xStream );
132}
133
134uno::Reference< xml::crypto::XDigestContext > ZipFile::StaticGetDigestContextForChecksum( const uno::Reference< uno::XComponentContext >& xArgContext, const ::rtl::Reference< EncryptionData >& xEncryptionData )
135{
136 uno::Reference< xml::crypto::XDigestContext > xDigestContext;
137 if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA256_1K )
138 {
139 uno::Reference< uno::XComponentContext > xContext = xArgContext;
140 if ( !xContext.is() )
142
143 uno::Reference< xml::crypto::XNSSInitializer > xDigestContextSupplier = xml::crypto::NSSInitializer::create( xContext );
144
145 xDigestContext.set( xDigestContextSupplier->getDigestContext( xEncryptionData->m_nCheckAlg, uno::Sequence< beans::NamedValue >() ), uno::UNO_SET_THROW );
146 }
147 else if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA1_1K )
148 {
149 if (xEncryptionData->m_bTryWrongSHA1)
150 {
151 xDigestContext.set(StarOfficeSHA1DigestContext::Create(), uno::UNO_SET_THROW);
152 }
153 else
154 {
155 xDigestContext.set(CorrectSHA1DigestContext::Create(), uno::UNO_SET_THROW);
156 }
157 }
158
159 return xDigestContext;
160}
161
162uno::Reference< xml::crypto::XCipherContext > ZipFile::StaticGetCipher( const uno::Reference< uno::XComponentContext >& xArgContext, const ::rtl::Reference< EncryptionData >& xEncryptionData, bool bEncrypt )
163{
164 uno::Reference< xml::crypto::XCipherContext > xResult;
165
166 if (xEncryptionData->m_nDerivedKeySize < 0)
167 {
168 throw ZipIOException("Invalid derived key length!" );
169 }
170
171 uno::Sequence< sal_Int8 > aDerivedKey( xEncryptionData->m_nDerivedKeySize );
172 if ( !xEncryptionData->m_nIterationCount &&
173 xEncryptionData->m_nDerivedKeySize == xEncryptionData->m_aKey.getLength() )
174 {
175 // gpg4libre: no need to derive key, m_aKey is already
176 // usable as symmetric session key
177 aDerivedKey = xEncryptionData->m_aKey;
178 }
179 else if ( rtl_Digest_E_None != rtl_digest_PBKDF2( reinterpret_cast< sal_uInt8* >( aDerivedKey.getArray() ),
180 aDerivedKey.getLength(),
181 reinterpret_cast< const sal_uInt8 * > (xEncryptionData->m_aKey.getConstArray() ),
182 xEncryptionData->m_aKey.getLength(),
183 reinterpret_cast< const sal_uInt8 * > ( xEncryptionData->m_aSalt.getConstArray() ),
184 xEncryptionData->m_aSalt.getLength(),
185 xEncryptionData->m_nIterationCount ) )
186 {
187 throw ZipIOException("Can not create derived key!" );
188 }
189
190 if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::AES_CBC_W3C_PADDING )
191 {
192 uno::Reference< uno::XComponentContext > xContext = xArgContext;
193 if ( !xContext.is() )
195
196 uno::Reference< xml::crypto::XNSSInitializer > xCipherContextSupplier = xml::crypto::NSSInitializer::create( xContext );
197
198 xResult = xCipherContextSupplier->getCipherContext( xEncryptionData->m_nEncAlg, aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt, uno::Sequence< beans::NamedValue >() );
199 }
200 else if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::BLOWFISH_CFB_8 )
201 {
202 xResult = BlowfishCFB8CipherContext::Create( aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt );
203 }
204 else
205 {
206 throw ZipIOException("Unknown cipher algorithm is requested!" );
207 }
208
209 return xResult;
210}
211
212void ZipFile::StaticFillHeader( const ::rtl::Reference< EncryptionData >& rData,
213 sal_Int64 nSize,
214 const OUString& aMediaType,
215 sal_Int8 * & pHeader )
216{
217 // I think it's safe to restrict vector and salt length to 2 bytes !
218 sal_Int16 nIVLength = static_cast < sal_Int16 > ( rData->m_aInitVector.getLength() );
219 sal_Int16 nSaltLength = static_cast < sal_Int16 > ( rData->m_aSalt.getLength() );
220 sal_Int16 nDigestLength = static_cast < sal_Int16 > ( rData->m_aDigest.getLength() );
221 sal_Int16 nMediaTypeLength = static_cast < sal_Int16 > ( aMediaType.getLength() * sizeof( sal_Unicode ) );
222
223 // First the header
224 *(pHeader++) = ( n_ConstHeader >> 0 ) & 0xFF;
225 *(pHeader++) = ( n_ConstHeader >> 8 ) & 0xFF;
226 *(pHeader++) = ( n_ConstHeader >> 16 ) & 0xFF;
227 *(pHeader++) = ( n_ConstHeader >> 24 ) & 0xFF;
228
229 // Then the version
230 *(pHeader++) = ( n_ConstCurrentVersion >> 0 ) & 0xFF;
231 *(pHeader++) = ( n_ConstCurrentVersion >> 8 ) & 0xFF;
232
233 // Then the iteration Count
234 sal_Int32 nIterationCount = rData->m_nIterationCount;
235 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 0 ) & 0xFF);
236 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 8 ) & 0xFF);
237 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 16 ) & 0xFF);
238 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 24 ) & 0xFF);
239
240 // FIXME64: need to handle larger sizes
241 // Then the size:
242 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 0 ) & 0xFF);
243 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 8 ) & 0xFF);
244 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 16 ) & 0xFF);
245 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 24 ) & 0xFF);
246
247 // Then the encryption algorithm
248 sal_Int32 nEncAlgID = rData->m_nEncAlg;
249 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 0 ) & 0xFF);
250 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 8 ) & 0xFF);
251 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 16 ) & 0xFF);
252 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 24 ) & 0xFF);
253
254 // Then the checksum algorithm
255 sal_Int32 nChecksumAlgID = rData->m_nCheckAlg;
256 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 0 ) & 0xFF);
257 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 8 ) & 0xFF);
258 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 16 ) & 0xFF);
259 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 24 ) & 0xFF);
260
261 // Then the derived key size
262 sal_Int32 nDerivedKeySize = rData->m_nDerivedKeySize;
263 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 0 ) & 0xFF);
264 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 8 ) & 0xFF);
265 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 16 ) & 0xFF);
266 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 24 ) & 0xFF);
267
268 // Then the start key generation algorithm
269 sal_Int32 nKeyAlgID = rData->m_nStartKeyGenID;
270 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 0 ) & 0xFF);
271 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 8 ) & 0xFF);
272 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 16 ) & 0xFF);
273 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 24 ) & 0xFF);
274
275 // Then the salt length
276 *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 0 ) & 0xFF);
277 *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 8 ) & 0xFF);
278
279 // Then the IV length
280 *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 0 ) & 0xFF);
281 *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 8 ) & 0xFF);
282
283 // Then the digest length
284 *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 0 ) & 0xFF);
285 *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 8 ) & 0xFF);
286
287 // Then the mediatype length
288 *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 0 ) & 0xFF);
289 *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 8 ) & 0xFF);
290
291 // Then the salt content
292 memcpy ( pHeader, rData->m_aSalt.getConstArray(), nSaltLength );
293 pHeader += nSaltLength;
294
295 // Then the IV content
296 memcpy ( pHeader, rData->m_aInitVector.getConstArray(), nIVLength );
297 pHeader += nIVLength;
298
299 // Then the digest content
300 memcpy ( pHeader, rData->m_aDigest.getConstArray(), nDigestLength );
301 pHeader += nDigestLength;
302
303 // Then the mediatype itself
304 memcpy ( pHeader, aMediaType.getStr(), nMediaTypeLength );
305 pHeader += nMediaTypeLength;
306}
307
308bool ZipFile::StaticFillData ( ::rtl::Reference< BaseEncryptionData > const & rData,
309 sal_Int32 &rEncAlg,
310 sal_Int32 &rChecksumAlg,
311 sal_Int32 &rDerivedKeySize,
312 sal_Int32 &rStartKeyGenID,
313 sal_Int32 &rSize,
314 OUString& aMediaType,
315 const uno::Reference< XInputStream >& rStream )
316{
317 bool bOk = false;
318 const sal_Int32 nHeaderSize = n_ConstHeaderSize - 4;
319 Sequence < sal_Int8 > aBuffer ( nHeaderSize );
320 if ( nHeaderSize == rStream->readBytes ( aBuffer, nHeaderSize ) )
321 {
322 sal_Int16 nPos = 0;
323 sal_Int8 *pBuffer = aBuffer.getArray();
324 sal_Int16 nVersion = pBuffer[nPos++] & 0xFF;
325 nVersion |= ( pBuffer[nPos++] & 0xFF ) << 8;
326 if ( nVersion == n_ConstCurrentVersion )
327 {
328 sal_Int32 nCount = pBuffer[nPos++] & 0xFF;
329 nCount |= ( pBuffer[nPos++] & 0xFF ) << 8;
330 nCount |= ( pBuffer[nPos++] & 0xFF ) << 16;
331 nCount |= ( pBuffer[nPos++] & 0xFF ) << 24;
332 rData->m_nIterationCount = nCount;
333
334 rSize = pBuffer[nPos++] & 0xFF;
335 rSize |= ( pBuffer[nPos++] & 0xFF ) << 8;
336 rSize |= ( pBuffer[nPos++] & 0xFF ) << 16;
337 rSize |= ( pBuffer[nPos++] & 0xFF ) << 24;
338
339 rEncAlg = pBuffer[nPos++] & 0xFF;
340 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 8;
341 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 16;
342 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 24;
343
344 rChecksumAlg = pBuffer[nPos++] & 0xFF;
345 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 8;
346 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 16;
347 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 24;
348
349 rDerivedKeySize = pBuffer[nPos++] & 0xFF;
350 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 8;
351 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 16;
352 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 24;
353
354 rStartKeyGenID = pBuffer[nPos++] & 0xFF;
355 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 8;
356 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 16;
357 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 24;
358
359 sal_Int16 nSaltLength = pBuffer[nPos++] & 0xFF;
360 nSaltLength |= ( pBuffer[nPos++] & 0xFF ) << 8;
361 sal_Int16 nIVLength = ( pBuffer[nPos++] & 0xFF );
362 nIVLength |= ( pBuffer[nPos++] & 0xFF ) << 8;
363 sal_Int16 nDigestLength = pBuffer[nPos++] & 0xFF;
364 nDigestLength |= ( pBuffer[nPos++] & 0xFF ) << 8;
365
366 sal_Int16 nMediaTypeLength = pBuffer[nPos++] & 0xFF;
367 nMediaTypeLength |= ( pBuffer[nPos++] & 0xFF ) << 8;
368
369 if ( nSaltLength == rStream->readBytes ( aBuffer, nSaltLength ) )
370 {
371 rData->m_aSalt.realloc ( nSaltLength );
372 memcpy ( rData->m_aSalt.getArray(), aBuffer.getConstArray(), nSaltLength );
373 if ( nIVLength == rStream->readBytes ( aBuffer, nIVLength ) )
374 {
375 rData->m_aInitVector.realloc ( nIVLength );
376 memcpy ( rData->m_aInitVector.getArray(), aBuffer.getConstArray(), nIVLength );
377 if ( nDigestLength == rStream->readBytes ( aBuffer, nDigestLength ) )
378 {
379 rData->m_aDigest.realloc ( nDigestLength );
380 memcpy ( rData->m_aDigest.getArray(), aBuffer.getConstArray(), nDigestLength );
381
382 if ( nMediaTypeLength == rStream->readBytes ( aBuffer, nMediaTypeLength ) )
383 {
384 aMediaType = OUString( reinterpret_cast<sal_Unicode const *>(aBuffer.getConstArray()),
385 nMediaTypeLength / sizeof( sal_Unicode ) );
386 bOk = true;
387 }
388 }
389 }
390 }
391 }
392 }
393 return bOk;
394}
395
396uno::Reference< XInputStream > ZipFile::StaticGetDataFromRawStream( const rtl::Reference< comphelper::RefCountedMutex >& aMutexHolder,
397 const uno::Reference< uno::XComponentContext >& rxContext,
398 const uno::Reference< XInputStream >& xStream,
399 const ::rtl::Reference< EncryptionData > &rData )
400{
401 if ( !rData.is() )
402 throw ZipIOException("Encrypted stream without encryption data!" );
403
404 if ( !rData->m_aKey.hasElements() )
405 throw packages::WrongPasswordException(THROW_WHERE );
406
407 uno::Reference< XSeekable > xSeek( xStream, UNO_QUERY );
408 if ( !xSeek.is() )
409 throw ZipIOException("The stream must be seekable!" );
410
411 // if we have a digest, then this file is an encrypted one and we should
412 // check if we can decrypt it or not
413 OSL_ENSURE( rData->m_aDigest.hasElements(), "Can't detect password correctness without digest!" );
414 if ( rData->m_aDigest.hasElements() )
415 {
416 sal_Int32 nSize = sal::static_int_cast< sal_Int32 >( xSeek->getLength() );
417 if ( nSize > n_ConstDigestLength + 32 )
418 nSize = n_ConstDigestLength + 32;
419
420 // skip header
421 xSeek->seek( n_ConstHeaderSize + rData->m_aInitVector.getLength() +
422 rData->m_aSalt.getLength() + rData->m_aDigest.getLength() );
423
424 // Only want to read enough to verify the digest
425 Sequence < sal_Int8 > aReadBuffer ( nSize );
426
427 xStream->readBytes( aReadBuffer, nSize );
428
429 if ( !StaticHasValidPassword( rxContext, aReadBuffer, rData ) )
430 throw packages::WrongPasswordException(THROW_WHERE );
431 }
432
433 return new XUnbufferedStream( aMutexHolder, xStream, rData );
434}
435
436#if 0
437// for debugging purposes
438void CheckSequence( const uno::Sequence< sal_Int8 >& aSequence )
439{
440 if ( aSequence.getLength() )
441 {
442 sal_Int32* pPointer = *( (sal_Int32**)&aSequence );
443 sal_Int32 nSize = *( pPointer + 1 );
444 sal_Int32 nMemSize = *( pPointer - 2 );
445 sal_Int32 nUsedMemSize = ( nSize + 4 * sizeof( sal_Int32 ) );
446 OSL_ENSURE( nSize == aSequence.getLength() && nUsedMemSize + 7 - ( nUsedMemSize - 1 ) % 8 == nMemSize, "Broken Sequence!" );
447 }
448}
449#endif
450
451bool ZipFile::StaticHasValidPassword( const uno::Reference< uno::XComponentContext >& rxContext, const Sequence< sal_Int8 > &aReadBuffer, const ::rtl::Reference< EncryptionData > &rData )
452{
453 if ( !rData.is() || !rData->m_aKey.hasElements() )
454 return false;
455
456 bool bRet = false;
457
458 uno::Reference< xml::crypto::XCipherContext > xCipher( StaticGetCipher( rxContext, rData, false ), uno::UNO_SET_THROW );
459
460 uno::Sequence< sal_Int8 > aDecryptBuffer;
461 uno::Sequence< sal_Int8 > aDecryptBuffer2;
462 try
463 {
464 aDecryptBuffer = xCipher->convertWithCipherContext( aReadBuffer );
465 aDecryptBuffer2 = xCipher->finalizeCipherContextAndDispose();
466 }
467 catch( uno::Exception& )
468 {
469 // decryption with padding will throw the exception in finalizing if the buffer represent only part of the stream
470 // it is no problem, actually this is why we read 32 additional bytes ( two of maximal possible encryption blocks )
471 }
472
473 if ( aDecryptBuffer2.hasElements() )
474 {
475 sal_Int32 nOldLen = aDecryptBuffer.getLength();
476 aDecryptBuffer.realloc( nOldLen + aDecryptBuffer2.getLength() );
477 memcpy( aDecryptBuffer.getArray() + nOldLen, aDecryptBuffer2.getConstArray(), aDecryptBuffer2.getLength() );
478 }
479
480 if ( aDecryptBuffer.getLength() > n_ConstDigestLength )
481 aDecryptBuffer.realloc( n_ConstDigestLength );
482
483 uno::Sequence< sal_Int8 > aDigestSeq;
484 uno::Reference< xml::crypto::XDigestContext > xDigestContext( StaticGetDigestContextForChecksum( rxContext, rData ), uno::UNO_SET_THROW );
485
486 xDigestContext->updateDigest( aDecryptBuffer );
487 aDigestSeq = xDigestContext->finalizeDigestAndDispose();
488
489 // If we don't have a digest, then we have to assume that the password is correct
490 if ( rData->m_aDigest.hasElements() &&
491 ( aDigestSeq.getLength() != rData->m_aDigest.getLength() ||
492 0 != memcmp ( aDigestSeq.getConstArray(),
493 rData->m_aDigest.getConstArray(),
494 aDigestSeq.getLength() ) ) )
495 {
496 // We should probably tell the user that the password they entered was wrong
497 }
498 else
499 bRet = true;
500
501 return bRet;
502}
503
504bool ZipFile::hasValidPassword ( ZipEntry const & rEntry, const ::rtl::Reference< EncryptionData >& rData )
505{
506 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
507
508 bool bRet = false;
509 if ( rData.is() && rData->m_aKey.hasElements() )
510 {
511 css::uno::Reference < css::io::XSeekable > xSeek(xStream, UNO_QUERY_THROW);
512 xSeek->seek( rEntry.nOffset );
513 sal_Int64 nSize = rEntry.nMethod == DEFLATED ? rEntry.nCompressedSize : rEntry.nSize;
514
515 // Only want to read enough to verify the digest
516 if ( nSize > n_ConstDigestDecrypt )
517 nSize = n_ConstDigestDecrypt;
518
519 Sequence < sal_Int8 > aReadBuffer ( nSize );
520
521 xStream->readBytes( aReadBuffer, nSize );
522
523 bRet = StaticHasValidPassword( m_xContext, aReadBuffer, rData );
524 }
525
526 return bRet;
527}
528
529namespace {
530
531class XBufferedStream : public cppu::WeakImplHelper<css::io::XInputStream, css::io::XSeekable>
532{
533 std::vector<sal_Int8> maBytes;
534 size_t mnPos;
535
536 size_t remainingSize() const
537 {
538 return maBytes.size() - mnPos;
539 }
540
541 bool hasBytes() const
542 {
543 return mnPos < maBytes.size();
544 }
545
546public:
547 XBufferedStream( const uno::Reference<XInputStream>& xSrcStream ) : mnPos(0)
548 {
549 sal_Int32 nRemaining = xSrcStream->available();
550 maBytes.reserve(nRemaining);
551
552 if (auto pByteReader = dynamic_cast< comphelper::ByteReader* >( xSrcStream.get() ))
553 {
554 maBytes.resize(nRemaining);
555
556 sal_Int8* pData = maBytes.data();
557 while (nRemaining > 0)
558 {
559 sal_Int32 nRead = pByteReader->readSomeBytes(pData, nRemaining);
560 nRemaining -= nRead;
561 pData += nRead;
562 }
563 return;
564 }
565
566 const sal_Int32 nBufSize = 8192;
567 uno::Sequence<sal_Int8> aBuf(nBufSize);
568 while (nRemaining > 0)
569 {
570 const sal_Int32 nBytes = xSrcStream->readBytes(aBuf, std::min(nBufSize, nRemaining));
571 if (!nBytes)
572 break;
573 maBytes.insert(maBytes.end(), aBuf.begin(), aBuf.begin() + nBytes);
574 nRemaining -= nBytes;
575 }
576 }
577
578 virtual sal_Int32 SAL_CALL readBytes( uno::Sequence<sal_Int8>& rData, sal_Int32 nBytesToRead ) override
579 {
580 if (!hasBytes())
581 return 0;
582
583 sal_Int32 nReadSize = std::min<sal_Int32>(nBytesToRead, remainingSize());
584 rData.realloc(nReadSize);
585 auto pData = rData.getArray();
586 std::vector<sal_Int8>::const_iterator it = maBytes.cbegin();
587 std::advance(it, mnPos);
588 for (sal_Int32 i = 0; i < nReadSize; ++i, ++it)
589 pData[i] = *it;
590
591 mnPos += nReadSize;
592
593 return nReadSize;
594 }
595
596 virtual sal_Int32 SAL_CALL readSomeBytes( ::css::uno::Sequence<sal_Int8>& rData, sal_Int32 nMaxBytesToRead ) override
597 {
598 return readBytes(rData, nMaxBytesToRead);
599 }
600
601 virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override
602 {
603 if (!hasBytes())
604 return;
605
606 mnPos += nBytesToSkip;
607 }
608
609 virtual sal_Int32 SAL_CALL available() override
610 {
611 if (!hasBytes())
612 return 0;
613
614 return remainingSize();
615 }
616
617 virtual void SAL_CALL closeInput() override
618 {
619 }
620 // XSeekable
621 virtual void SAL_CALL seek( sal_Int64 location ) override
622 {
623 if ( location < 0 || o3tl::make_unsigned(location) > maBytes.size() )
624 throw IllegalArgumentException(THROW_WHERE, uno::Reference< uno::XInterface >(), 1 );
625 mnPos = location;
626 }
627 virtual sal_Int64 SAL_CALL getPosition() override
628 {
629 return mnPos;
630 }
631 virtual sal_Int64 SAL_CALL getLength() override
632 {
633 return maBytes.size();
634 }
635};
636
637}
638
639uno::Reference< XInputStream > ZipFile::createStreamForZipEntry(
641 ZipEntry const & rEntry,
642 const ::rtl::Reference< EncryptionData > &rData,
643 sal_Int8 nStreamMode,
644 bool bIsEncrypted,
645 const bool bUseBufferedStream,
646 const OUString& aMediaType )
647{
648 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
649
651 m_xContext, aMutexHolder, rEntry, xStream, rData, nStreamMode, bIsEncrypted, aMediaType, bRecoveryMode);
652
653 if (!bUseBufferedStream)
654 return xSrcStream;
655
656 uno::Reference<io::XInputStream> xBufStream;
657#ifndef EMSCRIPTEN
658 static const sal_Int32 nThreadingThreshold = 10000;
659
660 if( xSrcStream->available() > nThreadingThreshold )
661 xBufStream = new XBufferedThreadedStream(xSrcStream, xSrcStream->getSize());
662 else
663#endif
664 xBufStream = new XBufferedStream(xSrcStream);
665
666 return xBufStream;
667}
668
669ZipEnumeration ZipFile::entries()
670{
671 return aEntries;
672}
673
674uno::Reference< XInputStream > ZipFile::getInputStream( ZipEntry& rEntry,
675 const ::rtl::Reference< EncryptionData > &rData,
676 bool bIsEncrypted,
678{
679 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
680
681 if ( rEntry.nOffset <= 0 )
682 readLOC( rEntry );
683
684 // We want to return a rawStream if we either don't have a key or if the
685 // key is wrong
686
687 bool bNeedRawStream = rEntry.nMethod == STORED;
688
689 // if we have a digest, then this file is an encrypted one and we should
690 // check if we can decrypt it or not
691 if ( bIsEncrypted && rData.is() && rData->m_aDigest.hasElements() )
692 bNeedRawStream = !hasValidPassword ( rEntry, rData );
693
694 return createStreamForZipEntry ( aMutexHolder,
695 rEntry,
696 rData,
697 bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
698 bIsEncrypted );
699}
700
701uno::Reference< XInputStream > ZipFile::getDataStream( ZipEntry& rEntry,
702 const ::rtl::Reference< EncryptionData > &rData,
703 bool bIsEncrypted,
705{
706 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
707
708 if ( rEntry.nOffset <= 0 )
709 readLOC( rEntry );
710
711 // An exception must be thrown in case stream is encrypted and
712 // there is no key or the key is wrong
713 bool bNeedRawStream = false;
714 if ( bIsEncrypted )
715 {
716 // in case no digest is provided there is no way
717 // to detect password correctness
718 if ( !rData.is() )
719 throw ZipException("Encrypted stream without encryption data!" );
720
721 // if we have a digest, then this file is an encrypted one and we should
722 // check if we can decrypt it or not
723 OSL_ENSURE( rData->m_aDigest.hasElements(), "Can't detect password correctness without digest!" );
724 if ( rData->m_aDigest.hasElements() && !hasValidPassword ( rEntry, rData ) )
725 throw packages::WrongPasswordException(THROW_WHERE );
726 }
727 else
728 bNeedRawStream = ( rEntry.nMethod == STORED );
729
730 return createStreamForZipEntry ( aMutexHolder,
731 rEntry,
732 rData,
733 bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
734 bIsEncrypted );
735}
736
737uno::Reference< XInputStream > ZipFile::getRawData( ZipEntry& rEntry,
738 const ::rtl::Reference< EncryptionData >& rData,
739 bool bIsEncrypted,
741 const bool bUseBufferedStream )
742{
743 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
744
745 if ( rEntry.nOffset <= 0 )
746 readLOC( rEntry );
747
748 return createStreamForZipEntry ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_RAW, bIsEncrypted, bUseBufferedStream );
749}
750
751uno::Reference< XInputStream > ZipFile::getWrappedRawStream(
752 ZipEntry& rEntry,
753 const ::rtl::Reference< EncryptionData >& rData,
754 const OUString& aMediaType,
756{
757 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
758
759 if ( !rData.is() )
760 throw packages::NoEncryptionException(THROW_WHERE );
761
762 if ( rEntry.nOffset <= 0 )
763 readLOC( rEntry );
764
765 return createStreamForZipEntry ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_WRAPPEDRAW, true, true, aMediaType );
766}
767
768void ZipFile::readLOC( ZipEntry &rEntry )
769{
770 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
771
772 sal_Int64 nPos = -rEntry.nOffset;
773
774 aGrabber.seek(nPos);
775 sal_Int32 nTestSig = aGrabber.ReadInt32();
776 if (nTestSig != LOCSIG)
777 throw ZipIOException("Invalid LOC header (bad signature)" );
778
779 // Ignore all (duplicated) information from the local file header.
780 // various programs produced "broken" zip files; even LO at some point.
781 // Just verify the path and calculate the data offset and otherwise
782 // rely on the central directory info.
783
784 aGrabber.ReadInt16(); //version
785 aGrabber.ReadInt16(); //flag
786 aGrabber.ReadInt16(); //how
787 aGrabber.ReadInt32(); //time
788 aGrabber.ReadInt32(); //crc
789 aGrabber.ReadInt32(); //compressed size
790 aGrabber.ReadInt32(); //size
791 sal_Int16 nPathLen = aGrabber.ReadInt16();
792 sal_Int16 nExtraLen = aGrabber.ReadInt16();
793
794 if (nPathLen < 0)
795 {
796 SAL_WARN("package", "bogus path len of: " << nPathLen);
797 nPathLen = 0;
798 }
799
800 rEntry.nOffset = aGrabber.getPosition() + nPathLen + nExtraLen;
801
802 bool bBroken = false;
803
804 try
805 {
806 // read always in UTF8, some tools seem not to set UTF8 bit
807 // coverity[tainted_data] - we've checked negative lens, and up to max short is ok here
808 uno::Sequence<sal_Int8> aNameBuffer(nPathLen);
809 sal_Int32 nRead = aGrabber.readBytes(aNameBuffer, nPathLen);
810 if (nRead < aNameBuffer.getLength())
811 aNameBuffer.realloc(nRead);
812
813 OUString sLOCPath( reinterpret_cast<const char *>(aNameBuffer.getConstArray()),
814 aNameBuffer.getLength(),
815 RTL_TEXTENCODING_UTF8 );
816
817 if ( rEntry.nPathLen == -1 ) // the file was created
818 {
819 rEntry.nPathLen = nPathLen;
820 rEntry.sPath = sLOCPath;
821 }
822
823 bBroken = rEntry.nPathLen != nPathLen
824 || rEntry.sPath != sLOCPath;
825 }
826 catch(...)
827 {
828 bBroken = true;
829 }
830
831 if ( bBroken && !bRecoveryMode )
832 throw ZipIOException("The stream seems to be broken!" );
833}
834
835sal_Int32 ZipFile::findEND()
836{
837 // this method is called in constructor only, no need for mutex
838 sal_Int32 nPos, nEnd;
840 try
841 {
842 sal_Int32 nLength = static_cast <sal_Int32 > (aGrabber.getLength());
843 if (nLength < ENDHDR)
844 return -1;
845 nPos = nLength - ENDHDR - ZIP_MAXNAMELEN;
846 nEnd = nPos >= 0 ? nPos : 0 ;
847
848 aGrabber.seek( nEnd );
849
850 auto nSize = nLength - nEnd;
851 if (nSize != aGrabber.readBytes(aBuffer, nSize))
852 throw ZipException("Zip END signature not found!" );
853
854 const sal_Int8 *pBuffer = aBuffer.getConstArray();
855
856 nPos = nSize - ENDHDR;
857 while ( nPos >= 0 )
858 {
859 if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 5 && pBuffer[nPos+3] == 6 )
860 return nPos + nEnd;
861 nPos--;
862 }
863 }
864 catch ( IllegalArgumentException& )
865 {
866 throw ZipException("Zip END signature not found!" );
867 }
868 catch ( NotConnectedException& )
869 {
870 throw ZipException("Zip END signature not found!" );
871 }
872 catch ( BufferSizeExceededException& )
873 {
874 throw ZipException("Zip END signature not found!" );
875 }
876 throw ZipException("Zip END signature not found!" );
877}
878
879sal_Int32 ZipFile::readCEN()
880{
881 // this method is called in constructor only, no need for mutex
882 sal_Int32 nCenPos = -1, nLocPos;
883 sal_uInt16 nCount;
884
885 try
886 {
887 sal_Int32 nEndPos = findEND();
888 if (nEndPos == -1)
889 return -1;
890 aGrabber.seek(nEndPos + ENDTOT);
891 sal_uInt16 nTotal = aGrabber.ReadUInt16();
892 sal_Int32 nCenLen = aGrabber.ReadInt32();
893 sal_Int32 nCenOff = aGrabber.ReadInt32();
894
895 if ( nTotal * CENHDR > nCenLen )
896 throw ZipException("invalid END header (bad entry count)" );
897
898 if ( nTotal > ZIP_MAXENTRIES )
899 throw ZipException("too many entries in ZIP File" );
900
901 if ( nCenLen < 0 || nCenLen > nEndPos )
902 throw ZipException("Invalid END header (bad central directory size)" );
903
904 nCenPos = nEndPos - nCenLen;
905
906 if ( nCenOff < 0 || nCenOff > nCenPos )
907 throw ZipException("Invalid END header (bad central directory size)" );
908
909 nLocPos = nCenPos - nCenOff;
910 aGrabber.seek( nCenPos );
911 Sequence < sal_Int8 > aCENBuffer ( nCenLen );
912 sal_Int64 nRead = aGrabber.readBytes ( aCENBuffer, nCenLen );
913 if ( static_cast < sal_Int64 > ( nCenLen ) != nRead )
914 throw ZipException ("Error reading CEN into memory buffer!" );
915
916 MemoryByteGrabber aMemGrabber(aCENBuffer);
917
918 ZipEntry aEntry;
919 sal_Int16 nCommentLen;
920
921 aEntries.reserve(nTotal);
922 for (nCount = 0 ; nCount < nTotal; nCount++)
923 {
924 sal_Int32 nTestSig = aMemGrabber.ReadInt32();
925 if ( nTestSig != CENSIG )
926 throw ZipException("Invalid CEN header (bad signature)" );
927
928 aMemGrabber.skipBytes ( 2 );
929 aEntry.nVersion = aMemGrabber.ReadInt16();
930 aEntry.nFlag = aMemGrabber.ReadInt16();
931
932 if ( ( aEntry.nFlag & 1 ) == 1 )
933 throw ZipException("Invalid CEN header (encrypted entry)" );
934
935 aEntry.nMethod = aMemGrabber.ReadInt16();
936
937 if ( aEntry.nMethod != STORED && aEntry.nMethod != DEFLATED)
938 throw ZipException("Invalid CEN header (bad compression method)" );
939
940 aEntry.nTime = aMemGrabber.ReadInt32();
941 aEntry.nCrc = aMemGrabber.ReadInt32();
942
943 sal_uInt64 nCompressedSize = aMemGrabber.ReadUInt32();
944 sal_uInt64 nSize = aMemGrabber.ReadUInt32();
945 aEntry.nPathLen = aMemGrabber.ReadInt16();
946 aEntry.nExtraLen = aMemGrabber.ReadInt16();
947 nCommentLen = aMemGrabber.ReadInt16();
948 aMemGrabber.skipBytes ( 8 );
949 sal_uInt64 nOffset = aMemGrabber.ReadUInt32();
950
951 if ( aEntry.nPathLen < 0 )
952 throw ZipException("unexpected name length" );
953
954 if ( nCommentLen < 0 )
955 throw ZipException("unexpected comment length" );
956
957 if ( aEntry.nExtraLen < 0 )
958 throw ZipException("unexpected extra header info length" );
959
960 if (aEntry.nPathLen > aMemGrabber.remainingSize())
961 throw ZipException("name too long");
962
963 // read always in UTF8, some tools seem not to set UTF8 bit
964 aEntry.sPath = OUString( reinterpret_cast<char const *>(aMemGrabber.getCurrentPos()),
965 aEntry.nPathLen,
966 RTL_TEXTENCODING_UTF8 );
967
969 throw ZipException("Zip entry has an invalid name." );
970
971 aMemGrabber.skipBytes(aEntry.nPathLen);
972
973 if (aEntry.nExtraLen>0)
974 {
975 readExtraFields(aMemGrabber, aEntry.nExtraLen, nSize, nCompressedSize, &nOffset);
976 }
977 aEntry.nCompressedSize = nCompressedSize;
978 aEntry.nSize = nSize;
979 aEntry.nOffset = nOffset;
980
981 aEntry.nOffset += nLocPos;
982 aEntry.nOffset *= -1;
983
984 aMemGrabber.skipBytes(nCommentLen);
985 aEntries[aEntry.sPath] = aEntry;
986 }
987
988 if (nCount != nTotal)
989 throw ZipException("Count != Total" );
990 }
991 catch ( IllegalArgumentException & )
992 {
993 // seek can throw this...
994 nCenPos = -1; // make sure we return -1 to indicate an error
995 }
996 return nCenPos;
997}
998
999void ZipFile::readExtraFields(MemoryByteGrabber& aMemGrabber, sal_Int16 nExtraLen,
1000 sal_uInt64& nSize, sal_uInt64& nCompressedSize, sal_uInt64* nOffset)
1001{
1002 while (nExtraLen > 0) // Extensible data fields
1003 {
1004 sal_Int16 nheaderID = aMemGrabber.ReadInt16();
1005 sal_uInt16 dataSize = aMemGrabber.ReadUInt16();
1006 if (nheaderID == 1) // Load Zip64 Extended Information Extra Field
1007 {
1008 // Datasize should be 28byte but some files have less (maybe non standard?)
1009 nSize = aMemGrabber.ReadUInt64();
1010 sal_uInt16 nReadSize = 8;
1011 if (dataSize >= 16)
1012 {
1013 nCompressedSize = aMemGrabber.ReadUInt64();
1014 nReadSize = 16;
1015 if (dataSize >= 24 && nOffset)
1016 {
1017 *nOffset = aMemGrabber.ReadUInt64();
1018 nReadSize = 24;
1019 // 4 byte should be "Disk Start Number" but we not need it
1020 }
1021 }
1022 if (dataSize > nReadSize)
1023 aMemGrabber.skipBytes(dataSize - nReadSize);
1024 }
1025 else
1026 {
1027 aMemGrabber.skipBytes(dataSize);
1028 }
1029 nExtraLen -= dataSize + 4;
1030 }
1031}
1032
1033void ZipFile::recover()
1034{
1035 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1036
1037 sal_Int64 nLength;
1039
1040 try
1041 {
1042 nLength = aGrabber.getLength();
1043 if (nLength < ENDHDR)
1044 return;
1045
1046 aGrabber.seek( 0 );
1047
1048 const sal_Int64 nToRead = 32000;
1049 for( sal_Int64 nGenPos = 0; aGrabber.readBytes( aBuffer, nToRead ) && aBuffer.getLength() > 16; )
1050 {
1051 const sal_Int8 *pBuffer = aBuffer.getConstArray();
1052 sal_Int32 nBufSize = aBuffer.getLength();
1053
1054 sal_Int64 nPos = 0;
1055 // the buffer should contain at least one header,
1056 // or if it is end of the file, at least the postheader with sizes and hash
1057 while( nPos < nBufSize - 30
1058 || ( nBufSize < nToRead && nPos < nBufSize - 16 ) )
1059
1060 {
1061 if ( nPos < nBufSize - 30 && pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 3 && pBuffer[nPos+3] == 4 )
1062 {
1063 //PK34: Local file header
1064 ZipEntry aEntry;
1065 Sequence<sal_Int8> aTmpBuffer(&(pBuffer[nPos+4]), 26);
1066 MemoryByteGrabber aMemGrabber(aTmpBuffer);
1067
1068 aEntry.nVersion = aMemGrabber.ReadInt16();
1069 aEntry.nFlag = aMemGrabber.ReadInt16();
1070
1071 if ( ( aEntry.nFlag & 1 ) != 1 )
1072 {
1073 aEntry.nMethod = aMemGrabber.ReadInt16();
1074
1075 if ( aEntry.nMethod == STORED || aEntry.nMethod == DEFLATED )
1076 {
1077 aEntry.nTime = aMemGrabber.ReadInt32();
1078 aEntry.nCrc = aMemGrabber.ReadInt32();
1079 sal_uInt64 nCompressedSize = aMemGrabber.ReadUInt32();
1080 sal_uInt64 nSize = aMemGrabber.ReadUInt32();
1081 aEntry.nPathLen = aMemGrabber.ReadInt16();
1082 aEntry.nExtraLen = aMemGrabber.ReadInt16();
1083
1084 sal_Int32 nDescrLength =
1085 ( aEntry.nMethod == DEFLATED && ( aEntry.nFlag & 8 ) ) ? 16 : 0;
1086
1087 sal_Int64 nBlockHeaderLength = aEntry.nPathLen + aEntry.nExtraLen + 30 + nDescrLength;
1088 if ( aEntry.nPathLen >= 0 && aEntry.nExtraLen >= 0
1089 && ( nGenPos + nPos + nBlockHeaderLength ) <= nLength )
1090 {
1091 // read always in UTF8, some tools seem not to set UTF8 bit
1092 if( nPos + 30 + aEntry.nPathLen <= nBufSize )
1093 aEntry.sPath = OUString ( reinterpret_cast<char const *>(&pBuffer[nPos + 30]),
1094 aEntry.nPathLen,
1095 RTL_TEXTENCODING_UTF8 );
1096 else
1097 {
1098 Sequence < sal_Int8 > aFileName;
1099 aGrabber.seek( nGenPos + nPos + 30 );
1100 aGrabber.readBytes( aFileName, aEntry.nPathLen );
1101 aEntry.sPath = OUString ( reinterpret_cast<const char *>(aFileName.getConstArray()),
1102 aFileName.getLength(),
1103 RTL_TEXTENCODING_UTF8 );
1104 aEntry.nPathLen = static_cast< sal_Int16 >(aFileName.getLength());
1105 }
1106
1107 // read 64bit header
1108 if (aEntry.nExtraLen > 0)
1109 {
1110 Sequence<sal_Int8> aExtraBuffer;
1111 if (nPos + 30 + aEntry.nPathLen + aEntry.nExtraLen <= nBufSize)
1112 {
1113 aExtraBuffer = Sequence<sal_Int8>(
1114 &(pBuffer[nPos + 30 + aEntry.nPathLen]),
1115 aEntry.nExtraLen);
1116 }
1117 else
1118 {
1119 aGrabber.seek(nGenPos + nPos + 30 + aEntry.nExtraLen);
1120 aGrabber.readBytes(aExtraBuffer, aEntry.nExtraLen);
1121 }
1122 MemoryByteGrabber aMemGrabberExtra(aExtraBuffer);
1123 if (aEntry.nExtraLen > 0)
1124 {
1125 readExtraFields(aMemGrabberExtra, aEntry.nExtraLen, nSize,
1126 nCompressedSize, nullptr);
1127 }
1128 }
1129
1130 sal_Int64 nDataSize = ( aEntry.nMethod == DEFLATED ) ? nCompressedSize : nSize;
1131 sal_Int64 nBlockLength = nDataSize + nBlockHeaderLength;
1132
1133 if (( nGenPos + nPos + nBlockLength ) <= nLength )
1134 {
1135 aEntry.nCompressedSize = nCompressedSize;
1136 aEntry.nSize = nSize;
1137
1138 aEntry.nOffset = nGenPos + nPos + 30 + aEntry.nPathLen + aEntry.nExtraLen;
1139
1140 if ( ( aEntry.nSize || aEntry.nCompressedSize ) && !checkSizeAndCRC( aEntry ) )
1141 {
1142 aEntry.nCrc = 0;
1143 aEntry.nCompressedSize = 0;
1144 aEntry.nSize = 0;
1145 }
1146
1147 aEntries.emplace( aEntry.sPath, aEntry );
1148 }
1149 }
1150 }
1151 }
1152
1153 nPos += 4;
1154 }
1155 else if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 7 && pBuffer[nPos+3] == 8 )
1156 {
1157 //PK78: Data descriptor
1158 sal_Int64 nCompressedSize, nSize;
1159 Sequence<sal_Int8> aTmpBuffer(&(pBuffer[nPos + 4]), 12 + 8 + 4);
1160 MemoryByteGrabber aMemGrabber(aTmpBuffer);
1161 sal_Int32 nCRC32 = aMemGrabber.ReadInt32();
1162
1163 // FIXME64: find a better way to recognize if Zip64 mode is used
1164 // Now we check if the memory at +16 byte seems to be a signature
1165 // if not, then probably Zip64 mode is used here, except
1166 // if memory at +24 byte seems not to be a signature.
1167 // Normally Data Descriptor should followed by the next Local File header
1168 // that should start with PK34, except for the last file, then it may
1169 // followed by Central directory that start with PK12, or
1170 // followed by "archive decryption header" that don't have a signature.
1171 if ((pBuffer[nPos + 16] == 'P' && pBuffer[nPos + 17] == 'K'
1172 && pBuffer[nPos + 19] == pBuffer[nPos + 18] + 1
1173 && (pBuffer[nPos + 18] == 3 || pBuffer[nPos + 18] == 1))
1174 || !(pBuffer[nPos + 24] == 'P' && pBuffer[nPos + 25] == 'K'
1175 && pBuffer[nPos + 27] == pBuffer[nPos + 26] + 1
1176 && (pBuffer[nPos + 26] == 3 || pBuffer[nPos + 26] == 1)))
1177 {
1178 nCompressedSize = aMemGrabber.ReadUInt32();
1179 nSize = aMemGrabber.ReadUInt32();
1180 }
1181 else
1182 {
1183 nCompressedSize = aMemGrabber.ReadUInt64();
1184 nSize = aMemGrabber.ReadUInt64();
1185 }
1186
1187 for( auto& rEntry : aEntries )
1188 {
1189 // this is a broken package, accept this block not only for DEFLATED streams
1190 if( rEntry.second.nFlag & 8 )
1191 {
1192 sal_Int64 nStreamOffset = nGenPos + nPos - nCompressedSize;
1193 if ( nStreamOffset == rEntry.second.nOffset && nCompressedSize > rEntry.second.nCompressedSize )
1194 {
1195 // only DEFLATED blocks need to be checked
1196 bool bAcceptBlock = ( rEntry.second.nMethod == STORED && nCompressedSize == nSize );
1197
1198 if ( !bAcceptBlock )
1199 {
1200 sal_Int64 nRealSize = 0;
1201 sal_Int32 nRealCRC = 0;
1202 getSizeAndCRC( nStreamOffset, nCompressedSize, &nRealSize, &nRealCRC );
1203 bAcceptBlock = ( nRealSize == nSize && nRealCRC == nCRC32 );
1204 }
1205
1206 if ( bAcceptBlock )
1207 {
1208 rEntry.second.nCrc = nCRC32;
1209 rEntry.second.nCompressedSize = nCompressedSize;
1210 rEntry.second.nSize = nSize;
1211 }
1212 }
1213#if 0
1214// for now ignore clearly broken streams
1215 else if( !rEntry.second.nCompressedSize )
1216 {
1217 rEntry.second.nCrc = nCRC32;
1218 sal_Int32 nRealStreamSize = nGenPos + nPos - rEntry.second.nOffset;
1219 rEntry.second.nCompressedSize = nRealStreamSize;
1220 rEntry.second.nSize = nSize;
1221 }
1222#endif
1223 }
1224 }
1225
1226 nPos += 4;
1227 }
1228 else
1229 nPos++;
1230 }
1231
1232 nGenPos += nPos;
1233 aGrabber.seek( nGenPos );
1234 }
1235 }
1236 catch ( IllegalArgumentException& )
1237 {
1238 throw ZipException("Zip END signature not found!" );
1239 }
1240 catch ( NotConnectedException& )
1241 {
1242 throw ZipException("Zip END signature not found!" );
1243 }
1244 catch ( BufferSizeExceededException& )
1245 {
1246 throw ZipException("Zip END signature not found!" );
1247 }
1248}
1249
1250bool ZipFile::checkSizeAndCRC( const ZipEntry& aEntry )
1251{
1252 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1253
1254 sal_Int32 nCRC = 0;
1255 sal_Int64 nSize = 0;
1256
1257 if( aEntry.nMethod == STORED )
1258 return ( getCRC( aEntry.nOffset, aEntry.nSize ) == aEntry.nCrc );
1259
1260 if (aEntry.nCompressedSize < 0)
1261 {
1262 SAL_WARN("package", "bogus compressed size of: " << aEntry.nCompressedSize);
1263 return false;
1264 }
1265
1266 getSizeAndCRC( aEntry.nOffset, aEntry.nCompressedSize, &nSize, &nCRC );
1267 return ( aEntry.nSize == nSize && aEntry.nCrc == nCRC );
1268}
1269
1270sal_Int32 ZipFile::getCRC( sal_Int64 nOffset, sal_Int64 nSize )
1271{
1272 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1273
1275 CRC32 aCRC;
1276 sal_Int64 nBlockSize = ::std::min(nSize, static_cast< sal_Int64 >(32000));
1277
1278 aGrabber.seek( nOffset );
1279 for (sal_Int64 ind = 0;
1280 aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nSize;
1281 ++ind)
1282 {
1283 sal_Int64 nLen = ::std::min(nBlockSize, nSize - ind * nBlockSize);
1284 aCRC.updateSegment(aBuffer, static_cast<sal_Int32>(nLen));
1285 }
1286
1287 return aCRC.getValue();
1288}
1289
1290void ZipFile::getSizeAndCRC( sal_Int64 nOffset, sal_Int64 nCompressedSize, sal_Int64 *nSize, sal_Int32 *nCRC )
1291{
1292 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1293
1295 CRC32 aCRC;
1296 sal_Int64 nRealSize = 0;
1297 Inflater aInflaterLocal( true );
1298 sal_Int32 nBlockSize = static_cast< sal_Int32 > (::std::min( nCompressedSize, static_cast< sal_Int64 >( 32000 ) ) );
1299
1300 aGrabber.seek( nOffset );
1301 for ( sal_Int64 ind = 0;
1302 !aInflaterLocal.finished() && aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nCompressedSize;
1303 ind++ )
1304 {
1305 Sequence < sal_Int8 > aData( nBlockSize );
1306 sal_Int32 nLastInflated = 0;
1307 sal_Int64 nInBlock = 0;
1308
1309 aInflaterLocal.setInput( aBuffer );
1310 do
1311 {
1312 nLastInflated = aInflaterLocal.doInflateSegment( aData, 0, nBlockSize );
1313 aCRC.updateSegment( aData, nLastInflated );
1314 nInBlock += nLastInflated;
1315 } while( !aInflater.finished() && nLastInflated );
1316
1317 nRealSize += nInBlock;
1318 }
1319
1320 *nSize = nRealSize;
1321 *nCRC = aCRC.getValue();
1322}
1323
1324/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const sal_Int32 n_ConstHeaderSize
const sal_Int16 n_ConstCurrentVersion
const sal_uInt32 n_ConstHeader
Reference< XComponentContext > m_xContext
const sal_Int32 n_ConstDigestDecrypt
const sal_Int32 n_ConstDigestLength
Reference< XInputStream > xStream
#define UNBUFF_STREAM_RAW
#define UNBUFF_STREAM_DATA
#define UNBUFF_STREAM_WRAPPEDRAW
#define THROW_WHERE
Definition: ZipFile.cxx:71
#define ZIP_MAXNAMELEN
Definition: ZipFile.hxx:46
#define ZIP_MAXENTRIES
Definition: ZipFile.hxx:47
static css::uno::Reference< css::xml::crypto::XCipherContext > Create(const css::uno::Sequence< sal_Int8 > &aDerivedKey, const css::uno::Sequence< sal_Int8 > &aInitVector, bool bEncrypt)
sal_Int64 getLength()
Definition: ByteGrabber.cxx:85
void seek(sal_Int64 location)
Definition: ByteGrabber.cxx:67
sal_Int16 ReadInt16()
Definition: ByteGrabber.hxx:64
void setInputStream(const css::uno::Reference< css::io::XInputStream > &xNewStream)
Definition: ByteGrabber.cxx:51
sal_Int32 ReadInt32()
Definition: ByteGrabber.hxx:68
sal_Int64 getPosition()
Definition: ByteGrabber.cxx:76
sal_Int32 readBytes(css::uno::Sequence< sal_Int8 > &aData, sal_Int32 nBytesToRead)
Definition: ByteGrabber.cxx:59
sal_uInt16 ReadUInt16()
Definition: ByteGrabber.cxx:94
Definition: CRC32.hxx:29
sal_Int32 getValue() const
Definition: CRC32.cxx:39
void updateSegment(const css::uno::Sequence< sal_Int8 > &b, sal_Int32 len)
Update CRC32 with specified sequence of bytes.
Definition: CRC32.cxx:45
static css::uno::Reference< css::xml::crypto::XDigestContext > Create()
Definition: sha1context.cxx:86
void skipBytes(sal_Int32 nBytesToSkip)
static css::uno::Reference< css::xml::crypto::XDigestContext > Create()
Definition: sha1context.cxx:31
~ZipFile()
Definition: ZipFile.cxx:121
ZipFile(const Filepath_t &FileName)
bool finished() const
Definition: Inflater.hxx:46
static bool IsValidZipEntryFileName(std::u16string_view aName, bool bSlashAllowed)
int nCount
ScXMLEditAttributeMap::Entry const aEntries[]
sal_Int16 nVersion
sal_uInt16 nPos
#define SAL_WARN(area, stream)
aBuf
std::unique_ptr< sal_Int32[]> pData
constexpr OUStringLiteral aData
double getLength(const B2DPolygon &rCandidate)
Reference< XComponentContext > getProcessComponentContext()
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
sal_Int64 nCompressedSize
Definition: ZipEntry.hxx:31
sal_Int16 nVersion
Definition: ZipEntry.hxx:26
sal_Int64 nOffset
Definition: ZipEntry.hxx:33
sal_Int32 nCrc
Definition: ZipEntry.hxx:30
sal_Int64 nSize
Definition: ZipEntry.hxx:32
sal_Int32 nTime
Definition: ZipEntry.hxx:29
sal_Int16 nExtraLen
Definition: ZipEntry.hxx:35
OUString sPath
Definition: ZipEntry.hxx:36
sal_Int16 nFlag
Definition: ZipEntry.hxx:27
sal_Int16 nMethod
Definition: ZipEntry.hxx:28
sal_Int16 nPathLen
Definition: ZipEntry.hxx:34
unsigned char sal_uInt8
sal_uInt16 sal_Unicode
signed char sal_Int8
std::unique_ptr< char[]> aBuffer
sal_Int32 nLength