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