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/packages/zip/ZipConstants.hpp> 32 #include <com/sun/star/packages/zip/ZipIOException.hpp> 33 #include <com/sun/star/xml/crypto/CipherID.hpp> 34 35 #include <XUnbufferedStream.hxx> 36 #include <EncryptionData.hxx> 37 #include <PackageConstants.hxx> 38 #include <ZipFile.hxx> 39 #include <EncryptedDataHeader.hxx> 40 #include <algorithm> 41 #include <string.h> 42 43 #include <osl/mutex.hxx> 44 45 #if 0 46 // for debugging purposes here 47 #include <com/sun/star/ucb/XSimpleFileAccess.hpp> 48 #include <comphelper/processfactory.hxx> 49 using namespace ::com::sun::star; 50 #endif 51 52 using namespace ::com::sun::star; 53 using namespace com::sun::star::packages::zip::ZipConstants; 54 using namespace com::sun::star::io; 55 using namespace com::sun::star::uno; 56 using com::sun::star::lang::IllegalArgumentException; 57 using com::sun::star::packages::zip::ZipIOException; 58 using ::rtl::OUString; 59 60 XUnbufferedStream::XUnbufferedStream( 61 const uno::Reference< lang::XMultiServiceFactory >& xFactory, 62 SotMutexHolderRef aMutexHolder, 63 ZipEntry & rEntry, 64 Reference < XInputStream > xNewZipStream, 65 const ::rtl::Reference< EncryptionData >& rData, 66 sal_Int8 nStreamMode, 67 sal_Bool bIsEncrypted, 68 const ::rtl::OUString& aMediaType, 69 sal_Bool bRecoveryMode ) 70 : maMutexHolder( aMutexHolder.Is() ? aMutexHolder : SotMutexHolderRef( new SotMutexHolder ) ) 71 , mxZipStream ( xNewZipStream ) 72 , mxZipSeek ( xNewZipStream, UNO_QUERY ) 73 , maEntry ( rEntry ) 74 , mxData ( rData ) 75 , mnBlockSize( 1 ) 76 , maInflater ( sal_True ) 77 , mbRawStream ( nStreamMode == UNBUFF_STREAM_RAW || nStreamMode == UNBUFF_STREAM_WRAPPEDRAW ) 78 , mbWrappedRaw ( nStreamMode == UNBUFF_STREAM_WRAPPEDRAW ) 79 , mbFinished ( sal_False ) 80 , mnHeaderToRead ( 0 ) 81 , mnZipCurrent ( 0 ) 82 , mnZipEnd ( 0 ) 83 , mnZipSize ( 0 ) 84 , mnMyCurrent ( 0 ) 85 , mbCheckCRC( !bRecoveryMode ) 86 { 87 mnZipCurrent = maEntry.nOffset; 88 if ( mbRawStream ) 89 { 90 mnZipSize = maEntry.nMethod == DEFLATED ? maEntry.nCompressedSize : maEntry.nSize; 91 mnZipEnd = maEntry.nOffset + mnZipSize; 92 } 93 else 94 { 95 mnZipSize = maEntry.nSize; 96 mnZipEnd = maEntry.nMethod == DEFLATED ? maEntry.nOffset + maEntry.nCompressedSize : maEntry.nOffset + maEntry.nSize; 97 } 98 sal_Bool bHaveEncryptData = ( rData.is() && rData->m_aSalt.getLength() && rData->m_aInitVector.getLength() && rData->m_nIterationCount != 0 ) ? sal_True : sal_False; 99 sal_Bool bMustDecrypt = ( nStreamMode == UNBUFF_STREAM_DATA && bHaveEncryptData && bIsEncrypted ) ? sal_True : sal_False; 100 101 if ( bMustDecrypt ) 102 { 103 m_xCipherContext = ZipFile::StaticGetCipher( xFactory, rData, false ); 104 mnBlockSize = ( rData->m_nEncAlg == xml::crypto::CipherID::AES_CBC_W3C_PADDING ? 16 : 1 ); 105 } 106 107 if ( bHaveEncryptData && mbWrappedRaw && bIsEncrypted ) 108 { 109 // if we have the data needed to decrypt it, but didn't want it decrypted (or 110 // we couldn't decrypt it due to wrong password), then we prepend this 111 // data to the stream 112 113 // Make a buffer big enough to hold both the header and the data itself 114 maHeader.realloc ( n_ConstHeaderSize + 115 rData->m_aInitVector.getLength() + 116 rData->m_aSalt.getLength() + 117 rData->m_aDigest.getLength() + 118 aMediaType.getLength() * sizeof( sal_Unicode ) ); 119 sal_Int8 * pHeader = maHeader.getArray(); 120 ZipFile::StaticFillHeader( rData, rEntry.nSize, aMediaType, pHeader ); 121 mnHeaderToRead = static_cast < sal_Int16 > ( maHeader.getLength() ); 122 } 123 } 124 125 // allows to read package raw stream 126 XUnbufferedStream::XUnbufferedStream( 127 const uno::Reference< lang::XMultiServiceFactory >& /*xFactory*/, 128 const Reference < XInputStream >& xRawStream, 129 const ::rtl::Reference< EncryptionData >& rData ) 130 : maMutexHolder( new SotMutexHolder ) 131 , mxZipStream ( xRawStream ) 132 , mxZipSeek ( xRawStream, UNO_QUERY ) 133 , mxData ( rData ) 134 , mnBlockSize( 1 ) 135 , maInflater ( sal_True ) 136 , mbRawStream ( sal_False ) 137 , mbWrappedRaw ( sal_False ) 138 , mbFinished ( sal_False ) 139 , mnHeaderToRead ( 0 ) 140 , mnZipCurrent ( 0 ) 141 , mnZipEnd ( 0 ) 142 , mnZipSize ( 0 ) 143 , mnMyCurrent ( 0 ) 144 , mbCheckCRC( sal_False ) 145 { 146 // for this scenario maEntry is not set !!! 147 OSL_ENSURE( mxZipSeek.is(), "The stream must be seekable!\n" ); 148 149 // skip raw header, it must be already parsed to rData 150 mnZipCurrent = n_ConstHeaderSize + rData->m_aInitVector.getLength() + 151 rData->m_aSalt.getLength() + rData->m_aDigest.getLength(); 152 153 try { 154 if ( mxZipSeek.is() ) 155 mnZipSize = mxZipSeek->getLength(); 156 } catch( Exception& ) 157 { 158 // in case of problem the size will stay set to 0 159 } 160 161 mnZipEnd = mnZipCurrent + mnZipSize; 162 163 // the raw data will not be decrypted, no need for the cipher 164 // m_xCipherContext = ZipFile::StaticGetCipher( xFactory, rData, false ); 165 } 166 167 XUnbufferedStream::~XUnbufferedStream() 168 { 169 } 170 171 sal_Int32 SAL_CALL XUnbufferedStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) 172 throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) 173 { 174 ::osl::MutexGuard aGuard( maMutexHolder->GetMutex() ); 175 176 sal_Int32 nRequestedBytes = nBytesToRead; 177 OSL_ENSURE( !mnHeaderToRead || mbWrappedRaw, "Only encrypted raw stream can be provided with header!" ); 178 if ( mnMyCurrent + nRequestedBytes > mnZipSize + maHeader.getLength() ) 179 nRequestedBytes = static_cast < sal_Int32 > ( mnZipSize + maHeader.getLength() - mnMyCurrent ); 180 181 sal_Int32 nRead = 0, nLastRead = 0, nTotal = 0; 182 aData.realloc ( nRequestedBytes ); 183 if ( nRequestedBytes ) 184 { 185 if ( mbRawStream ) 186 { 187 sal_Int64 nDiff = mnZipEnd - mnZipCurrent; 188 189 if ( mbWrappedRaw && mnHeaderToRead ) 190 { 191 sal_Int16 nHeadRead = static_cast< sal_Int16 >(( nRequestedBytes > mnHeaderToRead ? 192 mnHeaderToRead : nRequestedBytes )); 193 rtl_copyMemory ( aData.getArray(), maHeader.getConstArray() + maHeader.getLength() - mnHeaderToRead, nHeadRead ); 194 mnHeaderToRead = mnHeaderToRead - nHeadRead; 195 196 if ( nHeadRead < nRequestedBytes ) 197 { 198 sal_Int32 nToRead = nRequestedBytes - nHeadRead; 199 nToRead = ( nDiff < nToRead ) ? sal::static_int_cast< sal_Int32 >( nDiff ) : nToRead; 200 201 Sequence< sal_Int8 > aPureData( nToRead ); 202 mxZipSeek->seek ( mnZipCurrent ); 203 nRead = mxZipStream->readBytes ( aPureData, nToRead ); 204 mnZipCurrent += nRead; 205 206 aPureData.realloc( nRead ); 207 if ( mbCheckCRC ) 208 maCRC.update( aPureData ); 209 210 aData.realloc( nHeadRead + nRead ); 211 212 sal_Int8* pPureBuffer = aPureData.getArray(); 213 sal_Int8* pBuffer = aData.getArray(); 214 for ( sal_Int32 nInd = 0; nInd < nRead; nInd++ ) 215 pBuffer[ nHeadRead + nInd ] = pPureBuffer[ nInd ]; 216 } 217 218 nRead += nHeadRead; 219 } 220 else 221 { 222 mxZipSeek->seek ( mnZipCurrent ); 223 224 nRead = mxZipStream->readBytes ( 225 aData, 226 static_cast < sal_Int32 > ( nDiff < nRequestedBytes ? nDiff : nRequestedBytes ) ); 227 228 mnZipCurrent += nRead; 229 230 aData.realloc( nRead ); 231 if ( mbWrappedRaw && mbCheckCRC ) 232 maCRC.update( aData ); 233 } 234 } 235 else 236 { 237 while ( 0 == ( nLastRead = maInflater.doInflateSegment( aData, nRead, aData.getLength() - nRead ) ) || 238 ( nRead + nLastRead != nRequestedBytes && mnZipCurrent < mnZipEnd ) ) 239 { 240 nRead += nLastRead; 241 242 if ( nRead > nRequestedBytes ) 243 throw RuntimeException( 244 OUString( RTL_CONSTASCII_USTRINGPARAM( "Should not be possible to read more then requested!" ) ), 245 Reference< XInterface >() ); 246 247 if ( maInflater.finished() || maInflater.getLastInflateError() ) 248 throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ), 249 Reference< XInterface >() ); 250 251 if ( maInflater.needsDictionary() ) 252 throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "Dictionaries are not supported!" ) ), 253 Reference< XInterface >() ); 254 255 sal_Int32 nDiff = static_cast< sal_Int32 >( mnZipEnd - mnZipCurrent ); 256 if ( nDiff > 0 ) 257 { 258 mxZipSeek->seek ( mnZipCurrent ); 259 260 sal_Int32 nToRead = std::max( nRequestedBytes, static_cast< sal_Int32 >( 8192 ) ); 261 if ( mnBlockSize > 1 ) 262 nToRead = nToRead + mnBlockSize - nToRead % mnBlockSize; 263 nToRead = std::min( nDiff, nToRead ); 264 265 sal_Int32 nZipRead = mxZipStream->readBytes( maCompBuffer, nToRead ); 266 if ( nZipRead < nToRead ) 267 throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "No expected data!" ) ), 268 Reference< XInterface >() ); 269 270 mnZipCurrent += nZipRead; 271 // maCompBuffer now has the data, check if we need to decrypt 272 // before passing to the Inflater 273 if ( m_xCipherContext.is() ) 274 { 275 if ( mbCheckCRC ) 276 maCRC.update( maCompBuffer ); 277 278 maCompBuffer = m_xCipherContext->convertWithCipherContext( maCompBuffer ); 279 if ( mnZipCurrent == mnZipEnd ) 280 { 281 uno::Sequence< sal_Int8 > aSuffix = m_xCipherContext->finalizeCipherContextAndDispose(); 282 if ( aSuffix.getLength() ) 283 { 284 sal_Int32 nOldLen = maCompBuffer.getLength(); 285 maCompBuffer.realloc( nOldLen + aSuffix.getLength() ); 286 rtl_copyMemory( maCompBuffer.getArray() + nOldLen, aSuffix.getConstArray(), aSuffix.getLength() ); 287 } 288 } 289 } 290 maInflater.setInput ( maCompBuffer ); 291 } 292 else 293 { 294 throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ), 295 Reference< XInterface >() ); 296 } 297 } 298 } 299 300 mnMyCurrent += nRead + nLastRead; 301 nTotal = nRead + nLastRead; 302 if ( nTotal < nRequestedBytes) 303 aData.realloc ( nTotal ); 304 305 if ( mbCheckCRC && ( !mbRawStream || mbWrappedRaw ) ) 306 { 307 if ( !m_xCipherContext.is() && !mbWrappedRaw ) 308 maCRC.update( aData ); 309 310 #if 0 311 // for debugging purposes here 312 if ( mbWrappedRaw ) 313 { 314 if ( 0 ) 315 { 316 uno::Reference< lang::XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); 317 uno::Reference< ucb::XSimpleFileAccess > xAccess( xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY ); 318 uno::Reference< io::XOutputStream > xOut = xAccess->openFileWrite( ::rtl::OUString::createFromAscii( "file:///d:/777/Encrypted/picture" ) ); 319 xOut->writeBytes( aData ); 320 xOut->closeOutput(); 321 } 322 } 323 #endif 324 325 if ( mnZipSize + maHeader.getLength() == mnMyCurrent && maCRC.getValue() != maEntry.nCrc ) 326 throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ), 327 Reference< XInterface >() ); 328 } 329 } 330 331 return nTotal; 332 } 333 334 sal_Int32 SAL_CALL XUnbufferedStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) 335 throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) 336 { 337 return readBytes ( aData, nMaxBytesToRead ); 338 } 339 void SAL_CALL XUnbufferedStream::skipBytes( sal_Int32 nBytesToSkip ) 340 throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) 341 { 342 if ( nBytesToSkip ) 343 { 344 Sequence < sal_Int8 > aSequence ( nBytesToSkip ); 345 readBytes ( aSequence, nBytesToSkip ); 346 } 347 } 348 349 sal_Int32 SAL_CALL XUnbufferedStream::available( ) 350 throw( NotConnectedException, IOException, RuntimeException) 351 { 352 return static_cast < sal_Int32 > ( mnZipSize - mnMyCurrent ); 353 } 354 355 void SAL_CALL XUnbufferedStream::closeInput( ) 356 throw( NotConnectedException, IOException, RuntimeException) 357 { 358 } 359 /* 360 void SAL_CALL XUnbufferedStream::seek( sal_Int64 location ) 361 throw( IllegalArgumentException, IOException, RuntimeException) 362 { 363 } 364 sal_Int64 SAL_CALL XUnbufferedStream::getPosition( ) 365 throw(IOException, RuntimeException) 366 { 367 return mnMyCurrent; 368 } 369 sal_Int64 SAL_CALL XUnbufferedStream::getLength( ) 370 throw(IOException, RuntimeException) 371 { 372 return mnZipSize; 373 } 374 */ 375