1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_package.hxx" 26 27 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 28 #include <com/sun/star/ucb/XProgressHandler.hpp> 29 #include <com/sun/star/packages/zip/ZipConstants.hpp> 30 #include <com/sun/star/xml/crypto/XCipherContext.hpp> 31 #include <com/sun/star/xml/crypto/XDigestContext.hpp> 32 #include <com/sun/star/xml/crypto/XCipherContextSupplier.hpp> 33 #include <com/sun/star/xml/crypto/XDigestContextSupplier.hpp> 34 #include <com/sun/star/xml/crypto/CipherID.hpp> 35 #include <com/sun/star/xml/crypto/DigestID.hpp> 36 37 #include <comphelper/storagehelper.hxx> 38 #include <comphelper/processfactory.hxx> 39 #include <rtl/digest.h> 40 41 #include <vector> 42 43 #include "blowfishcontext.hxx" 44 #include "sha1context.hxx" 45 #include <ZipFile.hxx> 46 #include <ZipEnumeration.hxx> 47 #include <XUnbufferedStream.hxx> 48 #include <PackageConstants.hxx> 49 #include <EncryptedDataHeader.hxx> 50 #include <EncryptionData.hxx> 51 #include <MemoryByteGrabber.hxx> 52 53 #include <CRC32.hxx> 54 55 #define AES_CBC_BLOCK_SIZE 16 56 57 using namespace vos; 58 using namespace rtl; 59 using namespace com::sun::star; 60 using namespace com::sun::star::io; 61 using namespace com::sun::star::uno; 62 using namespace com::sun::star::ucb; 63 using namespace com::sun::star::lang; 64 using namespace com::sun::star::packages; 65 using namespace com::sun::star::packages::zip; 66 using namespace com::sun::star::packages::zip::ZipConstants; 67 68 69 /** This class is used to read entries from a zip file 70 */ 71 ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference < XMultiServiceFactory > &xNewFactory, sal_Bool bInitialise ) 72 throw(IOException, ZipException, RuntimeException) 73 : aGrabber(xInput) 74 , aInflater (sal_True) 75 , xStream(xInput) 76 , xSeek(xInput, UNO_QUERY) 77 , m_xFactory ( xNewFactory ) 78 , bRecoveryMode( sal_False ) 79 { 80 if (bInitialise) 81 { 82 if ( readCEN() == -1 ) 83 { 84 aEntries.clear(); 85 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "stream data looks to be broken" ) ), uno::Reference < XInterface > () ); 86 } 87 } 88 } 89 90 91 92 ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference < XMultiServiceFactory > &xNewFactory, sal_Bool bInitialise, sal_Bool bForceRecovery, uno::Reference < XProgressHandler > xProgress ) 93 throw(IOException, ZipException, RuntimeException) 94 : aGrabber(xInput) 95 , aInflater (sal_True) 96 , xStream(xInput) 97 , xSeek(xInput, UNO_QUERY) 98 , m_xFactory ( xNewFactory ) 99 , xProgressHandler( xProgress ) 100 , bRecoveryMode( bForceRecovery ) 101 { 102 if (bInitialise) 103 { 104 if ( bForceRecovery ) 105 { 106 recover(); 107 } 108 else if ( readCEN() == -1 ) 109 { 110 aEntries.clear(); 111 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "stream data looks to be broken" ) ), uno::Reference < XInterface > () ); 112 } 113 } 114 } 115 116 ZipFile::~ZipFile() 117 { 118 aEntries.clear(); 119 } 120 121 void ZipFile::setInputStream ( uno::Reference < XInputStream > xNewStream ) 122 { 123 ::osl::MutexGuard aGuard( m_aMutex ); 124 125 xStream = xNewStream; 126 xSeek = uno::Reference < XSeekable > ( xStream, UNO_QUERY ); 127 aGrabber.setInputStream ( xStream ); 128 } 129 130 uno::Reference< xml::crypto::XDigestContext > ZipFile::StaticGetDigestContextForChecksum( const uno::Reference< lang::XMultiServiceFactory >& xArgFactory, 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< lang::XMultiServiceFactory > xFactory = xArgFactory; 136 if ( !xFactory.is() ) 137 xFactory.set( comphelper::getProcessServiceFactory(), uno::UNO_SET_THROW ); 138 139 uno::Reference< xml::crypto::XDigestContextSupplier > xDigestContextSupplier( 140 xFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.crypto.NSSInitializer" ) ) ), 141 uno::UNO_QUERY_THROW ); 142 143 xDigestContext.set( xDigestContextSupplier->getDigestContext( xEncryptionData->m_nCheckAlg, uno::Sequence< beans::NamedValue >() ), uno::UNO_SET_THROW ); 144 } 145 else if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA1_1K ) 146 xDigestContext.set( SHA1DigestContext::Create(), uno::UNO_SET_THROW ); 147 148 return xDigestContext; 149 } 150 151 uno::Reference< xml::crypto::XCipherContext > ZipFile::StaticGetCipher( const uno::Reference< lang::XMultiServiceFactory >& xArgFactory, const ::rtl::Reference< EncryptionData >& xEncryptionData, bool bEncrypt ) 152 { 153 uno::Reference< xml::crypto::XCipherContext > xResult; 154 155 try 156 { 157 uno::Sequence< sal_Int8 > aDerivedKey( xEncryptionData->m_nDerivedKeySize ); 158 if ( rtl_Digest_E_None != rtl_digest_PBKDF2( reinterpret_cast< sal_uInt8* >( aDerivedKey.getArray() ), 159 aDerivedKey.getLength(), 160 reinterpret_cast< const sal_uInt8 * > (xEncryptionData->m_aKey.getConstArray() ), 161 xEncryptionData->m_aKey.getLength(), 162 reinterpret_cast< const sal_uInt8 * > ( xEncryptionData->m_aSalt.getConstArray() ), 163 xEncryptionData->m_aSalt.getLength(), 164 xEncryptionData->m_nIterationCount ) ) 165 { 166 throw ZipIOException( ::rtl::OUString::createFromAscii( "Can not create derived key!\n" ), 167 uno::Reference< XInterface >() ); 168 } 169 170 if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::AES_CBC_W3C_PADDING ) 171 { 172 uno::Reference< lang::XMultiServiceFactory > xFactory = xArgFactory; 173 if ( !xFactory.is() ) 174 xFactory.set( comphelper::getProcessServiceFactory(), uno::UNO_SET_THROW ); 175 176 uno::Reference< xml::crypto::XCipherContextSupplier > xCipherContextSupplier( 177 xFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.crypto.NSSInitializer" ) ) ), 178 uno::UNO_QUERY_THROW ); 179 180 xResult = xCipherContextSupplier->getCipherContext( xEncryptionData->m_nEncAlg, aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt, uno::Sequence< beans::NamedValue >() ); 181 } 182 else if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::BLOWFISH_CFB_8 ) 183 { 184 xResult = BlowfishCFB8CipherContext::Create( aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt ); 185 } 186 else 187 { 188 throw ZipIOException( ::rtl::OUString::createFromAscii( "Unknown cipher algorithm is requested!\n" ), 189 uno::Reference< XInterface >() ); 190 } 191 } 192 catch( uno::Exception& ) 193 { 194 OSL_ENSURE( sal_False, "Can not create cipher context!" ); 195 } 196 197 return xResult; 198 } 199 200 void ZipFile::StaticFillHeader( const ::rtl::Reference< EncryptionData >& rData, 201 sal_Int32 nSize, 202 const ::rtl::OUString& aMediaType, 203 sal_Int8 * & pHeader ) 204 { 205 // I think it's safe to restrict vector and salt length to 2 bytes ! 206 sal_Int16 nIVLength = static_cast < sal_Int16 > ( rData->m_aInitVector.getLength() ); 207 sal_Int16 nSaltLength = static_cast < sal_Int16 > ( rData->m_aSalt.getLength() ); 208 sal_Int16 nDigestLength = static_cast < sal_Int16 > ( rData->m_aDigest.getLength() ); 209 sal_Int16 nMediaTypeLength = static_cast < sal_Int16 > ( aMediaType.getLength() * sizeof( sal_Unicode ) ); 210 211 // First the header 212 *(pHeader++) = ( n_ConstHeader >> 0 ) & 0xFF; 213 *(pHeader++) = ( n_ConstHeader >> 8 ) & 0xFF; 214 *(pHeader++) = ( n_ConstHeader >> 16 ) & 0xFF; 215 *(pHeader++) = ( n_ConstHeader >> 24 ) & 0xFF; 216 217 // Then the version 218 *(pHeader++) = ( n_ConstCurrentVersion >> 0 ) & 0xFF; 219 *(pHeader++) = ( n_ConstCurrentVersion >> 8 ) & 0xFF; 220 221 // Then the iteration Count 222 sal_Int32 nIterationCount = rData->m_nIterationCount; 223 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 0 ) & 0xFF); 224 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 8 ) & 0xFF); 225 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 16 ) & 0xFF); 226 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 24 ) & 0xFF); 227 228 // Then the size 229 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 0 ) & 0xFF); 230 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 8 ) & 0xFF); 231 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 16 ) & 0xFF); 232 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 24 ) & 0xFF); 233 234 // Then the encryption algorithm 235 sal_Int32 nEncAlgID = rData->m_nEncAlg; 236 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 0 ) & 0xFF); 237 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 8 ) & 0xFF); 238 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 16 ) & 0xFF); 239 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 24 ) & 0xFF); 240 241 // Then the checksum algorithm 242 sal_Int32 nChecksumAlgID = rData->m_nCheckAlg; 243 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 0 ) & 0xFF); 244 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 8 ) & 0xFF); 245 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 16 ) & 0xFF); 246 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 24 ) & 0xFF); 247 248 // Then the derived key size 249 sal_Int32 nDerivedKeySize = rData->m_nDerivedKeySize; 250 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 0 ) & 0xFF); 251 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 8 ) & 0xFF); 252 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 16 ) & 0xFF); 253 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 24 ) & 0xFF); 254 255 // Then the start key generation algorithm 256 sal_Int32 nKeyAlgID = rData->m_nStartKeyGenID; 257 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 0 ) & 0xFF); 258 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 8 ) & 0xFF); 259 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 16 ) & 0xFF); 260 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 24 ) & 0xFF); 261 262 // Then the salt length 263 *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 0 ) & 0xFF); 264 *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 8 ) & 0xFF); 265 266 // Then the IV length 267 *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 0 ) & 0xFF); 268 *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 8 ) & 0xFF); 269 270 // Then the digest length 271 *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 0 ) & 0xFF); 272 *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 8 ) & 0xFF); 273 274 // Then the mediatype length 275 *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 0 ) & 0xFF); 276 *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 8 ) & 0xFF); 277 278 // Then the salt content 279 rtl_copyMemory ( pHeader, rData->m_aSalt.getConstArray(), nSaltLength ); 280 pHeader += nSaltLength; 281 282 // Then the IV content 283 rtl_copyMemory ( pHeader, rData->m_aInitVector.getConstArray(), nIVLength ); 284 pHeader += nIVLength; 285 286 // Then the digest content 287 rtl_copyMemory ( pHeader, rData->m_aDigest.getConstArray(), nDigestLength ); 288 pHeader += nDigestLength; 289 290 // Then the mediatype itself 291 rtl_copyMemory ( pHeader, aMediaType.getStr(), nMediaTypeLength ); 292 pHeader += nMediaTypeLength; 293 } 294 295 sal_Bool ZipFile::StaticFillData ( ::rtl::Reference< BaseEncryptionData > & rData, 296 sal_Int32 &rEncAlg, 297 sal_Int32 &rChecksumAlg, 298 sal_Int32 &rDerivedKeySize, 299 sal_Int32 &rStartKeyGenID, 300 sal_Int32 &rSize, 301 ::rtl::OUString& aMediaType, 302 const uno::Reference< XInputStream >& rStream ) 303 { 304 sal_Bool bOk = sal_False; 305 const sal_Int32 nHeaderSize = n_ConstHeaderSize - 4; 306 Sequence < sal_Int8 > aBuffer ( nHeaderSize ); 307 if ( nHeaderSize == rStream->readBytes ( aBuffer, nHeaderSize ) ) 308 { 309 sal_Int16 nPos = 0; 310 sal_Int8 *pBuffer = aBuffer.getArray(); 311 sal_Int16 nVersion = pBuffer[nPos++] & 0xFF; 312 nVersion |= ( pBuffer[nPos++] & 0xFF ) << 8; 313 if ( nVersion == n_ConstCurrentVersion ) 314 { 315 sal_Int32 nCount = pBuffer[nPos++] & 0xFF; 316 nCount |= ( pBuffer[nPos++] & 0xFF ) << 8; 317 nCount |= ( pBuffer[nPos++] & 0xFF ) << 16; 318 nCount |= ( pBuffer[nPos++] & 0xFF ) << 24; 319 rData->m_nIterationCount = nCount; 320 321 rSize = pBuffer[nPos++] & 0xFF; 322 rSize |= ( pBuffer[nPos++] & 0xFF ) << 8; 323 rSize |= ( pBuffer[nPos++] & 0xFF ) << 16; 324 rSize |= ( pBuffer[nPos++] & 0xFF ) << 24; 325 326 rEncAlg = pBuffer[nPos++] & 0xFF; 327 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 8; 328 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 16; 329 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 24; 330 331 rChecksumAlg = pBuffer[nPos++] & 0xFF; 332 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 8; 333 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 16; 334 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 24; 335 336 rDerivedKeySize = pBuffer[nPos++] & 0xFF; 337 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 8; 338 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 16; 339 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 24; 340 341 rStartKeyGenID = pBuffer[nPos++] & 0xFF; 342 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 8; 343 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 16; 344 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 24; 345 346 sal_Int16 nSaltLength = pBuffer[nPos++] & 0xFF; 347 nSaltLength |= ( pBuffer[nPos++] & 0xFF ) << 8; 348 sal_Int16 nIVLength = ( pBuffer[nPos++] & 0xFF ); 349 nIVLength |= ( pBuffer[nPos++] & 0xFF ) << 8; 350 sal_Int16 nDigestLength = pBuffer[nPos++] & 0xFF; 351 nDigestLength |= ( pBuffer[nPos++] & 0xFF ) << 8; 352 353 sal_Int16 nMediaTypeLength = pBuffer[nPos++] & 0xFF; 354 nMediaTypeLength |= ( pBuffer[nPos++] & 0xFF ) << 8; 355 356 if ( nSaltLength == rStream->readBytes ( aBuffer, nSaltLength ) ) 357 { 358 rData->m_aSalt.realloc ( nSaltLength ); 359 rtl_copyMemory ( rData->m_aSalt.getArray(), aBuffer.getConstArray(), nSaltLength ); 360 if ( nIVLength == rStream->readBytes ( aBuffer, nIVLength ) ) 361 { 362 rData->m_aInitVector.realloc ( nIVLength ); 363 rtl_copyMemory ( rData->m_aInitVector.getArray(), aBuffer.getConstArray(), nIVLength ); 364 if ( nDigestLength == rStream->readBytes ( aBuffer, nDigestLength ) ) 365 { 366 rData->m_aDigest.realloc ( nDigestLength ); 367 rtl_copyMemory ( rData->m_aDigest.getArray(), aBuffer.getConstArray(), nDigestLength ); 368 369 if ( nMediaTypeLength == rStream->readBytes ( aBuffer, nMediaTypeLength ) ) 370 { 371 aMediaType = ::rtl::OUString( (sal_Unicode*)aBuffer.getConstArray(), 372 nMediaTypeLength / sizeof( sal_Unicode ) ); 373 bOk = sal_True; 374 } 375 } 376 } 377 } 378 } 379 } 380 return bOk; 381 } 382 383 uno::Reference< XInputStream > ZipFile::StaticGetDataFromRawStream( const uno::Reference< lang::XMultiServiceFactory >& xFactory, 384 const uno::Reference< XInputStream >& xStream, 385 const ::rtl::Reference< EncryptionData > &rData ) 386 throw ( packages::WrongPasswordException, ZipIOException, RuntimeException ) 387 { 388 if ( !rData.is() ) 389 throw ZipIOException( OUString::createFromAscii( "Encrypted stream without encryption data!\n" ), 390 uno::Reference< XInterface >() ); 391 392 if ( !rData->m_aKey.getLength() ) 393 throw packages::WrongPasswordException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 394 395 uno::Reference< XSeekable > xSeek( xStream, UNO_QUERY ); 396 if ( !xSeek.is() ) 397 throw ZipIOException( OUString::createFromAscii( "The stream must be seekable!\n" ), 398 uno::Reference< XInterface >() ); 399 400 401 // if we have a digest, then this file is an encrypted one and we should 402 // check if we can decrypt it or not 403 OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!\n" ); 404 if ( rData->m_aDigest.getLength() ) 405 { 406 sal_Int32 nSize = sal::static_int_cast< sal_Int32 >( xSeek->getLength() ); 407 if ( nSize > n_ConstDigestLength + 32 ) 408 nSize = n_ConstDigestLength + 32; 409 410 // skip header 411 xSeek->seek( n_ConstHeaderSize + rData->m_aInitVector.getLength() + 412 rData->m_aSalt.getLength() + rData->m_aDigest.getLength() ); 413 414 // Only want to read enough to verify the digest 415 Sequence < sal_Int8 > aReadBuffer ( nSize ); 416 417 xStream->readBytes( aReadBuffer, nSize ); 418 419 if ( !StaticHasValidPassword( xFactory, aReadBuffer, rData ) ) 420 throw packages::WrongPasswordException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 421 } 422 423 return new XUnbufferedStream( xFactory, xStream, rData ); 424 } 425 426 #if 0 427 // for debugging purposes 428 void CheckSequence( const uno::Sequence< sal_Int8 >& aSequence ) 429 { 430 if ( aSequence.getLength() ) 431 { 432 sal_Int32* pPointer = *( (sal_Int32**)&aSequence ); 433 sal_Int32 nSize = *( pPointer + 1 ); 434 sal_Int32 nMemSize = *( pPointer - 2 ); 435 sal_Int32 nUsedMemSize = ( nSize + 4 * sizeof( sal_Int32 ) ); 436 OSL_ENSURE( nSize == aSequence.getLength() && nUsedMemSize + 7 - ( nUsedMemSize - 1 ) % 8 == nMemSize, "Broken Sequence!" ); 437 } 438 } 439 #endif 440 441 sal_Bool ZipFile::StaticHasValidPassword( const uno::Reference< lang::XMultiServiceFactory >& xFactory, const Sequence< sal_Int8 > &aReadBuffer, const ::rtl::Reference< EncryptionData > &rData ) 442 { 443 if ( !rData.is() || !rData->m_aKey.getLength() ) 444 return sal_False; 445 446 sal_Bool bRet = sal_False; 447 448 uno::Reference< xml::crypto::XCipherContext > xCipher( StaticGetCipher( xFactory, rData, false ), uno::UNO_SET_THROW ); 449 450 uno::Sequence< sal_Int8 > aDecryptBuffer; 451 uno::Sequence< sal_Int8 > aDecryptBuffer2; 452 try 453 { 454 aDecryptBuffer = xCipher->convertWithCipherContext( aReadBuffer ); 455 aDecryptBuffer2 = xCipher->finalizeCipherContextAndDispose(); 456 } 457 catch( uno::Exception& ) 458 { 459 // decryption with padding will throw the exception in finalizing if the buffer represent only part of the stream 460 // it is no problem, actually this is why we read 32 additional bytes ( two of maximal possible encryption blocks ) 461 } 462 463 if ( aDecryptBuffer2.getLength() ) 464 { 465 sal_Int32 nOldLen = aDecryptBuffer.getLength(); 466 aDecryptBuffer.realloc( nOldLen + aDecryptBuffer2.getLength() ); 467 rtl_copyMemory( aDecryptBuffer.getArray() + nOldLen, aDecryptBuffer2.getArray(), aDecryptBuffer2.getLength() ); 468 } 469 470 if ( aDecryptBuffer.getLength() > n_ConstDigestLength ) 471 aDecryptBuffer.realloc( n_ConstDigestLength ); 472 473 uno::Sequence< sal_Int8 > aDigestSeq; 474 uno::Reference< xml::crypto::XDigestContext > xDigestContext( StaticGetDigestContextForChecksum( xFactory, rData ), uno::UNO_SET_THROW ); 475 476 xDigestContext->updateDigest( aDecryptBuffer ); 477 aDigestSeq = xDigestContext->finalizeDigestAndDispose(); 478 479 // If we don't have a digest, then we have to assume that the password is correct 480 if ( rData->m_aDigest.getLength() != 0 && 481 ( aDigestSeq.getLength() != rData->m_aDigest.getLength() || 482 0 != rtl_compareMemory ( aDigestSeq.getConstArray(), 483 rData->m_aDigest.getConstArray(), 484 aDigestSeq.getLength() ) ) ) 485 { 486 // We should probably tell the user that the password they entered was wrong 487 } 488 else 489 bRet = sal_True; 490 491 return bRet; 492 } 493 494 sal_Bool ZipFile::hasValidPassword ( ZipEntry & rEntry, const ::rtl::Reference< EncryptionData >& rData ) 495 { 496 ::osl::MutexGuard aGuard( m_aMutex ); 497 498 sal_Bool bRet = sal_False; 499 if ( rData.is() && rData->m_aKey.getLength() ) 500 { 501 xSeek->seek( rEntry.nFileDataOffset ); 502 sal_Int32 nSize = rEntry.nMethod == DEFLATED ? rEntry.nCompressedSize : rEntry.nSize; 503 504 // Only want to read enough to verify the digest 505 if ( nSize > n_ConstDigestDecrypt ) 506 nSize = n_ConstDigestDecrypt; 507 508 Sequence < sal_Int8 > aReadBuffer ( nSize ); 509 510 xStream->readBytes( aReadBuffer, nSize ); 511 512 bRet = StaticHasValidPassword( m_xFactory, aReadBuffer, rData ); 513 } 514 515 return bRet; 516 } 517 518 uno::Reference< XInputStream > ZipFile::createUnbufferedStream( 519 SotMutexHolderRef aMutexHolder, 520 ZipEntry & rEntry, 521 const ::rtl::Reference< EncryptionData > &rData, 522 sal_Int8 nStreamMode, 523 sal_Bool bIsEncrypted, 524 ::rtl::OUString aMediaType ) 525 { 526 527 // Only encrypted entries can be STORED and have a data descriptor 528 if ( !bIsEncrypted && ( rEntry.nMethod == STORED ) && rEntry.bHasDataDescriptor ) 529 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "entry has spurious file descriptor" ) ), uno::Reference < XInterface > () ); 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.nFileDataOffset <= 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.nFileDataOffset <= 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.nFileDataOffset <= 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.nFileDataOffset <= 0 ) 640 readLOC( rEntry ); 641 642 return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_WRAPPEDRAW, sal_True, aMediaType ); 643 } 644 645 /** Read extra fields 646 * 647 * @param rGrabber Grabber object for reading data. 648 * @param nLength extra field length 649 * @param rEntry entry data. 650 * 651 * Expects rGrabber to point to the beginning of the extra fields. 652 * Advances it until all fields are read (i.e. after nLength bytes). 653 * 654 * @throw ZipException in case of problems. 655 */ 656 static void readExtraFields( MemoryByteGrabber &rMemGrabber, sal_Int16 nLength, ZipEntry &rEntry ) 657 { 658 sal_Int16 nHeaderID, nDataSize; 659 sal_Int16 nReadBytes = 0; 660 sal_Int8 n8; 661 rtl::OUString s; 662 while ( ( nLength - nReadBytes ) >= 2 ) { 663 rMemGrabber >> nHeaderID; 664 rMemGrabber >> nDataSize; 665 nReadBytes += 2; 666 if (( nDataSize > ( nLength - nReadBytes ) ) || 667 ( nDataSize > rMemGrabber.available() ) ) 668 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid ZIP extra fields" ) ), uno::Reference < XInterface > () ); 669 switch ( nHeaderID ) { 670 case 0x7075: // Info-ZIP Unicode Path Extra Field 671 rMemGrabber >> n8; // Version 672 rMemGrabber.skipBytes( 4 ); // skip NameCRC32 673 s = rtl::OUString::intern ( (sal_Char *) rMemGrabber.getCurrentPos(), 674 nDataSize - 5, 675 RTL_TEXTENCODING_UTF8 ); 676 if ( n8 != 1 ) 677 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid ZIP unicode path extra field version" ) ), uno::Reference < XInterface > () ); 678 if ( s != rEntry.sPath ) 679 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid ZIP unicode path extra field" ) ), uno::Reference < XInterface > () ); 680 rMemGrabber.skipBytes( nDataSize - 5 ); 681 break; 682 default: // We are not interested in this field 683 rMemGrabber.skipBytes( nDataSize ); 684 } 685 } 686 } 687 688 sal_Bool ZipFile::readLOC( ZipEntry &rEntry ) 689 throw(IOException, ZipException, RuntimeException) 690 { 691 ::osl::MutexGuard aGuard( m_aMutex ); 692 693 sal_Int32 nTestSig, nTime, nCRC, nSize, nCompressedSize; 694 sal_Int16 nVersion, nFlag, nHow, nPathLen; 695 sal_Int32 nPos = rEntry.nFileHeaderOffset; 696 697 aGrabber.seek(nPos); 698 aGrabber >> nTestSig; 699 700 if (nTestSig != LOCSIG) 701 throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid LOC header (bad signature") ), uno::Reference < XInterface > () ); 702 aGrabber >> nVersion; 703 aGrabber >> nFlag; 704 aGrabber >> nHow; 705 aGrabber >> nTime; 706 aGrabber >> nCRC; 707 aGrabber >> nCompressedSize; 708 aGrabber >> nSize; 709 aGrabber >> nPathLen; 710 aGrabber >> rEntry.nLOCExtraLen; 711 rEntry.nFileDataOffset = static_cast < sal_Int32 > (aGrabber.getPosition()) + nPathLen + rEntry.nLOCExtraLen; 712 713 // read always in UTF8, some tools seem not to set UTF8 bit 714 uno::Sequence < sal_Int8 > aNameBuffer( nPathLen ); 715 sal_Int32 nRead = aGrabber.readBytes( aNameBuffer, nPathLen ); 716 if ( nRead < aNameBuffer.getLength() ) 717 aNameBuffer.realloc( nRead ); 718 719 ::rtl::OUString sLOCPath = rtl::OUString::intern( (sal_Char *) aNameBuffer.getArray(), 720 aNameBuffer.getLength(), 721 RTL_TEXTENCODING_UTF8 ); 722 723 if ( rEntry.nPathLen == -1 ) // the file was created 724 { 725 rEntry.nPathLen = nPathLen; 726 rEntry.sPath = sLOCPath; 727 } 728 729 // the method can be reset for internal use so it is not checked 730 sal_Bool bBroken = rEntry.nVersion != nVersion 731 || rEntry.nFlag != nFlag 732 || rEntry.nMethod != nHow 733 || rEntry.nTime != nTime 734 || rEntry.nPathLen != nPathLen 735 || !rEntry.sPath.equals( sLOCPath ); 736 737 if ( bBroken && !bRecoveryMode ) 738 throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ), 739 uno::Reference< XInterface >() ); 740 741 Sequence < sal_Int8 > aExtraFields ( rEntry.nLOCExtraLen ); 742 nRead = aGrabber.readBytes( aExtraFields, rEntry.nLOCExtraLen ); 743 if ( nRead != rEntry.nLOCExtraLen ) 744 throw ZipException ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Error reading LOC extra fields into memory buffer!") ), uno::Reference < XInterface > () ); 745 MemoryByteGrabber aMemGrabber ( aExtraFields ); 746 readExtraFields( aMemGrabber, rEntry.nLOCExtraLen, rEntry ); 747 748 // Check for a data descriptor 749 rEntry.bHasDataDescriptor = rEntry.nFlag & ( 1 << 3 ); 750 if ( rEntry.bHasDataDescriptor ) { 751 // some fields of the local file header must be zero 752 if ( ( nCRC | nCompressedSize | nSize ) != 0 ) 753 throw ZipException ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Data descriptor mismatch!") ), uno::Reference < XInterface > () ); 754 } 755 sal_Int32 n32; 756 aGrabber.seek( rEntry.nFileDataOffset + rEntry.nCompressedSize ); 757 aGrabber >> n32; 758 if ( n32 == EXTSIG ) { // Signature detected 759 rEntry.bHasDataDescriptor = sal_True; 760 aGrabber >> n32; 761 } 762 if ( rEntry.bHasDataDescriptor ) { 763 if ( n32 != rEntry.nCrc ) 764 throw ZipException ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Data descriptor CRC mismatch!") ), uno::Reference < XInterface > () ); 765 aGrabber >> n32; 766 if ( n32 != rEntry.nCompressedSize ) 767 throw ZipException ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Data descriptor compressed size mismatch!") ), uno::Reference < XInterface > () ); 768 aGrabber >> n32; 769 if ( n32 != rEntry.nSize ) 770 throw ZipException ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Data descriptor uncompressed size mismatch!") ), uno::Reference < XInterface > () ); 771 } 772 return sal_True; 773 } 774 775 sal_Int32 ZipFile::findEND( ) 776 throw(IOException, ZipException, RuntimeException) 777 { 778 // this method is called in constructor only, no need for mutex 779 sal_Int32 nLength, nPos, nEnd; 780 Sequence < sal_Int8 > aBuffer; 781 try 782 { 783 nLength = static_cast <sal_Int32 > (aGrabber.getLength()); 784 if (nLength == 0 || nLength < ENDHDR) 785 return -1; 786 nPos = nLength - ENDHDR - ZIP_MAXNAMELEN; 787 nEnd = nPos >= 0 ? nPos : 0 ; 788 789 aGrabber.seek( nEnd ); 790 aGrabber.readBytes ( aBuffer, nLength - nEnd ); 791 792 const sal_Int8 *pBuffer = aBuffer.getConstArray(); 793 794 nPos = nLength - nEnd - ENDHDR; 795 while ( nPos >= 0 ) 796 { 797 if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 5 && pBuffer[nPos+3] == 6 ) 798 return nPos + nEnd; 799 nPos--; 800 } 801 } 802 catch ( IllegalArgumentException& ) 803 { 804 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 805 } 806 catch ( NotConnectedException& ) 807 { 808 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 809 } 810 catch ( BufferSizeExceededException& ) 811 { 812 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 813 } 814 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 815 } 816 817 static sal_Bool entriesContainPath( const EntryHash &rEntries, 818 const OUString &sPath ) 819 { 820 for ( EntryHash::const_iterator aIt = rEntries.begin(); 821 aIt != rEntries.end(); ++aIt) 822 { 823 if ( aIt->first.equalsIgnoreAsciiCase( sPath ) ) 824 return sal_True; 825 } 826 return sal_False; 827 } 828 829 sal_Int32 ZipFile::readCEN() 830 throw(IOException, ZipException, RuntimeException) 831 { 832 // this method is called in constructor only, no need for mutex 833 sal_Int32 nCenLen, nCenPos = -1, nCenOff, nEndPos, nLocPos; 834 sal_uInt16 nCount, nTotal; 835 836 try 837 { 838 nEndPos = findEND(); 839 if (nEndPos == -1) 840 return -1; 841 /* 842 Ignored fields: 843 - number of this disk 844 - number of the disk with the start of the central directory 845 - total number of entries in the central directory on this disk 846 */ 847 aGrabber.seek(nEndPos + ENDTOT); 848 // total number of entries in the central directory 849 aGrabber >> nTotal; 850 // size of the central directory 851 aGrabber >> nCenLen; 852 // offset of start of central directory 853 aGrabber >> nCenOff; 854 855 if ( nTotal * CENHDR > nCenLen ) 856 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "invalid END header (bad entry count)") ), uno::Reference < XInterface > () ); 857 858 if ( nTotal > ZIP_MAXENTRIES ) 859 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "too many entries in ZIP File") ), uno::Reference < XInterface > () ); 860 861 if ( nCenLen < 0 || nCenLen > nEndPos ) 862 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid END header (bad central directory size)") ), uno::Reference < XInterface > () ); 863 864 nCenPos = nEndPos - nCenLen; 865 866 if ( nCenOff < 0 || nCenOff > nCenPos ) 867 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid END header (bad central directory size)") ), uno::Reference < XInterface > () ); 868 869 // Read the central directory headers 870 nLocPos = nCenPos - nCenOff; 871 aGrabber.seek( nCenPos ); 872 Sequence < sal_Int8 > aCENBuffer ( nCenLen ); 873 sal_Int64 nRead = aGrabber.readBytes ( aCENBuffer, nCenLen ); 874 if ( static_cast < sal_Int64 > ( nCenLen ) != nRead ) 875 throw ZipException ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Error reading CEN into memory buffer!") ), uno::Reference < XInterface > () ); 876 877 MemoryByteGrabber aMemGrabber ( aCENBuffer ); 878 879 ZipEntry aEntry; 880 sal_Int32 nTestSig; 881 sal_Int16 nCommentLen; 882 rtl::OUString sFirstFilePath; 883 884 for (nCount = 0 ; nCount < nTotal; nCount++) 885 { 886 aMemGrabber >> nTestSig; 887 if ( nTestSig != CENSIG ) 888 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid CEN header (bad signature)") ), uno::Reference < XInterface > () ); 889 890 aMemGrabber.skipBytes ( 2 ); // skip: versione made by 891 aMemGrabber >> aEntry.nVersion; // version needed to extract 892 aMemGrabber >> aEntry.nFlag; // general purpose bit flag 893 if ( ( aEntry.nFlag & 1 ) == 1 ) 894 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid CEN header (encrypted entry)") ), uno::Reference < XInterface > () ); 895 896 aMemGrabber >> aEntry.nMethod; // compression method 897 898 if ( aEntry.nMethod != STORED && aEntry.nMethod != DEFLATED) 899 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid CEN header (bad compression method)") ), uno::Reference < XInterface > () ); 900 901 aMemGrabber >> aEntry.nTime; // last mod file date & time 902 aMemGrabber >> aEntry.nCrc; // crc-32 903 aMemGrabber >> aEntry.nCompressedSize; // compressed size 904 aMemGrabber >> aEntry.nSize; // uncompressed size 905 if ( aEntry.nMethod == STORED && ( aEntry.nCompressedSize != aEntry.nSize ) ) 906 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Size mismatch of STORED entry") ), uno::Reference < XInterface > () ); 907 aMemGrabber >> aEntry.nPathLen; // file name length 908 aMemGrabber >> aEntry.nCENExtraLen; // extra field length 909 aMemGrabber >> nCommentLen; // file comment length 910 // skip: disk number start, internal & external file attributes 911 aMemGrabber.skipBytes ( 8 ); 912 aMemGrabber >> aEntry.nFileHeaderOffset; // relative offset of local header 913 914 aEntry.nFileHeaderOffset += nLocPos; 915 916 if ( aEntry.nPathLen < 0 ) 917 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "unexpected name length" ) ), uno::Reference < XInterface > () ); 918 919 if ( nCommentLen < 0 ) 920 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "unexpected comment length" ) ), uno::Reference < XInterface > () ); 921 922 if ( aEntry.nCENExtraLen < 0 ) 923 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "unexpected extra header info length") ), uno::Reference < XInterface > () ); 924 925 // read file name always in UTF8, some tools seem not to set UTF8 bit 926 aEntry.sPath = rtl::OUString::intern ( (sal_Char *) aMemGrabber.getCurrentPos(), 927 aEntry.nPathLen, 928 RTL_TEXTENCODING_UTF8 ); 929 930 if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( aEntry.sPath, sal_True ) ) 931 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip entry has an invalid name.") ), uno::Reference < XInterface > () ); 932 // Simplify path removing leading "./" 933 while ( aEntry.sPath.compareToAscii( "./", 2 ) == 0 ) 934 aEntry.sPath = aEntry.sPath.copy( 2 ); 935 936 // skip: file name (already processed) 937 aMemGrabber.skipBytes( aEntry.nPathLen ); 938 readExtraFields( aMemGrabber, aEntry.nCENExtraLen, aEntry ); 939 // Search for Zip64 data among the comments. 940 // The Zip64 EOCDL takes 20 bytes; the ZIP64 EOCDR takes > 56 bytes 941 const sal_Int8* pCommentStart = aMemGrabber.getCurrentPos(); 942 for ( const sal_Int8* pCommentEnd = pCommentStart + nCommentLen; 943 pCommentEnd >= ( pCommentStart + 76 ); 944 --pCommentEnd) { 945 const sal_Int8 * p = ( pCommentEnd - 20 ); 946 sal_Int32 n32; 947 if (p[0] == 0x50) 948 // Detect EOCDL signature 0x07064b50 949 if ( ( p[0] == 0x50 ) && 950 ( p[1] == 0x4b ) && 951 ( p[2] == 0x06 ) && 952 ( p[3] == 0x07 ) ) { 953 // the relative offset of the zip64 end of central directory record starts at offset 8... 954 n32 = p[8] | ( p[9] << 8 ) | ( p[10] << 16 ) | 955 ( p[11] << 24 ); 956 // ...and it must be a 32-bit number represented with 64 bits 957 if ( ( p[12] | p[13] | p[14] | p[15] ) == 0 ) { 958 n32 -= nCenPos + aMemGrabber.getPosition(); 959 // Detect EOCDR signature 0x06064b50 960 if ( ( n32 > 0 ) && 961 ( pCommentStart[n32] == 0x50 ) && 962 ( pCommentStart[n32 + 1] == 0x4b ) && 963 ( pCommentStart[n32 + 2] == 0x06 ) && 964 ( pCommentStart[n32 + 3] == 0x06 ) ) { 965 throw ZipException ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Zip64 data found inside comments section") ), uno::Reference < XInterface > () ); 966 } 967 } 968 } 969 } 970 aMemGrabber.skipBytes( nCommentLen ); 971 if ( entriesContainPath( aEntries, aEntry.sPath ) ) 972 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Duplicated zip entry") ), uno::Reference < XInterface > () ); 973 readLOC( aEntry ); 974 if ( aEntry.nFileHeaderOffset == 0 ) 975 sFirstFilePath = aEntry.sPath; 976 aEntries[aEntry.sPath] = aEntry; 977 } 978 979 if (nCount != nTotal) 980 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Count != Total") ), uno::Reference < XInterface > () ); 981 982 if ( sFirstFilePath.getLength() == 0 ) 983 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "File contains junk before compressed data" ) ), uno::Reference < XInterface > () ); 984 985 // Verify the proper sequence of fields 986 sal_Int32 nPos, nPos2; 987 EntryHash::const_iterator aIt = aEntries.find( sFirstFilePath ); 988 nCount = 0; 989 nPos = 0; 990 do { 991 if ( aIt == aEntries.end() ) throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Internal error" ) ), uno::Reference < XInterface > () ); 992 // Local file header 993 nPos += 30 + aIt->first.getLength() + aIt->second.nLOCExtraLen; 994 if ( nPos != aIt->second.nFileDataOffset ) 995 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "ZIP file contains a hole between local descriptor and file data" ) ), uno::Reference < XInterface > () ); 996 // File data 997 nPos += aIt->second.nCompressedSize; 998 if ( aIt->second.nFlag & ( 1 << 3 ) ) { 999 // Data descriptor... 1000 nPos += 16; // ...with signature 1001 nPos2 = nPos - 4; // ...without signature 1002 } else nPos2 = nPos; 1003 ++nCount; 1004 if ( nCount == nTotal ) { 1005 break; 1006 } 1007 // Find next entry, starting at either nPos or nPos2 1008 for ( aIt = aEntries.begin(); aIt != aEntries.end(); ++aIt ) 1009 if (( aIt->second.nFileHeaderOffset == nPos ) || 1010 ( aIt->second.nFileHeaderOffset == nPos2 )) 1011 break; 1012 if ( aIt == aEntries.end() ) 1013 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "ZIP file contains holes among files" ) ), uno::Reference < XInterface > () ); 1014 nPos = aIt->second.nFileHeaderOffset; 1015 } while ( 1 ); 1016 // After all files, we should have arrived at the central directory header 1017 if ( nPos != nCenPos ) 1018 throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "ZIP file contains a hole before the central directory" ) ), uno::Reference < XInterface > () ); 1019 } 1020 catch ( IllegalArgumentException & ) 1021 { 1022 // seek can throw this... 1023 nCenPos = -1; // make sure we return -1 to indicate an error 1024 } 1025 return nCenPos; 1026 } 1027 1028 sal_Int32 ZipFile::recover() 1029 throw(IOException, ZipException, RuntimeException) 1030 { 1031 ::osl::MutexGuard aGuard( m_aMutex ); 1032 1033 sal_Int32 nLength; 1034 Sequence < sal_Int8 > aBuffer; 1035 Sequence < sal_Int32 > aHeaderOffsets; 1036 1037 try 1038 { 1039 nLength = static_cast <sal_Int32 > (aGrabber.getLength()); 1040 if (nLength == 0 || nLength < ENDHDR) 1041 return -1; 1042 1043 aGrabber.seek( 0 ); 1044 1045 const sal_Int32 nToRead = 32000; 1046 for( sal_Int32 nGenPos = 0; aGrabber.readBytes( aBuffer, nToRead ) && aBuffer.getLength() > 16; ) 1047 { 1048 const sal_Int8 *pBuffer = aBuffer.getConstArray(); 1049 sal_Int32 nBufSize = aBuffer.getLength(); 1050 1051 sal_Int32 nPos = 0; 1052 // the buffer should contain at least one header, 1053 // or if it is end of the file, at least the postheader with sizes and hash 1054 while( nPos < nBufSize - 30 1055 || ( aBuffer.getLength() < nToRead && nPos < nBufSize - 16 ) ) 1056 1057 { 1058 if ( nPos < nBufSize - 30 && pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 3 && pBuffer[nPos+3] == 4 ) 1059 { 1060 // Local file header 1061 ZipEntry aEntry; 1062 MemoryByteGrabber aMemGrabber ( Sequence< sal_Int8 >( ((sal_Int8*)(&(pBuffer[nPos+4]))), 26 ) ); 1063 1064 aMemGrabber >> aEntry.nVersion; 1065 aMemGrabber >> aEntry.nFlag; 1066 if ( ( aEntry.nFlag & 1 ) != 1 ) // Must not be encrypted 1067 { 1068 aMemGrabber >> aEntry.nMethod; 1069 1070 if ( aEntry.nMethod == STORED || aEntry.nMethod == DEFLATED ) 1071 { 1072 aMemGrabber >> aEntry.nTime; 1073 aMemGrabber >> aEntry.nCrc; 1074 aMemGrabber >> aEntry.nCompressedSize; 1075 aMemGrabber >> aEntry.nSize; 1076 aMemGrabber >> aEntry.nPathLen; 1077 aMemGrabber >> aEntry.nLOCExtraLen; 1078 1079 sal_Int32 nDescrLength = 1080 ( aEntry.nMethod == DEFLATED && ( aEntry.nFlag & 8 ) ) ? 1081 16 : 0; 1082 1083 1084 // This is a quick fix for OOo1.1RC 1085 // For OOo2.0 the whole package must be switched to unsigned values 1086 if ( aEntry.nCompressedSize < 0 ) aEntry.nCompressedSize = 0x7FFFFFFF; 1087 if ( aEntry.nSize < 0 ) aEntry.nSize = 0x7FFFFFFF; 1088 if ( aEntry.nPathLen < 0 ) aEntry.nPathLen = 0x7FFF; 1089 if ( aEntry.nLOCExtraLen < 0 ) aEntry.nLOCExtraLen = 0x7FFF; 1090 // End of quick fix 1091 1092 sal_Int32 nDataSize = ( aEntry.nMethod == DEFLATED ) ? aEntry.nCompressedSize : aEntry.nSize; 1093 sal_Int32 nBlockLength = nDataSize + aEntry.nPathLen + aEntry.nLOCExtraLen + 30 + nDescrLength; 1094 if ( aEntry.nPathLen >= 0 && aEntry.nLOCExtraLen >= 0 1095 && ( nGenPos + nPos + nBlockLength ) <= nLength ) 1096 { 1097 // read always in UTF8, some tools seem not to set UTF8 bit 1098 if( nPos + 30 + aEntry.nPathLen <= nBufSize ) 1099 aEntry.sPath = OUString ( (sal_Char *) &pBuffer[nPos + 30], 1100 aEntry.nPathLen, 1101 RTL_TEXTENCODING_UTF8 ); 1102 else 1103 { 1104 Sequence < sal_Int8 > aFileName; 1105 aGrabber.seek( nGenPos + nPos + 30 ); 1106 aGrabber.readBytes( aFileName, aEntry.nPathLen ); 1107 aEntry.sPath = OUString ( (sal_Char *) aFileName.getArray(), 1108 aFileName.getLength(), 1109 RTL_TEXTENCODING_UTF8 ); 1110 aEntry.nPathLen = static_cast< sal_Int16 >(aFileName.getLength()); 1111 } 1112 1113 aEntry.nFileDataOffset = nGenPos + nPos + 30 + aEntry.nPathLen + aEntry.nLOCExtraLen; 1114 1115 if ( ( aEntry.nSize || aEntry.nCompressedSize ) && !checkSizeAndCRC( aEntry ) ) 1116 { 1117 aEntry.nCrc = 0; 1118 aEntry.nCompressedSize = 0; 1119 aEntry.nSize = 0; 1120 } 1121 1122 if ( aEntries.find( aEntry.sPath ) == aEntries.end() ) 1123 aEntries[aEntry.sPath] = aEntry; 1124 } 1125 } 1126 } 1127 1128 nPos += 4; 1129 } 1130 else if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 7 && pBuffer[nPos+3] == 8 ) 1131 { // This is a data descriptor 1132 sal_Int32 nCompressedSize, nSize, nCRC32; 1133 MemoryByteGrabber aMemGrabber ( Sequence< sal_Int8 >( ((sal_Int8*)(&(pBuffer[nPos+4]))), 12 ) ); 1134 aMemGrabber >> nCRC32; 1135 aMemGrabber >> nCompressedSize; 1136 aMemGrabber >> nSize; 1137 1138 for( EntryHash::iterator aIter = aEntries.begin(); aIter != aEntries.end(); aIter++ ) 1139 { 1140 ZipEntry aTmp = (*aIter).second; 1141 1142 // this is a broken package, accept this block not only for DEFLATED streams 1143 if( (*aIter).second.nFlag & 8 ) 1144 { 1145 sal_Int32 nStreamOffset = nGenPos + nPos - nCompressedSize; 1146 if ( nStreamOffset == (*aIter).second.nFileDataOffset && nCompressedSize > (*aIter).second.nCompressedSize ) 1147 { 1148 // only DEFLATED blocks need to be checked 1149 sal_Bool bAcceptBlock = ( (*aIter).second.nMethod == STORED && nCompressedSize == nSize ); 1150 1151 if ( !bAcceptBlock ) 1152 { 1153 sal_Int32 nRealSize = 0, nRealCRC = 0; 1154 getSizeAndCRC( nStreamOffset, nCompressedSize, &nRealSize, &nRealCRC ); 1155 bAcceptBlock = ( nRealSize == nSize && nRealCRC == nCRC32 ); 1156 } 1157 1158 if ( bAcceptBlock ) 1159 { 1160 (*aIter).second.nCrc = nCRC32; 1161 (*aIter).second.nCompressedSize = nCompressedSize; 1162 (*aIter).second.nSize = nSize; 1163 } 1164 } 1165 #if 0 1166 // for now ignore clearly broken streams 1167 else if( !(*aIter).second.nCompressedSize ) 1168 { 1169 (*aIter).second.nCrc = nCRC32; 1170 sal_Int32 nRealStreamSize = nGenPos + nPos - (*aIter).second.nFileDataOffset; 1171 (*aIter).second.nCompressedSize = nGenPos + nPos - (*aIter).second.nFileDataOffset; 1172 (*aIter).second.nSize = nSize; 1173 } 1174 #endif 1175 } 1176 } 1177 1178 nPos += 4; 1179 } 1180 else 1181 nPos++; 1182 } 1183 1184 nGenPos += nPos; 1185 aGrabber.seek( nGenPos ); 1186 } 1187 1188 return 0; 1189 } 1190 catch ( IllegalArgumentException& ) 1191 { 1192 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 1193 } 1194 catch ( NotConnectedException& ) 1195 { 1196 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 1197 } 1198 catch ( BufferSizeExceededException& ) 1199 { 1200 throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), uno::Reference < XInterface > () ); 1201 } 1202 } 1203 1204 sal_Bool ZipFile::checkSizeAndCRC( const ZipEntry& aEntry ) 1205 { 1206 ::osl::MutexGuard aGuard( m_aMutex ); 1207 1208 sal_Int32 nSize = 0, nCRC = 0; 1209 1210 if( aEntry.nMethod == STORED ) 1211 return ( getCRC( aEntry.nFileDataOffset, aEntry.nSize ) == aEntry.nCrc ); 1212 1213 getSizeAndCRC( aEntry.nFileDataOffset, aEntry.nCompressedSize, &nSize, &nCRC ); 1214 return ( aEntry.nSize == nSize && aEntry.nCrc == nCRC ); 1215 } 1216 1217 sal_Int32 ZipFile::getCRC( sal_Int32 nFileDataOffset, sal_Int32 nSize ) 1218 { 1219 ::osl::MutexGuard aGuard( m_aMutex ); 1220 1221 Sequence < sal_Int8 > aBuffer; 1222 CRC32 aCRC; 1223 sal_Int32 nBlockSize = ::std::min( nSize, static_cast< sal_Int32 >( 32000 ) ); 1224 1225 aGrabber.seek( nFileDataOffset ); 1226 for ( int ind = 0; 1227 aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nSize; 1228 ind++ ) 1229 { 1230 aCRC.updateSegment( aBuffer, 0, ::std::min( nBlockSize, nSize - ind * nBlockSize ) ); 1231 } 1232 1233 return aCRC.getValue(); 1234 } 1235 1236 void ZipFile::getSizeAndCRC( sal_Int32 nFileDataOffset, sal_Int32 nCompressedSize, sal_Int32 *nSize, sal_Int32 *nCRC ) 1237 { 1238 ::osl::MutexGuard aGuard( m_aMutex ); 1239 1240 Sequence < sal_Int8 > aBuffer; 1241 CRC32 aCRC; 1242 sal_Int32 nRealSize = 0; 1243 Inflater aInflaterLocal( sal_True ); 1244 sal_Int32 nBlockSize = ::std::min( nCompressedSize, static_cast< sal_Int32 >( 32000 ) ); 1245 1246 aGrabber.seek( nFileDataOffset ); 1247 for ( int ind = 0; 1248 !aInflaterLocal.finished() && aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nCompressedSize; 1249 ind++ ) 1250 { 1251 Sequence < sal_Int8 > aData( nBlockSize ); 1252 sal_Int32 nLastInflated = 0; 1253 sal_Int32 nInBlock = 0; 1254 1255 aInflaterLocal.setInput( aBuffer ); 1256 do 1257 { 1258 nLastInflated = aInflaterLocal.doInflateSegment( aData, 0, nBlockSize ); 1259 aCRC.updateSegment( aData, 0, nLastInflated ); 1260 nInBlock += nLastInflated; 1261 } while( !aInflater.finished() && nLastInflated ); 1262 1263 nRealSize += nInBlock; 1264 } 1265 1266 *nSize = nRealSize; 1267 *nCRC = aCRC.getValue(); 1268 } 1269 1270