1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_package.hxx" 30 31 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 32 #include <com/sun/star/ucb/XProgressHandler.hpp> 33 #include <com/sun/star/packages/zip/ZipConstants.hpp> 34 #include <com/sun/star/xml/crypto/XCipherContext.hpp> 35 #include <com/sun/star/xml/crypto/XDigestContext.hpp> 36 #include <com/sun/star/xml/crypto/XCipherContextSupplier.hpp> 37 #include <com/sun/star/xml/crypto/XDigestContextSupplier.hpp> 38 #include <com/sun/star/xml/crypto/CipherID.hpp> 39 #include <com/sun/star/xml/crypto/DigestID.hpp> 40 41 #include <comphelper/storagehelper.hxx> 42 #include <comphelper/processfactory.hxx> 43 #include <rtl/digest.h> 44 45 #include <vector> 46 47 #include "blowfishcontext.hxx" 48 #include "sha1context.hxx" 49 #include <ZipFile.hxx> 50 #include <ZipEnumeration.hxx> 51 #include <XUnbufferedStream.hxx> 52 #include <PackageConstants.hxx> 53 #include <EncryptedDataHeader.hxx> 54 #include <EncryptionData.hxx> 55 #include <MemoryByteGrabber.hxx> 56 57 #include <CRC32.hxx> 58 59 #define AES_CBC_BLOCK_SIZE 16 60 61 using namespace vos; 62 using namespace rtl; 63 using namespace com::sun::star; 64 using namespace com::sun::star::io; 65 using namespace com::sun::star::uno; 66 using namespace com::sun::star::ucb; 67 using namespace com::sun::star::lang; 68 using namespace com::sun::star::packages; 69 using namespace com::sun::star::packages::zip; 70 using namespace com::sun::star::packages::zip::ZipConstants; 71 72 73 /** This class is used to read entries from a zip file 74 */ 75 ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference < XMultiServiceFactory > &xNewFactory, sal_Bool bInitialise ) 76 throw(IOException, ZipException, RuntimeException) 77 : aGrabber(xInput) 78 , aInflater (sal_True) 79 , xStream(xInput) 80 , xSeek(xInput, UNO_QUERY) 81 , m_xFactory ( xNewFactory ) 82 , bRecoveryMode( sal_False ) 83 { 84 if (bInitialise) 85 { 86 if ( readCEN() == -1 ) 87 { 88 aEntries.clear(); 89 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "stream data looks to be broken" ) ), uno::Reference < XInterface > () ); 90 } 91 } 92 } 93 94 95 96 ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference < XMultiServiceFactory > &xNewFactory, sal_Bool bInitialise, sal_Bool bForceRecovery, uno::Reference < XProgressHandler > xProgress ) 97 throw(IOException, ZipException, RuntimeException) 98 : aGrabber(xInput) 99 , aInflater (sal_True) 100 , xStream(xInput) 101 , xSeek(xInput, UNO_QUERY) 102 , m_xFactory ( xNewFactory ) 103 , xProgressHandler( xProgress ) 104 , bRecoveryMode( bForceRecovery ) 105 { 106 if (bInitialise) 107 { 108 if ( bForceRecovery ) 109 { 110 recover(); 111 } 112 else if ( readCEN() == -1 ) 113 { 114 aEntries.clear(); 115 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "stream data looks to be broken" ) ), uno::Reference < XInterface > () ); 116 } 117 } 118 } 119 120 ZipFile::~ZipFile() 121 { 122 aEntries.clear(); 123 } 124 125 void ZipFile::setInputStream ( uno::Reference < XInputStream > xNewStream ) 126 { 127 ::osl::MutexGuard aGuard( m_aMutex ); 128 129 xStream = xNewStream; 130 xSeek = uno::Reference < XSeekable > ( xStream, UNO_QUERY ); 131 aGrabber.setInputStream ( xStream ); 132 } 133 134 uno::Reference< xml::crypto::XDigestContext > ZipFile::StaticGetDigestContextForChecksum( const uno::Reference< lang::XMultiServiceFactory >& xArgFactory, 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< lang::XMultiServiceFactory > xFactory = xArgFactory; 140 if ( !xFactory.is() ) 141 xFactory.set( comphelper::getProcessServiceFactory(), uno::UNO_SET_THROW ); 142 143 uno::Reference< xml::crypto::XDigestContextSupplier > xDigestContextSupplier( 144 xFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.crypto.NSSInitializer" ) ) ), 145 uno::UNO_QUERY_THROW ); 146 147 xDigestContext.set( xDigestContextSupplier->getDigestContext( xEncryptionData->m_nCheckAlg, uno::Sequence< beans::NamedValue >() ), uno::UNO_SET_THROW ); 148 } 149 else if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA1_1K ) 150 xDigestContext.set( SHA1DigestContext::Create(), uno::UNO_SET_THROW ); 151 152 return xDigestContext; 153 } 154 155 uno::Reference< xml::crypto::XCipherContext > ZipFile::StaticGetCipher( const uno::Reference< lang::XMultiServiceFactory >& xArgFactory, const ::rtl::Reference< EncryptionData >& xEncryptionData, bool bEncrypt ) 156 { 157 uno::Reference< xml::crypto::XCipherContext > xResult; 158 159 try 160 { 161 uno::Sequence< sal_Int8 > aDerivedKey( xEncryptionData->m_nDerivedKeySize ); 162 if ( rtl_Digest_E_None != rtl_digest_PBKDF2( reinterpret_cast< sal_uInt8* >( aDerivedKey.getArray() ), 163 aDerivedKey.getLength(), 164 reinterpret_cast< const sal_uInt8 * > (xEncryptionData->m_aKey.getConstArray() ), 165 xEncryptionData->m_aKey.getLength(), 166 reinterpret_cast< const sal_uInt8 * > ( xEncryptionData->m_aSalt.getConstArray() ), 167 xEncryptionData->m_aSalt.getLength(), 168 xEncryptionData->m_nIterationCount ) ) 169 { 170 throw ZipIOException( ::rtl::OUString::createFromAscii( "Can not create derived key!\n" ), 171 uno::Reference< XInterface >() ); 172 } 173 174 if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::AES_CBC_W3C_PADDING ) 175 { 176 uno::Reference< lang::XMultiServiceFactory > xFactory = xArgFactory; 177 if ( !xFactory.is() ) 178 xFactory.set( comphelper::getProcessServiceFactory(), uno::UNO_SET_THROW ); 179 180 uno::Reference< xml::crypto::XCipherContextSupplier > xCipherContextSupplier( 181 xFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.crypto.NSSInitializer" ) ) ), 182 uno::UNO_QUERY_THROW ); 183 184 xResult = xCipherContextSupplier->getCipherContext( xEncryptionData->m_nEncAlg, aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt, uno::Sequence< beans::NamedValue >() ); 185 } 186 else if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::BLOWFISH_CFB_8 ) 187 { 188 xResult = BlowfishCFB8CipherContext::Create( aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt ); 189 } 190 else 191 { 192 throw ZipIOException( ::rtl::OUString::createFromAscii( "Unknown cipher algorithm is requested!\n" ), 193 uno::Reference< XInterface >() ); 194 } 195 } 196 catch( uno::Exception& ) 197 { 198 OSL_ENSURE( sal_False, "Can not create cipher context!" ); 199 } 200 201 return xResult; 202 } 203 204 void ZipFile::StaticFillHeader( const ::rtl::Reference< EncryptionData >& rData, 205 sal_Int32 nSize, 206 const ::rtl::OUString& aMediaType, 207 sal_Int8 * & pHeader ) 208 { 209 // I think it's safe to restrict vector and salt length to 2 bytes ! 210 sal_Int16 nIVLength = static_cast < sal_Int16 > ( rData->m_aInitVector.getLength() ); 211 sal_Int16 nSaltLength = static_cast < sal_Int16 > ( rData->m_aSalt.getLength() ); 212 sal_Int16 nDigestLength = static_cast < sal_Int16 > ( rData->m_aDigest.getLength() ); 213 sal_Int16 nMediaTypeLength = static_cast < sal_Int16 > ( aMediaType.getLength() * sizeof( sal_Unicode ) ); 214 215 // First the header 216 *(pHeader++) = ( n_ConstHeader >> 0 ) & 0xFF; 217 *(pHeader++) = ( n_ConstHeader >> 8 ) & 0xFF; 218 *(pHeader++) = ( n_ConstHeader >> 16 ) & 0xFF; 219 *(pHeader++) = ( n_ConstHeader >> 24 ) & 0xFF; 220 221 // Then the version 222 *(pHeader++) = ( n_ConstCurrentVersion >> 0 ) & 0xFF; 223 *(pHeader++) = ( n_ConstCurrentVersion >> 8 ) & 0xFF; 224 225 // Then the iteration Count 226 sal_Int32 nIterationCount = rData->m_nIterationCount; 227 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 0 ) & 0xFF); 228 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 8 ) & 0xFF); 229 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 16 ) & 0xFF); 230 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 24 ) & 0xFF); 231 232 // Then the size 233 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 0 ) & 0xFF); 234 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 8 ) & 0xFF); 235 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 16 ) & 0xFF); 236 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 24 ) & 0xFF); 237 238 // Then the encryption algorithm 239 sal_Int32 nEncAlgID = rData->m_nEncAlg; 240 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 0 ) & 0xFF); 241 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 8 ) & 0xFF); 242 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 16 ) & 0xFF); 243 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 24 ) & 0xFF); 244 245 // Then the checksum algorithm 246 sal_Int32 nChecksumAlgID = rData->m_nCheckAlg; 247 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 0 ) & 0xFF); 248 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 8 ) & 0xFF); 249 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 16 ) & 0xFF); 250 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 24 ) & 0xFF); 251 252 // Then the derived key size 253 sal_Int32 nDerivedKeySize = rData->m_nDerivedKeySize; 254 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 0 ) & 0xFF); 255 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 8 ) & 0xFF); 256 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 16 ) & 0xFF); 257 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 24 ) & 0xFF); 258 259 // Then the start key generation algorithm 260 sal_Int32 nKeyAlgID = rData->m_nStartKeyGenID; 261 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 0 ) & 0xFF); 262 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 8 ) & 0xFF); 263 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 16 ) & 0xFF); 264 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 24 ) & 0xFF); 265 266 // Then the salt length 267 *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 0 ) & 0xFF); 268 *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 8 ) & 0xFF); 269 270 // Then the IV length 271 *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 0 ) & 0xFF); 272 *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 8 ) & 0xFF); 273 274 // Then the digest length 275 *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 0 ) & 0xFF); 276 *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 8 ) & 0xFF); 277 278 // Then the mediatype length 279 *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 0 ) & 0xFF); 280 *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 8 ) & 0xFF); 281 282 // Then the salt content 283 rtl_copyMemory ( pHeader, rData->m_aSalt.getConstArray(), nSaltLength ); 284 pHeader += nSaltLength; 285 286 // Then the IV content 287 rtl_copyMemory ( pHeader, rData->m_aInitVector.getConstArray(), nIVLength ); 288 pHeader += nIVLength; 289 290 // Then the digest content 291 rtl_copyMemory ( pHeader, rData->m_aDigest.getConstArray(), nDigestLength ); 292 pHeader += nDigestLength; 293 294 // Then the mediatype itself 295 rtl_copyMemory ( pHeader, aMediaType.getStr(), nMediaTypeLength ); 296 pHeader += nMediaTypeLength; 297 } 298 299 sal_Bool ZipFile::StaticFillData ( ::rtl::Reference< BaseEncryptionData > & rData, 300 sal_Int32 &rEncAlg, 301 sal_Int32 &rChecksumAlg, 302 sal_Int32 &rDerivedKeySize, 303 sal_Int32 &rStartKeyGenID, 304 sal_Int32 &rSize, 305 ::rtl::OUString& aMediaType, 306 const uno::Reference< XInputStream >& rStream ) 307 { 308 sal_Bool bOk = sal_False; 309 const sal_Int32 nHeaderSize = n_ConstHeaderSize - 4; 310 Sequence < sal_Int8 > aBuffer ( nHeaderSize ); 311 if ( nHeaderSize == rStream->readBytes ( aBuffer, nHeaderSize ) ) 312 { 313 sal_Int16 nPos = 0; 314 sal_Int8 *pBuffer = aBuffer.getArray(); 315 sal_Int16 nVersion = pBuffer[nPos++] & 0xFF; 316 nVersion |= ( pBuffer[nPos++] & 0xFF ) << 8; 317 if ( nVersion == n_ConstCurrentVersion ) 318 { 319 sal_Int32 nCount = pBuffer[nPos++] & 0xFF; 320 nCount |= ( pBuffer[nPos++] & 0xFF ) << 8; 321 nCount |= ( pBuffer[nPos++] & 0xFF ) << 16; 322 nCount |= ( pBuffer[nPos++] & 0xFF ) << 24; 323 rData->m_nIterationCount = nCount; 324 325 rSize = pBuffer[nPos++] & 0xFF; 326 rSize |= ( pBuffer[nPos++] & 0xFF ) << 8; 327 rSize |= ( pBuffer[nPos++] & 0xFF ) << 16; 328 rSize |= ( pBuffer[nPos++] & 0xFF ) << 24; 329 330 rEncAlg = pBuffer[nPos++] & 0xFF; 331 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 8; 332 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 16; 333 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 24; 334 335 rChecksumAlg = pBuffer[nPos++] & 0xFF; 336 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 8; 337 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 16; 338 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 24; 339 340 rDerivedKeySize = pBuffer[nPos++] & 0xFF; 341 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 8; 342 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 16; 343 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 24; 344 345 rStartKeyGenID = pBuffer[nPos++] & 0xFF; 346 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 8; 347 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 16; 348 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 24; 349 350 sal_Int16 nSaltLength = pBuffer[nPos++] & 0xFF; 351 nSaltLength |= ( pBuffer[nPos++] & 0xFF ) << 8; 352 sal_Int16 nIVLength = ( pBuffer[nPos++] & 0xFF ); 353 nIVLength |= ( pBuffer[nPos++] & 0xFF ) << 8; 354 sal_Int16 nDigestLength = pBuffer[nPos++] & 0xFF; 355 nDigestLength |= ( pBuffer[nPos++] & 0xFF ) << 8; 356 357 sal_Int16 nMediaTypeLength = pBuffer[nPos++] & 0xFF; 358 nMediaTypeLength |= ( pBuffer[nPos++] & 0xFF ) << 8; 359 360 if ( nSaltLength == rStream->readBytes ( aBuffer, nSaltLength ) ) 361 { 362 rData->m_aSalt.realloc ( nSaltLength ); 363 rtl_copyMemory ( rData->m_aSalt.getArray(), aBuffer.getConstArray(), nSaltLength ); 364 if ( nIVLength == rStream->readBytes ( aBuffer, nIVLength ) ) 365 { 366 rData->m_aInitVector.realloc ( nIVLength ); 367 rtl_copyMemory ( rData->m_aInitVector.getArray(), aBuffer.getConstArray(), nIVLength ); 368 if ( nDigestLength == rStream->readBytes ( aBuffer, nDigestLength ) ) 369 { 370 rData->m_aDigest.realloc ( nDigestLength ); 371 rtl_copyMemory ( rData->m_aDigest.getArray(), aBuffer.getConstArray(), nDigestLength ); 372 373 if ( nMediaTypeLength == rStream->readBytes ( aBuffer, nMediaTypeLength ) ) 374 { 375 aMediaType = ::rtl::OUString( (sal_Unicode*)aBuffer.getConstArray(), 376 nMediaTypeLength / sizeof( sal_Unicode ) ); 377 bOk = sal_True; 378 } 379 } 380 } 381 } 382 } 383 } 384 return bOk; 385 } 386 387 uno::Reference< XInputStream > ZipFile::StaticGetDataFromRawStream( const uno::Reference< lang::XMultiServiceFactory >& xFactory, 388 const uno::Reference< XInputStream >& xStream, 389 const ::rtl::Reference< EncryptionData > &rData ) 390 throw ( packages::WrongPasswordException, ZipIOException, RuntimeException ) 391 { 392 if ( !rData.is() ) 393 throw ZipIOException( OUString::createFromAscii( "Encrypted stream without encryption data!\n" ), 394 uno::Reference< XInterface >() ); 395 396 if ( !rData->m_aKey.getLength() ) 397 throw packages::WrongPasswordException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 398 399 uno::Reference< XSeekable > xSeek( xStream, UNO_QUERY ); 400 if ( !xSeek.is() ) 401 throw ZipIOException( OUString::createFromAscii( "The stream must be seekable!\n" ), 402 uno::Reference< XInterface >() ); 403 404 405 // if we have a digest, then this file is an encrypted one and we should 406 // check if we can decrypt it or not 407 OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!\n" ); 408 if ( rData->m_aDigest.getLength() ) 409 { 410 sal_Int32 nSize = sal::static_int_cast< sal_Int32 >( xSeek->getLength() ); 411 if ( nSize > n_ConstDigestLength + 32 ) 412 nSize = n_ConstDigestLength + 32; 413 414 // skip header 415 xSeek->seek( n_ConstHeaderSize + rData->m_aInitVector.getLength() + 416 rData->m_aSalt.getLength() + rData->m_aDigest.getLength() ); 417 418 // Only want to read enough to verify the digest 419 Sequence < sal_Int8 > aReadBuffer ( nSize ); 420 421 xStream->readBytes( aReadBuffer, nSize ); 422 423 if ( !StaticHasValidPassword( xFactory, aReadBuffer, rData ) ) 424 throw packages::WrongPasswordException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 425 } 426 427 return new XUnbufferedStream( xFactory, xStream, rData ); 428 } 429 430 #if 0 431 // for debugging purposes 432 void CheckSequence( const uno::Sequence< sal_Int8 >& aSequence ) 433 { 434 if ( aSequence.getLength() ) 435 { 436 sal_Int32* pPointer = *( (sal_Int32**)&aSequence ); 437 sal_Int32 nSize = *( pPointer + 1 ); 438 sal_Int32 nMemSize = *( pPointer - 2 ); 439 sal_Int32 nUsedMemSize = ( nSize + 4 * sizeof( sal_Int32 ) ); 440 OSL_ENSURE( nSize == aSequence.getLength() && nUsedMemSize + 7 - ( nUsedMemSize - 1 ) % 8 == nMemSize, "Broken Sequence!" ); 441 } 442 } 443 #endif 444 445 sal_Bool ZipFile::StaticHasValidPassword( const uno::Reference< lang::XMultiServiceFactory >& xFactory, const Sequence< sal_Int8 > &aReadBuffer, const ::rtl::Reference< EncryptionData > &rData ) 446 { 447 if ( !rData.is() || !rData->m_aKey.getLength() ) 448 return sal_False; 449 450 sal_Bool bRet = sal_False; 451 452 uno::Reference< xml::crypto::XCipherContext > xCipher( StaticGetCipher( xFactory, rData, false ), uno::UNO_SET_THROW ); 453 454 uno::Sequence< sal_Int8 > aDecryptBuffer; 455 uno::Sequence< sal_Int8 > aDecryptBuffer2; 456 try 457 { 458 aDecryptBuffer = xCipher->convertWithCipherContext( aReadBuffer ); 459 aDecryptBuffer2 = xCipher->finalizeCipherContextAndDispose(); 460 } 461 catch( uno::Exception& ) 462 { 463 // decryption with padding will throw the exception in finalizing if the buffer represent only part of the stream 464 // it is no problem, actually this is why we read 32 additional bytes ( two of maximal possible encryption blocks ) 465 } 466 467 if ( aDecryptBuffer2.getLength() ) 468 { 469 sal_Int32 nOldLen = aDecryptBuffer.getLength(); 470 aDecryptBuffer.realloc( nOldLen + aDecryptBuffer2.getLength() ); 471 rtl_copyMemory( aDecryptBuffer.getArray() + nOldLen, aDecryptBuffer2.getArray(), aDecryptBuffer2.getLength() ); 472 } 473 474 if ( aDecryptBuffer.getLength() > n_ConstDigestLength ) 475 aDecryptBuffer.realloc( n_ConstDigestLength ); 476 477 uno::Sequence< sal_Int8 > aDigestSeq; 478 uno::Reference< xml::crypto::XDigestContext > xDigestContext( StaticGetDigestContextForChecksum( xFactory, rData ), uno::UNO_SET_THROW ); 479 480 xDigestContext->updateDigest( aDecryptBuffer ); 481 aDigestSeq = xDigestContext->finalizeDigestAndDispose(); 482 483 // If we don't have a digest, then we have to assume that the password is correct 484 if ( rData->m_aDigest.getLength() != 0 && 485 ( aDigestSeq.getLength() != rData->m_aDigest.getLength() || 486 0 != rtl_compareMemory ( aDigestSeq.getConstArray(), 487 rData->m_aDigest.getConstArray(), 488 aDigestSeq.getLength() ) ) ) 489 { 490 // We should probably tell the user that the password they entered was wrong 491 } 492 else 493 bRet = sal_True; 494 495 return bRet; 496 } 497 498 sal_Bool ZipFile::hasValidPassword ( ZipEntry & rEntry, const ::rtl::Reference< EncryptionData >& rData ) 499 { 500 ::osl::MutexGuard aGuard( m_aMutex ); 501 502 sal_Bool bRet = sal_False; 503 if ( rData.is() && rData->m_aKey.getLength() ) 504 { 505 xSeek->seek( rEntry.nOffset ); 506 sal_Int32 nSize = rEntry.nMethod == DEFLATED ? rEntry.nCompressedSize : rEntry.nSize; 507 508 // Only want to read enough to verify the digest 509 if ( nSize > n_ConstDigestDecrypt ) 510 nSize = n_ConstDigestDecrypt; 511 512 Sequence < sal_Int8 > aReadBuffer ( nSize ); 513 514 xStream->readBytes( aReadBuffer, nSize ); 515 516 bRet = StaticHasValidPassword( m_xFactory, aReadBuffer, rData ); 517 } 518 519 return bRet; 520 } 521 522 uno::Reference< XInputStream > ZipFile::createUnbufferedStream( 523 SotMutexHolderRef aMutexHolder, 524 ZipEntry & rEntry, 525 const ::rtl::Reference< EncryptionData > &rData, 526 sal_Int8 nStreamMode, 527 sal_Bool bIsEncrypted, 528 ::rtl::OUString aMediaType ) 529 { 530 ::osl::MutexGuard aGuard( m_aMutex ); 531 532 return new XUnbufferedStream ( m_xFactory, aMutexHolder, rEntry, xStream, rData, nStreamMode, bIsEncrypted, aMediaType, bRecoveryMode ); 533 } 534 535 536 ZipEnumeration * SAL_CALL ZipFile::entries( ) 537 { 538 return new ZipEnumeration ( aEntries ); 539 } 540 541 uno::Reference< XInputStream > SAL_CALL ZipFile::getInputStream( ZipEntry& rEntry, 542 const ::rtl::Reference< EncryptionData > &rData, 543 sal_Bool bIsEncrypted, 544 SotMutexHolderRef aMutexHolder ) 545 throw(IOException, ZipException, RuntimeException) 546 { 547 ::osl::MutexGuard aGuard( m_aMutex ); 548 549 if ( rEntry.nOffset <= 0 ) 550 readLOC( rEntry ); 551 552 // We want to return a rawStream if we either don't have a key or if the 553 // key is wrong 554 555 sal_Bool bNeedRawStream = rEntry.nMethod == STORED; 556 557 // if we have a digest, then this file is an encrypted one and we should 558 // check if we can decrypt it or not 559 if ( bIsEncrypted && rData.is() && rData->m_aDigest.getLength() ) 560 bNeedRawStream = !hasValidPassword ( rEntry, rData ); 561 562 return createUnbufferedStream ( aMutexHolder, 563 rEntry, 564 rData, 565 bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA, 566 bIsEncrypted ); 567 } 568 569 uno::Reference< XInputStream > SAL_CALL ZipFile::getDataStream( ZipEntry& rEntry, 570 const ::rtl::Reference< EncryptionData > &rData, 571 sal_Bool bIsEncrypted, 572 SotMutexHolderRef aMutexHolder ) 573 throw ( packages::WrongPasswordException, 574 IOException, 575 ZipException, 576 RuntimeException ) 577 { 578 ::osl::MutexGuard aGuard( m_aMutex ); 579 580 if ( rEntry.nOffset <= 0 ) 581 readLOC( rEntry ); 582 583 // An exception must be thrown in case stream is encrypted and 584 // there is no key or the key is wrong 585 sal_Bool bNeedRawStream = sal_False; 586 if ( bIsEncrypted ) 587 { 588 // in case no digest is provided there is no way 589 // to detect password correctness 590 if ( !rData.is() ) 591 throw ZipException( OUString::createFromAscii( "Encrypted stream without encryption data!\n" ), 592 uno::Reference< XInterface >() ); 593 594 // if we have a digest, then this file is an encrypted one and we should 595 // check if we can decrypt it or not 596 OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!\n" ); 597 if ( rData->m_aDigest.getLength() && !hasValidPassword ( rEntry, rData ) ) 598 throw packages::WrongPasswordException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 599 } 600 else 601 bNeedRawStream = ( rEntry.nMethod == STORED ); 602 603 return createUnbufferedStream ( aMutexHolder, 604 rEntry, 605 rData, 606 bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA, 607 bIsEncrypted ); 608 } 609 610 uno::Reference< XInputStream > SAL_CALL ZipFile::getRawData( ZipEntry& rEntry, 611 const ::rtl::Reference< EncryptionData >& rData, 612 sal_Bool bIsEncrypted, 613 SotMutexHolderRef aMutexHolder ) 614 throw(IOException, ZipException, RuntimeException) 615 { 616 ::osl::MutexGuard aGuard( m_aMutex ); 617 618 if ( rEntry.nOffset <= 0 ) 619 readLOC( rEntry ); 620 621 return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_RAW, bIsEncrypted ); 622 } 623 624 uno::Reference< XInputStream > SAL_CALL ZipFile::getWrappedRawStream( 625 ZipEntry& rEntry, 626 const ::rtl::Reference< EncryptionData >& rData, 627 const ::rtl::OUString& aMediaType, 628 SotMutexHolderRef aMutexHolder ) 629 throw ( packages::NoEncryptionException, 630 IOException, 631 ZipException, 632 RuntimeException ) 633 { 634 ::osl::MutexGuard aGuard( m_aMutex ); 635 636 if ( !rData.is() ) 637 throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 638 639 if ( rEntry.nOffset <= 0 ) 640 readLOC( rEntry ); 641 642 return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_WRAPPEDRAW, sal_True, aMediaType ); 643 } 644 645 sal_Bool ZipFile::readLOC( ZipEntry &rEntry ) 646 throw(IOException, ZipException, RuntimeException) 647 { 648 ::osl::MutexGuard aGuard( m_aMutex ); 649 650 sal_Int32 nTestSig, nTime, nCRC, nSize, nCompressedSize; 651 sal_Int16 nVersion, nFlag, nHow, nPathLen, nExtraLen; 652 sal_Int32 nPos = -rEntry.nOffset; 653 654 aGrabber.seek(nPos); 655 aGrabber >> nTestSig; 656 657 if (nTestSig != LOCSIG) 658 throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid LOC header (bad signature") ), uno::Reference < XInterface > () ); 659 aGrabber >> nVersion; 660 aGrabber >> nFlag; 661 aGrabber >> nHow; 662 aGrabber >> nTime; 663 aGrabber >> nCRC; 664 aGrabber >> nCompressedSize; 665 aGrabber >> nSize; 666 aGrabber >> nPathLen; 667 aGrabber >> nExtraLen; 668 rEntry.nOffset = static_cast < sal_Int32 > (aGrabber.getPosition()) + nPathLen + nExtraLen; 669 670 // read always in UTF8, some tools seem not to set UTF8 bit 671 uno::Sequence < sal_Int8 > aNameBuffer( nPathLen ); 672 sal_Int32 nRead = aGrabber.readBytes( aNameBuffer, nPathLen ); 673 if ( nRead < aNameBuffer.getLength() ) 674 aNameBuffer.realloc( nRead ); 675 676 ::rtl::OUString sLOCPath = rtl::OUString::intern( (sal_Char *) aNameBuffer.getArray(), 677 aNameBuffer.getLength(), 678 RTL_TEXTENCODING_UTF8 ); 679 680 if ( rEntry.nPathLen == -1 ) // the file was created 681 { 682 rEntry.nPathLen = nPathLen; 683 rEntry.sPath = sLOCPath; 684 } 685 686 // the method can be reset for internal use so it is not checked 687 sal_Bool bBroken = rEntry.nVersion != nVersion 688 || rEntry.nFlag != nFlag 689 || rEntry.nTime != nTime 690 || rEntry.nPathLen != nPathLen 691 || !rEntry.sPath.equals( sLOCPath ); 692 693 if ( bBroken && !bRecoveryMode ) 694 throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ), 695 uno::Reference< XInterface >() ); 696 697 return sal_True; 698 } 699 700 sal_Int32 ZipFile::findEND( ) 701 throw(IOException, ZipException, RuntimeException) 702 { 703 // this method is called in constructor only, no need for mutex 704 sal_Int32 nLength, nPos, nEnd; 705 Sequence < sal_Int8 > aBuffer; 706 try 707 { 708 nLength = static_cast <sal_Int32 > (aGrabber.getLength()); 709 if (nLength == 0 || nLength < ENDHDR) 710 return -1; 711 nPos = nLength - ENDHDR - ZIP_MAXNAMELEN; 712 nEnd = nPos >= 0 ? nPos : 0 ; 713 714 aGrabber.seek( nEnd ); 715 aGrabber.readBytes ( aBuffer, nLength - nEnd ); 716 717 const sal_Int8 *pBuffer = aBuffer.getConstArray(); 718 719 nPos = nLength - nEnd - ENDHDR; 720 while ( nPos >= 0 ) 721 { 722 if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 5 && pBuffer[nPos+3] == 6 ) 723 return nPos + nEnd; 724 nPos--; 725 } 726 } 727 catch ( IllegalArgumentException& ) 728 { 729 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 730 } 731 catch ( NotConnectedException& ) 732 { 733 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 734 } 735 catch ( BufferSizeExceededException& ) 736 { 737 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 738 } 739 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 740 } 741 742 sal_Int32 ZipFile::readCEN() 743 throw(IOException, ZipException, RuntimeException) 744 { 745 // this method is called in constructor only, no need for mutex 746 sal_Int32 nCenLen, nCenPos = -1, nCenOff, nEndPos, nLocPos; 747 sal_uInt16 nCount, nTotal; 748 749 try 750 { 751 nEndPos = findEND(); 752 if (nEndPos == -1) 753 return -1; 754 aGrabber.seek(nEndPos + ENDTOT); 755 aGrabber >> nTotal; 756 aGrabber >> nCenLen; 757 aGrabber >> nCenOff; 758 759 if ( nTotal * CENHDR > nCenLen ) 760 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "invalid END header (bad entry count)") ), uno::Reference < XInterface > () ); 761 762 if ( nTotal > ZIP_MAXENTRIES ) 763 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "too many entries in ZIP File") ), uno::Reference < XInterface > () ); 764 765 if ( nCenLen < 0 || nCenLen > nEndPos ) 766 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid END header (bad central directory size)") ), uno::Reference < XInterface > () ); 767 768 nCenPos = nEndPos - nCenLen; 769 770 if ( nCenOff < 0 || nCenOff > nCenPos ) 771 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid END header (bad central directory size)") ), uno::Reference < XInterface > () ); 772 773 nLocPos = nCenPos - nCenOff; 774 aGrabber.seek( nCenPos ); 775 Sequence < sal_Int8 > aCENBuffer ( nCenLen ); 776 sal_Int64 nRead = aGrabber.readBytes ( aCENBuffer, nCenLen ); 777 if ( static_cast < sal_Int64 > ( nCenLen ) != nRead ) 778 throw ZipException ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Error reading CEN into memory buffer!") ), uno::Reference < XInterface > () ); 779 780 MemoryByteGrabber aMemGrabber ( aCENBuffer ); 781 782 ZipEntry aEntry; 783 sal_Int32 nTestSig; 784 sal_Int16 nCommentLen; 785 786 for (nCount = 0 ; nCount < nTotal; nCount++) 787 { 788 aMemGrabber >> nTestSig; 789 if ( nTestSig != CENSIG ) 790 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid CEN header (bad signature)") ), uno::Reference < XInterface > () ); 791 792 aMemGrabber.skipBytes ( 2 ); 793 aMemGrabber >> aEntry.nVersion; 794 795 if ( ( aEntry.nVersion & 1 ) == 1 ) 796 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid CEN header (encrypted entry)") ), uno::Reference < XInterface > () ); 797 798 aMemGrabber >> aEntry.nFlag; 799 aMemGrabber >> aEntry.nMethod; 800 801 if ( aEntry.nMethod != STORED && aEntry.nMethod != DEFLATED) 802 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid CEN header (bad compression method)") ), uno::Reference < XInterface > () ); 803 804 aMemGrabber >> aEntry.nTime; 805 aMemGrabber >> aEntry.nCrc; 806 aMemGrabber >> aEntry.nCompressedSize; 807 aMemGrabber >> aEntry.nSize; 808 aMemGrabber >> aEntry.nPathLen; 809 aMemGrabber >> aEntry.nExtraLen; 810 aMemGrabber >> nCommentLen; 811 aMemGrabber.skipBytes ( 8 ); 812 aMemGrabber >> aEntry.nOffset; 813 814 aEntry.nOffset += nLocPos; 815 aEntry.nOffset *= -1; 816 817 if ( aEntry.nPathLen < 0 ) 818 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "unexpected name length" ) ), uno::Reference < XInterface > () ); 819 820 if ( nCommentLen < 0 ) 821 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "unexpected comment length" ) ), uno::Reference < XInterface > () ); 822 823 if ( aEntry.nExtraLen < 0 ) 824 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "unexpected extra header info length") ), uno::Reference < XInterface > () ); 825 826 // read always in UTF8, some tools seem not to set UTF8 bit 827 aEntry.sPath = rtl::OUString::intern ( (sal_Char *) aMemGrabber.getCurrentPos(), 828 aEntry.nPathLen, 829 RTL_TEXTENCODING_UTF8 ); 830 831 if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( aEntry.sPath, sal_True ) ) 832 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip entry has an invalid name.") ), uno::Reference < XInterface > () ); 833 834 aMemGrabber.skipBytes( aEntry.nPathLen + aEntry.nExtraLen + nCommentLen ); 835 aEntries[aEntry.sPath] = aEntry; 836 } 837 838 if (nCount != nTotal) 839 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Count != Total") ), uno::Reference < XInterface > () ); 840 } 841 catch ( IllegalArgumentException & ) 842 { 843 // seek can throw this... 844 nCenPos = -1; // make sure we return -1 to indicate an error 845 } 846 return nCenPos; 847 } 848 849 sal_Int32 ZipFile::recover() 850 throw(IOException, ZipException, RuntimeException) 851 { 852 ::osl::MutexGuard aGuard( m_aMutex ); 853 854 sal_Int32 nLength; 855 Sequence < sal_Int8 > aBuffer; 856 Sequence < sal_Int32 > aHeaderOffsets; 857 858 try 859 { 860 nLength = static_cast <sal_Int32 > (aGrabber.getLength()); 861 if (nLength == 0 || nLength < ENDHDR) 862 return -1; 863 864 aGrabber.seek( 0 ); 865 866 const sal_Int32 nToRead = 32000; 867 for( sal_Int32 nGenPos = 0; aGrabber.readBytes( aBuffer, nToRead ) && aBuffer.getLength() > 16; ) 868 { 869 const sal_Int8 *pBuffer = aBuffer.getConstArray(); 870 sal_Int32 nBufSize = aBuffer.getLength(); 871 872 sal_Int32 nPos = 0; 873 // the buffer should contain at least one header, 874 // or if it is end of the file, at least the postheader with sizes and hash 875 while( nPos < nBufSize - 30 876 || ( aBuffer.getLength() < nToRead && nPos < nBufSize - 16 ) ) 877 878 { 879 if ( nPos < nBufSize - 30 && pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 3 && pBuffer[nPos+3] == 4 ) 880 { 881 ZipEntry aEntry; 882 MemoryByteGrabber aMemGrabber ( Sequence< sal_Int8 >( ((sal_Int8*)(&(pBuffer[nPos+4]))), 26 ) ); 883 884 aMemGrabber >> aEntry.nVersion; 885 if ( ( aEntry.nVersion & 1 ) != 1 ) 886 { 887 aMemGrabber >> aEntry.nFlag; 888 aMemGrabber >> aEntry.nMethod; 889 890 if ( aEntry.nMethod == STORED || aEntry.nMethod == DEFLATED ) 891 { 892 aMemGrabber >> aEntry.nTime; 893 aMemGrabber >> aEntry.nCrc; 894 aMemGrabber >> aEntry.nCompressedSize; 895 aMemGrabber >> aEntry.nSize; 896 aMemGrabber >> aEntry.nPathLen; 897 aMemGrabber >> aEntry.nExtraLen; 898 899 sal_Int32 nDescrLength = 900 ( aEntry.nMethod == DEFLATED && ( aEntry.nFlag & 8 ) ) ? 901 16 : 0; 902 903 904 // This is a quick fix for OOo1.1RC 905 // For OOo2.0 the whole package must be switched to unsigned values 906 if ( aEntry.nCompressedSize < 0 ) aEntry.nCompressedSize = 0x7FFFFFFF; 907 if ( aEntry.nSize < 0 ) aEntry.nSize = 0x7FFFFFFF; 908 if ( aEntry.nPathLen < 0 ) aEntry.nPathLen = 0x7FFF; 909 if ( aEntry.nExtraLen < 0 ) aEntry.nExtraLen = 0x7FFF; 910 // End of quick fix 911 912 sal_Int32 nDataSize = ( aEntry.nMethod == DEFLATED ) ? aEntry.nCompressedSize : aEntry.nSize; 913 sal_Int32 nBlockLength = nDataSize + aEntry.nPathLen + aEntry.nExtraLen + 30 + nDescrLength; 914 if ( aEntry.nPathLen >= 0 && aEntry.nExtraLen >= 0 915 && ( nGenPos + nPos + nBlockLength ) <= nLength ) 916 { 917 // read always in UTF8, some tools seem not to set UTF8 bit 918 if( nPos + 30 + aEntry.nPathLen <= nBufSize ) 919 aEntry.sPath = OUString ( (sal_Char *) &pBuffer[nPos + 30], 920 aEntry.nPathLen, 921 RTL_TEXTENCODING_UTF8 ); 922 else 923 { 924 Sequence < sal_Int8 > aFileName; 925 aGrabber.seek( nGenPos + nPos + 30 ); 926 aGrabber.readBytes( aFileName, aEntry.nPathLen ); 927 aEntry.sPath = OUString ( (sal_Char *) aFileName.getArray(), 928 aFileName.getLength(), 929 RTL_TEXTENCODING_UTF8 ); 930 aEntry.nPathLen = static_cast< sal_Int16 >(aFileName.getLength()); 931 } 932 933 aEntry.nOffset = nGenPos + nPos + 30 + aEntry.nPathLen + aEntry.nExtraLen; 934 935 if ( ( aEntry.nSize || aEntry.nCompressedSize ) && !checkSizeAndCRC( aEntry ) ) 936 { 937 aEntry.nCrc = 0; 938 aEntry.nCompressedSize = 0; 939 aEntry.nSize = 0; 940 } 941 942 if ( aEntries.find( aEntry.sPath ) == aEntries.end() ) 943 aEntries[aEntry.sPath] = aEntry; 944 } 945 } 946 } 947 948 nPos += 4; 949 } 950 else if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 7 && pBuffer[nPos+3] == 8 ) 951 { 952 sal_Int32 nCompressedSize, nSize, nCRC32; 953 MemoryByteGrabber aMemGrabber ( Sequence< sal_Int8 >( ((sal_Int8*)(&(pBuffer[nPos+4]))), 12 ) ); 954 aMemGrabber >> nCRC32; 955 aMemGrabber >> nCompressedSize; 956 aMemGrabber >> nSize; 957 958 for( EntryHash::iterator aIter = aEntries.begin(); aIter != aEntries.end(); aIter++ ) 959 { 960 ZipEntry aTmp = (*aIter).second; 961 962 // this is a broken package, accept this block not only for DEFLATED streams 963 if( (*aIter).second.nFlag & 8 ) 964 { 965 sal_Int32 nStreamOffset = nGenPos + nPos - nCompressedSize; 966 if ( nStreamOffset == (*aIter).second.nOffset && nCompressedSize > (*aIter).second.nCompressedSize ) 967 { 968 // only DEFLATED blocks need to be checked 969 sal_Bool bAcceptBlock = ( (*aIter).second.nMethod == STORED && nCompressedSize == nSize ); 970 971 if ( !bAcceptBlock ) 972 { 973 sal_Int32 nRealSize = 0, nRealCRC = 0; 974 getSizeAndCRC( nStreamOffset, nCompressedSize, &nRealSize, &nRealCRC ); 975 bAcceptBlock = ( nRealSize == nSize && nRealCRC == nCRC32 ); 976 } 977 978 if ( bAcceptBlock ) 979 { 980 (*aIter).second.nCrc = nCRC32; 981 (*aIter).second.nCompressedSize = nCompressedSize; 982 (*aIter).second.nSize = nSize; 983 } 984 } 985 #if 0 986 // for now ignore clearly broken streams 987 else if( !(*aIter).second.nCompressedSize ) 988 { 989 (*aIter).second.nCrc = nCRC32; 990 sal_Int32 nRealStreamSize = nGenPos + nPos - (*aIter).second.nOffset; 991 (*aIter).second.nCompressedSize = nGenPos + nPos - (*aIter).second.nOffset; 992 (*aIter).second.nSize = nSize; 993 } 994 #endif 995 } 996 } 997 998 nPos += 4; 999 } 1000 else 1001 nPos++; 1002 } 1003 1004 nGenPos += nPos; 1005 aGrabber.seek( nGenPos ); 1006 } 1007 1008 return 0; 1009 } 1010 catch ( IllegalArgumentException& ) 1011 { 1012 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 1013 } 1014 catch ( NotConnectedException& ) 1015 { 1016 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 1017 } 1018 catch ( BufferSizeExceededException& ) 1019 { 1020 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 1021 } 1022 } 1023 1024 sal_Bool ZipFile::checkSizeAndCRC( const ZipEntry& aEntry ) 1025 { 1026 ::osl::MutexGuard aGuard( m_aMutex ); 1027 1028 sal_Int32 nSize = 0, nCRC = 0; 1029 1030 if( aEntry.nMethod == STORED ) 1031 return ( getCRC( aEntry.nOffset, aEntry.nSize ) == aEntry.nCrc ); 1032 1033 getSizeAndCRC( aEntry.nOffset, aEntry.nCompressedSize, &nSize, &nCRC ); 1034 return ( aEntry.nSize == nSize && aEntry.nCrc == nCRC ); 1035 } 1036 1037 sal_Int32 ZipFile::getCRC( sal_Int32 nOffset, sal_Int32 nSize ) 1038 { 1039 ::osl::MutexGuard aGuard( m_aMutex ); 1040 1041 Sequence < sal_Int8 > aBuffer; 1042 CRC32 aCRC; 1043 sal_Int32 nBlockSize = ::std::min( nSize, static_cast< sal_Int32 >( 32000 ) ); 1044 1045 aGrabber.seek( nOffset ); 1046 for ( int ind = 0; 1047 aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nSize; 1048 ind++ ) 1049 { 1050 aCRC.updateSegment( aBuffer, 0, ::std::min( nBlockSize, nSize - ind * nBlockSize ) ); 1051 } 1052 1053 return aCRC.getValue(); 1054 } 1055 1056 void ZipFile::getSizeAndCRC( sal_Int32 nOffset, sal_Int32 nCompressedSize, sal_Int32 *nSize, sal_Int32 *nCRC ) 1057 { 1058 ::osl::MutexGuard aGuard( m_aMutex ); 1059 1060 Sequence < sal_Int8 > aBuffer; 1061 CRC32 aCRC; 1062 sal_Int32 nRealSize = 0; 1063 Inflater aInflaterLocal( sal_True ); 1064 sal_Int32 nBlockSize = ::std::min( nCompressedSize, static_cast< sal_Int32 >( 32000 ) ); 1065 1066 aGrabber.seek( nOffset ); 1067 for ( int ind = 0; 1068 !aInflaterLocal.finished() && aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nCompressedSize; 1069 ind++ ) 1070 { 1071 Sequence < sal_Int8 > aData( nBlockSize ); 1072 sal_Int32 nLastInflated = 0; 1073 sal_Int32 nInBlock = 0; 1074 1075 aInflaterLocal.setInput( aBuffer ); 1076 do 1077 { 1078 nLastInflated = aInflaterLocal.doInflateSegment( aData, 0, nBlockSize ); 1079 aCRC.updateSegment( aData, 0, nLastInflated ); 1080 nInBlock += nLastInflated; 1081 } while( !aInflater.finished() && nLastInflated ); 1082 1083 nRealSize += nInBlock; 1084 } 1085 1086 *nSize = nRealSize; 1087 *nCRC = aCRC.getValue(); 1088 } 1089 1090