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