From 72f0ada28f17b0079d296fa6dbc98d3b76b058a3 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 20 Sep 2016 22:37:31 +0100 Subject: [PATCH] allow decorators to be used in SheetDataWriter and use ZipEntrySource in SXSSFWorkbook to allow custom implementations to be used instead of raw ZipFile --- .../org/apache/poi/xssf/streaming/SXSSFWorkbook.java | 18 +++++++++--------- .../org/apache/poi/xssf/streaming/SheetDataWriter.java | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java index 331ad9a..23032c6 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java @@ -35,6 +35,8 @@ import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.openxml4j.util.ZipEntrySource; +import org.apache.poi.openxml4j.util.ZipFileZipEntrySource; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.formula.udf.UDFFinder; import org.apache.poi.ss.usermodel.CellStyle; @@ -101,12 +103,12 @@ public class SXSSFWorkbook implements Workbook { /** * whether temp files should be compressed. */ - private boolean _compressTmpFiles = false; + protected boolean _compressTmpFiles = false; /** * shared string table - a cache of strings in this workbook */ - private final SharedStringsTable _sharedStringSource; + protected final SharedStringsTable _sharedStringSource; /** * Construct a new workbook with default row window size @@ -353,21 +355,19 @@ public class SXSSFWorkbook implements Workbook { return null; } - private void injectData(File zipfile, OutputStream out) throws IOException + private void injectData(ZipEntrySource zipEntrySource, OutputStream out) throws IOException { - // don't use ZipHelper.openZipFile here - see #59743 - ZipFile zip = new ZipFile(zipfile); try { ZipOutputStream zos = new ZipOutputStream(out); try { - Enumeration en = zip.entries(); + Enumeration en = zipEntrySource.getEntries(); while (en.hasMoreElements()) { ZipEntry ze = en.nextElement(); zos.putNextEntry(new ZipEntry(ze.getName())); - InputStream is = zip.getInputStream(ze); + InputStream is = zipEntrySource.getInputStream(ze); XSSFSheet xSheet=getSheetFromZipEntryName(ze.getName()); if(xSheet!=null) { @@ -396,7 +396,7 @@ public class SXSSFWorkbook implements Workbook { } finally { - zip.close(); + zipEntrySource.close(); } } private static void copyStream(InputStream in, OutputStream out) throws IOException { @@ -946,7 +946,7 @@ public class SXSSFWorkbook implements Workbook { } //Substitute the template entries with the generated sheet data files - injectData(tmplFile, stream); + injectData(new ZipFileZipEntrySource(new ZipFile(tmplFile)), stream); } finally { diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java index 4bd0c6b..54c6f4f 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java @@ -25,6 +25,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.Iterator; @@ -90,8 +91,12 @@ public class SheetDataWriter { * * @param fd the file to write to */ - public Writer createWriter(File fd)throws IOException { - return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fd), "UTF-8")); + public Writer createWriter(File fd) throws IOException { + return new BufferedWriter(new OutputStreamWriter(decorateOutputStream(new FileOutputStream(fd)), "UTF-8")); + } + + protected OutputStream decorateOutputStream(FileOutputStream fos) { + return fos; } /** @@ -112,7 +117,11 @@ public class SheetDataWriter { */ public InputStream getWorksheetXMLInputStream() throws IOException { File fd = getTempFile(); - return new FileInputStream(fd); + return decorateInputStream(new FileInputStream(fd)); + } + + protected InputStream decorateInputStream(FileInputStream fis) { + return fis; } public int getNumberOfFlushedRows() { -- 2.2.1 From 333d1af99908a42394608feb8d462ebae99efc7e Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 21 Sep 2016 00:10:06 +0100 Subject: [PATCH] add test case for encrypting temp file data --- .../apache/poi/xssf/streaming/SXSSFWorkbook.java | 18 +-- .../poi/poifs/crypt/AesZipFileZipEntrySource.java | 118 +++++++++++++++++ .../apache/poi/poifs/crypt/TestSecureTempZip.java | 106 +--------------- .../TestSXSSFWorkbookWithCustomZipEntrySource.java | 140 +++++++++++++++++++++ 4 files changed, 270 insertions(+), 112 deletions(-) create mode 100644 src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java create mode 100644 src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java index 23032c6..82768ae 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java @@ -93,7 +93,7 @@ public class SXSSFWorkbook implements Workbook { public static final int DEFAULT_WINDOW_SIZE = 100; private static final POILogger logger = POILogFactory.getLogger(SXSSFWorkbook.class); - private final XSSFWorkbook _wb; + protected final XSSFWorkbook _wb; private final Map _sxFromXHash = new HashMap(); private final Map _xFromSxHash = new HashMap(); @@ -306,7 +306,7 @@ public class SXSSFWorkbook implements Workbook { _compressTmpFiles = compress; } - SheetDataWriter createSheetDataWriter() throws IOException { + protected SheetDataWriter createSheetDataWriter() throws IOException { if(_compressTmpFiles) { return new GZIPSheetDataWriter(_sharedStringSource); } @@ -355,7 +355,7 @@ public class SXSSFWorkbook implements Workbook { return null; } - private void injectData(ZipEntrySource zipEntrySource, OutputStream out) throws IOException + protected void injectData(ZipEntrySource zipEntrySource, OutputStream out) throws IOException { try { @@ -926,10 +926,7 @@ public class SXSSFWorkbook implements Workbook { @Override public void write(OutputStream stream) throws IOException { - for (SXSSFSheet sheet : _xFromSxHash.values()) - { - sheet.flushRows(); - } + flushSheets(); //Save the template File tmplFile = TempFile.createTempFile("poi-sxssf-template", ".xlsx"); @@ -956,6 +953,13 @@ public class SXSSFWorkbook implements Workbook { } } + protected void flushSheets() throws IOException { + for (SXSSFSheet sheet : _xFromSxHash.values()) + { + sheet.flushRows(); + } + } + /** * Dispose of temporary files backing this workbook on disk. * Calling this method will render the workbook unusable. diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java new file mode 100644 index 0000000..fd15cfd --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java @@ -0,0 +1,118 @@ +package org.apache.poi.poifs.crypt; + +import java.io.File; +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.util.ZipEntrySource; +import org.apache.poi.util.IOUtils; +import org.apache.poi.util.TempFile; + +public class AesZipFileZipEntrySource implements ZipEntrySource { + final File tmpFile; + final ZipFile zipFile; + final Cipher ci; + boolean closed; + + public AesZipFileZipEntrySource(File tmpFile, Cipher ci) throws IOException { + this.tmpFile = tmpFile; + this.zipFile = new ZipFile(tmpFile); + this.ci = ci; + this.closed = false; + } + + /** + * 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 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(); + tmpFile.delete(); + closed = true; + } + + @Override + public boolean isClosed() { + return closed; + } + + public static ZipEntrySource createZipEntrySource(InputStream is) throws IOException, GeneralSecurityException { + // generate session key + SecureRandom sr = new SecureRandom(); + byte[] ivBytes = new byte[16], keyBytes = new byte[16]; + sr.nextBytes(ivBytes); + sr.nextBytes(keyBytes); + final File tmpFile = TempFile.createTempFile("protectedXlsx", ".zip"); + copyToFile(is, tmpFile, CipherAlgorithm.aes128, keyBytes, ivBytes); + IOUtils.closeQuietly(is); + return fileToSource(tmpFile, CipherAlgorithm.aes128, keyBytes, ivBytes); + } + + private static 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 static 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"); + return new AesZipFileZipEntrySource(tmpFile, ciDec); + } + +} + diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java index 868a382..77ae003 100644 --- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java +++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java @@ -22,30 +22,14 @@ 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.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.util.TempFile; import org.apache.poi.xssf.XSSFTestDataSamples; import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor; import org.apache.poi.xssf.usermodel.XSSFWorkbook; @@ -59,7 +43,6 @@ public class TestSecureTempZip { */ @Test public void protectedTempZip() throws IOException, GeneralSecurityException, XmlException, OpenXML4JException { - final File tmpFile = TempFile.createTempFile("protectedXlsx", ".zip"); File tikaProt = XSSFTestDataSamples.getSampleFile("protected_passtika.xlsx"); FileInputStream fis = new FileInputStream(tikaProt); POIFSFileSystem poifs = new POIFSFileSystem(fis); @@ -68,19 +51,11 @@ public class TestSecureTempZip { 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); + ZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(is); // test the source OPCPackage opc = OPCPackage.open(source); @@ -102,84 +77,5 @@ public class TestSecureTempZip { source.close(); poifs.close(); fis.close(); - tmpFile.delete(); - } - - 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; - boolean closed; - - AesZipFileZipEntrySource(ZipFile zipFile, Cipher ci) { - this.zipFile = zipFile; - this.ci = ci; - this.closed = false; - } - - /** - * 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 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(); - closed = true; - } - - @Override - public boolean isClosed() { - return closed; - } } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java b/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java new file mode 100644 index 0000000..4831b74 --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java @@ -0,0 +1,140 @@ +/* + * ==================================================================== + * 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.xssf.streaming; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.poi.openxml4j.util.ZipEntrySource; +import org.apache.poi.poifs.crypt.AesZipFileZipEntrySource; +import org.apache.poi.poifs.crypt.ChainingMode; +import org.apache.poi.poifs.crypt.CipherAlgorithm; +import org.apache.poi.poifs.crypt.CryptoFunctions; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.Test; + +public final class TestSXSSFWorkbookWithCustomZipEntrySource { + + @Test + public void customZipEntrySource() throws IOException, GeneralSecurityException { + final String sheetName = "TestSheet1"; + final String cellValue = "customZipEntrySource"; + SXSSFWorkbookWithCustomZipEntrySource workbook = new SXSSFWorkbookWithCustomZipEntrySource(); + SXSSFSheet sheet1 = workbook.createSheet(sheetName); + SXSSFRow row1 = sheet1.createRow(1); + SXSSFCell cell1 = row1.createCell(1); + cell1.setCellValue("customZipEntrySource"); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + workbook.write(os); + workbook.close(); + workbook.dispose(); + XSSFWorkbook xwb = new XSSFWorkbook(new ByteArrayInputStream(os.toByteArray())); + XSSFSheet xs1 = xwb.getSheetAt(0); + assertEquals(sheetName, xs1.getSheetName()); + XSSFRow xr1 = xs1.getRow(1); + XSSFCell xc1 = xr1.getCell(1); + assertEquals(cellValue, xc1.getStringCellValue()); + xwb.close(); + } + + static class SXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbook { + + private static final POILogger logger = POILogFactory.getLogger(SXSSFWorkbookWithCustomZipEntrySource.class); + + @Override + public void write(OutputStream stream) throws IOException { + flushSheets(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + _wb.write(os); + ZipEntrySource source = null; + try { + // provide ZipEntrySource to poi which decrypts on the fly + source = AesZipFileZipEntrySource.createZipEntrySource(new ByteArrayInputStream(os.toByteArray())); + injectData(source, stream); + } catch (GeneralSecurityException e) { + throw new IOException(e); + } finally { + source.close(); + } + } + + @Override + protected SheetDataWriter createSheetDataWriter() throws IOException { + //log values to ensure these values are accessible to subclasses + logger.log(POILogger.INFO, "_compressTmpFiles: " + _compressTmpFiles); + logger.log(POILogger.INFO, "_sharedStringSource: " + _sharedStringSource); + return new SheetDataWriterWithDecorator(); + } + } + + static class SheetDataWriterWithDecorator extends SheetDataWriter { + final static CipherAlgorithm cipherAlgorithm = CipherAlgorithm.aes128; + SecretKeySpec skeySpec; + byte[] ivBytes; + + public SheetDataWriterWithDecorator() throws IOException { + super(); + } + + void init() { + if(skeySpec == null) { + SecureRandom sr = new SecureRandom(); + ivBytes = new byte[16]; + byte[] keyBytes = new byte[16]; + sr.nextBytes(ivBytes); + sr.nextBytes(keyBytes); + skeySpec = new SecretKeySpec(keyBytes, cipherAlgorithm.jceId); + } + } + + @Override + protected OutputStream decorateOutputStream(FileOutputStream fos) { + init(); + Cipher ciEnc = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.ENCRYPT_MODE, "PKCS5Padding"); + return new CipherOutputStream(fos, ciEnc); + } + + @Override + protected InputStream decorateInputStream(FileInputStream fis) { + Cipher ciDec = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.DECRYPT_MODE, "PKCS5Padding"); + return new CipherInputStream(fis, ciDec); + } + + } +} -- 2.2.1