ASF Bugzilla – Attachment 34047 Details for
Bug 59841
ZipInputStreamZipEntrySource should use temp files instead of ByteArrayOutputStream
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
new OPCPackage.open(ZipEntrySource) method / custom encrypted temp zip
custom-encrypted-temp-zip.diff (text/plain), 10.95 KB, created by
Andreas Beeker
on 2016-07-16 23:53:18 UTC
(
hide
)
Description:
new OPCPackage.open(ZipEntrySource) method / custom encrypted temp zip
Filename:
MIME Type:
Creator:
Andreas Beeker
Created:
2016-07-16 23:53:18 UTC
Size:
10.95 KB
patch
obsolete
>Index: src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java >=================================================================== >--- src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java (revision 1752865) >+++ src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java (working copy) >@@ -53,6 +53,7 @@ > import org.apache.poi.openxml4j.opc.internal.unmarshallers.PackagePropertiesUnmarshaller; > import org.apache.poi.openxml4j.opc.internal.unmarshallers.UnmarshallContext; > import org.apache.poi.openxml4j.util.Nullable; >+import org.apache.poi.openxml4j.util.ZipEntrySource; > import org.apache.poi.util.NotImplemented; > import org.apache.poi.util.POILogFactory; > import org.apache.poi.util.POILogger; >@@ -200,6 +201,42 @@ > return open(file, defaultPackageAccess); > } > >+ /** >+ * Open an user provided {@link ZipEntrySource} with read-only permission. >+ * This method can be used to stream data into POI. >+ * Opposed to other open variants, the data is read as-is, e.g. there aren't >+ * any zip-bomb protection put in place. >+ * >+ * @param zipEntry the custom source >+ * @return A Package object >+ * @throws InvalidFormatException if a parsing error occur. >+ */ >+ public static OPCPackage open(ZipEntrySource zipEntry) >+ throws InvalidFormatException { >+ OPCPackage pack = new ZipPackage(zipEntry, PackageAccess.READ); >+ try { >+ if (pack.partList == null) { >+ pack.getParts(); >+ } >+ // pack.originalPackagePath = file.getAbsolutePath(); >+ return pack; >+ } catch (InvalidFormatException e) { >+ try { >+ pack.close(); >+ } catch (IOException e1) { >+ throw new IllegalStateException(e); >+ } >+ throw e; >+ } catch (RuntimeException e) { >+ try { >+ pack.close(); >+ } catch (IOException e1) { >+ throw new IllegalStateException(e); >+ } >+ throw e; >+ } >+ } >+ > /** > * Open a package. > * >Index: src/ooxml/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java >=================================================================== >--- src/ooxml/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java (revision 1752865) >+++ src/ooxml/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java (working copy) >@@ -20,6 +20,7 @@ > > import java.io.IOException; > import java.io.InputStream; >+import java.io.PushbackInputStream; > import java.util.ArrayList; > import java.util.List; > >@@ -140,8 +141,11 @@ > * @throws ParserConfigurationException > */ > public void readFrom(InputStream is) throws IOException, SAXException { >- if (is.available() > 0) { >- InputSource sheetSource = new InputSource(is); >+ PushbackInputStream pis = new PushbackInputStream(is, 1); >+ int emptyTest = pis.read(); >+ if (emptyTest > -1) { >+ pis.unread(emptyTest); >+ InputSource sheetSource = new InputSource(pis); > try { > XMLReader sheetParser = SAXHelper.newXMLReader(); > sheetParser.setContentHandler(this); >Index: src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java >=================================================================== >--- src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java (nonexistent) >+++ src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java (working copy) >@@ -0,0 +1,172 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.poifs.crypt; >+ >+import static org.junit.Assert.assertEquals; >+import static org.junit.Assert.assertTrue; >+ >+import java.io.File; >+import java.io.FileInputStream; >+import java.io.FileOutputStream; >+import java.io.FilterOutputStream; >+import java.io.IOException; >+import java.io.InputStream; >+import java.security.GeneralSecurityException; >+import java.security.SecureRandom; >+import java.util.Enumeration; >+import java.util.zip.ZipEntry; >+import java.util.zip.ZipException; >+import java.util.zip.ZipFile; >+import java.util.zip.ZipInputStream; >+import java.util.zip.ZipOutputStream; >+ >+import javax.crypto.Cipher; >+import javax.crypto.CipherInputStream; >+import javax.crypto.CipherOutputStream; >+import javax.crypto.spec.SecretKeySpec; >+ >+import org.apache.poi.openxml4j.exceptions.InvalidFormatException; >+import org.apache.poi.openxml4j.exceptions.OpenXML4JException; >+import org.apache.poi.openxml4j.opc.OPCPackage; >+import org.apache.poi.openxml4j.util.ZipEntrySource; >+import org.apache.poi.poifs.filesystem.POIFSFileSystem; >+import org.apache.poi.util.IOUtils; >+import org.apache.poi.xssf.XSSFTestDataSamples; >+import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor; >+import org.apache.poi.xssf.usermodel.XSSFWorkbook; >+import org.apache.xmlbeans.XmlException; >+import org.junit.Test; >+ >+public class TestSecureTempZip { >+ @Test >+ public void protectedTempZip() throws IOException, GeneralSecurityException, XmlException, OpenXML4JException { >+ final File tmpFile = new File("build/tmp", "protectedXlsx.zip"); >+ File tikaProt = XSSFTestDataSamples.getSampleFile("protected_passtika.xlsx"); >+ FileInputStream fis = new FileInputStream(tikaProt); >+ POIFSFileSystem poifs = new POIFSFileSystem(fis); >+ EncryptionInfo ei = new EncryptionInfo(poifs); >+ Decryptor dec = ei.getDecryptor(); >+ boolean passOk = dec.verifyPassword("tika"); >+ assertTrue(passOk); >+ >+ // generate session key >+ SecureRandom sr = new SecureRandom(); >+ byte[] ivBytes = new byte[16], keyBytes = new byte[16]; >+ sr.nextBytes(ivBytes); >+ sr.nextBytes(keyBytes); >+ >+ // extract encrypted ooxml file and write to custom encrypted zip file >+ InputStream is = dec.getDataStream(poifs); >+ copyToFile(is, tmpFile, CipherAlgorithm.aes128, keyBytes, ivBytes); >+ is.close(); >+ >+ // provide ZipEntrySource to poi which decrypts on the fly >+ ZipEntrySource source = fileToSource(tmpFile, CipherAlgorithm.aes128, keyBytes, ivBytes); >+ >+ // test the source >+ OPCPackage opc = OPCPackage.open(source); >+ String expected = "This is an Encrypted Excel spreadsheet."; >+ >+ XSSFEventBasedExcelExtractor extractor = new XSSFEventBasedExcelExtractor(opc); >+ extractor.setIncludeSheetNames(false); >+ String txt = extractor.getText(); >+ assertEquals(expected, txt.trim()); >+ >+ XSSFWorkbook wb = new XSSFWorkbook(opc); >+ txt = wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue(); >+ assertEquals(expected, txt); >+ >+ extractor.close(); >+ >+ wb.close(); >+ opc.close(); >+ source.close(); >+ poifs.close(); >+ fis.close(); >+ } >+ >+ private void copyToFile(InputStream is, File tmpFile, CipherAlgorithm cipherAlgorithm, byte keyBytes[], byte ivBytes[]) throws IOException, GeneralSecurityException { >+ SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, cipherAlgorithm.jceId); >+ Cipher ciEnc = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.ENCRYPT_MODE, "PKCS5Padding"); >+ >+ ZipInputStream zis = new ZipInputStream(is); >+ FileOutputStream fos = new FileOutputStream(tmpFile); >+ ZipOutputStream zos = new ZipOutputStream(fos); >+ >+ ZipEntry ze; >+ while ((ze = zis.getNextEntry()) != null) { >+ // the cipher output stream pads the data, therefore we can't reuse the ZipEntry with set sizes >+ // as those will be validated upon close() >+ ZipEntry zeNew = new ZipEntry(ze.getName()); >+ zeNew.setComment(ze.getComment()); >+ zeNew.setExtra(ze.getExtra()); >+ zeNew.setTime(ze.getTime()); >+ // zeNew.setMethod(ze.getMethod()); >+ zos.putNextEntry(zeNew); >+ FilterOutputStream fos2 = new FilterOutputStream(zos){ >+ // don't close underlying ZipOutputStream >+ public void close() {} >+ }; >+ CipherOutputStream cos = new CipherOutputStream(fos2, ciEnc); >+ IOUtils.copy(zis, cos); >+ cos.close(); >+ fos2.close(); >+ zos.closeEntry(); >+ zis.closeEntry(); >+ } >+ zos.close(); >+ fos.close(); >+ zis.close(); >+ } >+ >+ private ZipEntrySource fileToSource(File tmpFile, CipherAlgorithm cipherAlgorithm, byte keyBytes[], byte ivBytes[]) throws ZipException, IOException { >+ SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, cipherAlgorithm.jceId); >+ Cipher ciDec = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.DECRYPT_MODE, "PKCS5Padding"); >+ ZipFile zf = new ZipFile(tmpFile); >+ return new AesZipFileZipEntrySource(zf, ciDec); >+ } >+ >+ static class AesZipFileZipEntrySource implements ZipEntrySource { >+ final ZipFile zipFile; >+ final Cipher ci; >+ >+ AesZipFileZipEntrySource(ZipFile zipFile, Cipher ci) { >+ this.zipFile = zipFile; >+ this.ci = ci; >+ } >+ >+ /** >+ * Note: the file sizes are rounded up to the next cipher block size, >+ * so don't rely on file sizes of these custom encrypted zip file entries! >+ */ >+ public Enumeration<? extends ZipEntry> getEntries() { >+ return zipFile.entries(); >+ } >+ >+ @SuppressWarnings("resource") >+ public InputStream getInputStream(ZipEntry entry) throws IOException { >+ InputStream is = zipFile.getInputStream(entry); >+ return new CipherInputStream(is, ci); >+ } >+ >+ @Override >+ public void close() throws IOException { >+ zipFile.close(); >+ } >+ } >+} > >Property changes on: src\ooxml\testcases\org\apache\poi\poifs\crypt\TestSecureTempZip.java >___________________________________________________________________ >Added: svn:eol-style >## -0,0 +1 ## >+native
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 59841
:
34046
| 34047