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