From 776621c3bb18ccdd75f11d3e263d255616bf60d1 Mon Sep 17 00:00:00 2001 From: Javen O'Neal Date: Tue, 8 Nov 2016 17:32:38 +0000 Subject: [PATCH] bug 60321: add examples with encrypted temp data. Patch from PJ Fanning. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1768744 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/AesZipFileZipEntrySource.java | 147 ++++++++++++++++++ .../poi/crypt/examples/EncryptedTempData.java | 72 +++++++++ .../poi/crypt/examples/EncryptionUtils.java | 43 +++++ .../poi/examples/util/TempFileUtils.java | 43 +++++ .../LoadPasswordProtectedXlsxStreaming.java | 88 +++++++++++ ...SXSSFWorkbookWithCustomZipEntrySource.java | 113 ++++++++++++++ .../examples/SavePasswordProtectedXlsx.java | 112 +++++++++++++ .../examples/LoadPasswordProtectedXlsx.java | 85 ++++++++++ 8 files changed, 703 insertions(+) create mode 100644 src/examples/src/org/apache/poi/crypt/examples/AesZipFileZipEntrySource.java create mode 100644 src/examples/src/org/apache/poi/crypt/examples/EncryptedTempData.java create mode 100644 src/examples/src/org/apache/poi/crypt/examples/EncryptionUtils.java create mode 100644 src/examples/src/org/apache/poi/examples/util/TempFileUtils.java create mode 100644 src/examples/src/org/apache/poi/xssf/eventusermodel/examples/LoadPasswordProtectedXlsxStreaming.java create mode 100644 src/examples/src/org/apache/poi/xssf/streaming/examples/SXSSFWorkbookWithCustomZipEntrySource.java create mode 100644 src/examples/src/org/apache/poi/xssf/streaming/examples/SavePasswordProtectedXlsx.java create mode 100644 src/examples/src/org/apache/poi/xssf/usermodel/examples/LoadPasswordProtectedXlsx.java diff --git a/src/examples/src/org/apache/poi/crypt/examples/AesZipFileZipEntrySource.java b/src/examples/src/org/apache/poi/crypt/examples/AesZipFileZipEntrySource.java new file mode 100644 index 0000000000..af281e2590 --- /dev/null +++ b/src/examples/src/org/apache/poi/crypt/examples/AesZipFileZipEntrySource.java @@ -0,0 +1,147 @@ +/* + * ==================================================================== + * 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.crypt.examples; + +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.poifs.crypt.ChainingMode; +import org.apache.poi.poifs.crypt.CipherAlgorithm; +import org.apache.poi.poifs.crypt.CryptoFunctions; +import org.apache.poi.util.IOUtils; +import org.apache.poi.util.TempFile; + +/** + * An example ZipEntrySource that has encrypted temp files to ensure that + * sensitive data is not stored in raw format on disk. + */ +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! + */ + @Override + public Enumeration getEntries() { + return zipFile.entries(); + } + + @Override + public InputStream getInputStream(ZipEntry entry) throws IOException { + InputStream is = zipFile.getInputStream(entry); + return new CipherInputStream(is, ci); + } + + @Override + public void close() throws IOException { + if(!closed) { + zipFile.close(); + tmpFile.delete(); + } + closed = true; + } + + @Override + public boolean isClosed() { + return closed; + } + + public static AesZipFileZipEntrySource 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 + @Override + 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 AesZipFileZipEntrySource 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); + } + +} \ No newline at end of file diff --git a/src/examples/src/org/apache/poi/crypt/examples/EncryptedTempData.java b/src/examples/src/org/apache/poi/crypt/examples/EncryptedTempData.java new file mode 100644 index 0000000000..e4c5796d6f --- /dev/null +++ b/src/examples/src/org/apache/poi/crypt/examples/EncryptedTempData.java @@ -0,0 +1,72 @@ +/* + * ==================================================================== + * 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.crypt.examples; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +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.poifs.crypt.ChainingMode; +import org.apache.poi.poifs.crypt.CipherAlgorithm; +import org.apache.poi.poifs.crypt.CryptoFunctions; +import org.apache.poi.util.TempFile; + +/** + * EncryptedTempData can be used to buffer binary data in a secure way, by using encrypted temp files. + */ +public class EncryptedTempData { + final static CipherAlgorithm cipherAlgorithm = CipherAlgorithm.aes128; + final SecretKeySpec skeySpec; + final byte[] ivBytes; + final File tempFile; + + public EncryptedTempData() throws IOException { + 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); + tempFile = TempFile.createTempFile("poi-temp-data", ".tmp"); + } + + public OutputStream getOutputStream() throws IOException { + Cipher ciEnc = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.ENCRYPT_MODE, null); + return new CipherOutputStream(new FileOutputStream(tempFile), ciEnc); + } + + public InputStream getInputStream() throws IOException { + Cipher ciDec = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.DECRYPT_MODE, null); + return new CipherInputStream(new FileInputStream(tempFile), ciDec); + } + + public void dispose() { + tempFile.delete(); + } +} diff --git a/src/examples/src/org/apache/poi/crypt/examples/EncryptionUtils.java b/src/examples/src/org/apache/poi/crypt/examples/EncryptionUtils.java new file mode 100644 index 0000000000..acbfdd1890 --- /dev/null +++ b/src/examples/src/org/apache/poi/crypt/examples/EncryptionUtils.java @@ -0,0 +1,43 @@ +/* + * ==================================================================== + * 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.crypt.examples; + +import java.io.InputStream; + +import org.apache.poi.poifs.crypt.Decryptor; +import org.apache.poi.poifs.crypt.EncryptionInfo; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.util.IOUtils; + +public class EncryptionUtils { + public static InputStream decrypt(final InputStream inputStream, final String pwd) throws Exception { + try { + POIFSFileSystem fs = new POIFSFileSystem(inputStream); + EncryptionInfo info = new EncryptionInfo(fs); + Decryptor d = Decryptor.getInstance(info); + if (!d.verifyPassword(pwd)) { + throw new RuntimeException("incorrect password"); + } + return d.getDataStream(fs); + } finally { + IOUtils.closeQuietly(inputStream); + } + } +} diff --git a/src/examples/src/org/apache/poi/examples/util/TempFileUtils.java b/src/examples/src/org/apache/poi/examples/util/TempFileUtils.java new file mode 100644 index 0000000000..f34f35d3cb --- /dev/null +++ b/src/examples/src/org/apache/poi/examples/util/TempFileUtils.java @@ -0,0 +1,43 @@ +/* + * ==================================================================== + * 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.examples.util; + +import java.io.File; +import java.io.IOException; + +import org.apache.poi.util.TempFile; + +public class TempFileUtils { + public static void checkTempFiles() throws IOException { + String tmpDir = System.getProperty(TempFile.JAVA_IO_TMPDIR) + "/poifiles"; + File tempDir = new File(tmpDir); + if(tempDir.exists()) { + String[] tempFiles = tempDir.list(); + if(tempFiles.length > 0) { + System.out.println("found files in poi temp dir " + tempDir.getAbsolutePath()); + for(String filename : tempDir.list()) { + System.out.println("file: " + filename); + } + } + } else { + System.out.println("unable to find poi temp dir"); + } + } +} diff --git a/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/LoadPasswordProtectedXlsxStreaming.java b/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/LoadPasswordProtectedXlsxStreaming.java new file mode 100644 index 0000000000..aa7d0ceee7 --- /dev/null +++ b/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/LoadPasswordProtectedXlsxStreaming.java @@ -0,0 +1,88 @@ +/* + * ==================================================================== + * 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.eventusermodel.examples; + +import java.io.FileInputStream; +import java.io.InputStream; + +import org.apache.poi.crypt.examples.AesZipFileZipEntrySource; +import org.apache.poi.crypt.examples.EncryptionUtils; +import org.apache.poi.examples.util.TempFileUtils; +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.eventusermodel.XSSFReader; +import org.apache.poi.xssf.eventusermodel.XSSFReader.SheetIterator; + +/** + * An example that loads a password protected workbook and counts the sheets. + * The example highlights how to do this in streaming way. + *

+ */ +public class LoadPasswordProtectedXlsxStreaming { + + public static void main(String[] args) { + try { + if(args.length != 2) { + throw new Exception("Expected 2 params: filename and password"); + } + TempFileUtils.checkTempFiles(); + String filename = args[0]; + String password = args[1]; + FileInputStream fis = new FileInputStream(filename); + try { + InputStream unencryptedStream = EncryptionUtils.decrypt(fis, password); + try { + printSheetCount(unencryptedStream); + } finally { + IOUtils.closeQuietly(unencryptedStream); + } + } finally { + IOUtils.closeQuietly(fis); + } + TempFileUtils.checkTempFiles(); + } catch(Throwable t) { + t.printStackTrace(); + } + } + + public static void printSheetCount(final InputStream inputStream) throws Exception { + AesZipFileZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(inputStream); + try { + OPCPackage pkg = OPCPackage.open(source); + try { + XSSFReader reader = new XSSFReader(pkg); + SheetIterator iter = (SheetIterator)reader.getSheetsData(); + int count = 0; + while(iter.hasNext()) { + iter.next(); + count++; + } + System.out.println("sheet count: " + count); + } finally { + IOUtils.closeQuietly(pkg); + } + } finally { + IOUtils.closeQuietly(source); + } + } +} diff --git a/src/examples/src/org/apache/poi/xssf/streaming/examples/SXSSFWorkbookWithCustomZipEntrySource.java b/src/examples/src/org/apache/poi/xssf/streaming/examples/SXSSFWorkbookWithCustomZipEntrySource.java new file mode 100644 index 0000000000..48f3f3a826 --- /dev/null +++ b/src/examples/src/org/apache/poi/xssf/streaming/examples/SXSSFWorkbookWithCustomZipEntrySource.java @@ -0,0 +1,113 @@ +/* + * ==================================================================== + * 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.examples; + +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.crypt.examples.AesZipFileZipEntrySource; +import org.apache.poi.crypt.examples.EncryptedTempData; +import org.apache.poi.openxml4j.util.ZipEntrySource; +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.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.streaming.SheetDataWriter; + +public class SXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbook { + + public SXSSFWorkbookWithCustomZipEntrySource() { + super(20); + setCompressTempFiles(true); + } + + @Override + public void write(OutputStream stream) throws IOException { + flushSheets(); + EncryptedTempData tempData = new EncryptedTempData(); + ZipEntrySource source = null; + try { + OutputStream os = tempData.getOutputStream(); + try { + getXSSFWorkbook().write(os); + } finally { + IOUtils.closeQuietly(os); + } + // provide ZipEntrySource to poi which decrypts on the fly + source = AesZipFileZipEntrySource.createZipEntrySource(tempData.getInputStream()); + injectData(source, stream); + } catch (GeneralSecurityException e) { + throw new IOException(e); + } finally { + tempData.dispose(); + IOUtils.closeQuietly(source); + } + } + + @Override + protected SheetDataWriter createSheetDataWriter() throws IOException { + 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); + } + } +} diff --git a/src/examples/src/org/apache/poi/xssf/streaming/examples/SavePasswordProtectedXlsx.java b/src/examples/src/org/apache/poi/xssf/streaming/examples/SavePasswordProtectedXlsx.java new file mode 100644 index 0000000000..4c741873a5 --- /dev/null +++ b/src/examples/src/org/apache/poi/xssf/streaming/examples/SavePasswordProtectedXlsx.java @@ -0,0 +1,112 @@ +/* + * ==================================================================== + * 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.examples; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; + +import org.apache.poi.crypt.examples.EncryptedTempData; +import org.apache.poi.examples.util.TempFileUtils; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.poifs.crypt.EncryptionInfo; +import org.apache.poi.poifs.crypt.EncryptionMode; +import org.apache.poi.poifs.crypt.Encryptor; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFCell; +import org.apache.poi.xssf.streaming.SXSSFRow; +import org.apache.poi.xssf.streaming.SXSSFSheet; + +/** + * An example that outputs a simple generated workbook that is password protected. + * The example highlights how to do this in streaming way. + *

+ */ +public class SavePasswordProtectedXlsx { + + public static void main(String[] args) { + try { + if(args.length != 2) { + throw new Exception("Expected 2 params: filename and password"); + } + TempFileUtils.checkTempFiles(); + String filename = args[0]; + String password = args[1]; + SXSSFWorkbookWithCustomZipEntrySource wb = new SXSSFWorkbookWithCustomZipEntrySource(); + try { + for(int i = 0; i < 10; i++) { + SXSSFSheet sheet = wb.createSheet("Sheet" + i); + for(int r = 0; r < 1000; r++) { + SXSSFRow row = sheet.createRow(r); + for(int c = 0; c < 100; c++) { + SXSSFCell cell = row.createCell(c); + cell.setCellValue("abcd"); + } + } + } + EncryptedTempData tempData = new EncryptedTempData(); + try { + wb.write(tempData.getOutputStream()); + save(tempData.getInputStream(), filename, password); + System.out.println("Saved " + filename); + } finally { + tempData.dispose(); + } + } finally { + wb.close(); + wb.dispose(); + } + TempFileUtils.checkTempFiles(); + } catch(Throwable t) { + t.printStackTrace(); + } + } + + public static void save(final InputStream inputStream, final String filename, final String pwd) + throws InvalidFormatException, IOException, GeneralSecurityException { + try { + POIFSFileSystem fs = new POIFSFileSystem(); + EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile); + Encryptor enc = Encryptor.getInstance(info); + enc.confirmPassword(pwd); + OPCPackage opc = OPCPackage.open(inputStream); + try { + FileOutputStream fos = new FileOutputStream(filename); + try { + opc.save(enc.getDataStream(fs)); + fs.writeFilesystem(fos); + } finally { + IOUtils.closeQuietly(fos); + } + } finally { + IOUtils.closeQuietly(opc); + } + } finally { + IOUtils.closeQuietly(inputStream); + } + } + +} diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/LoadPasswordProtectedXlsx.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/LoadPasswordProtectedXlsx.java new file mode 100644 index 0000000000..7bb677bf22 --- /dev/null +++ b/src/examples/src/org/apache/poi/xssf/usermodel/examples/LoadPasswordProtectedXlsx.java @@ -0,0 +1,85 @@ +/* + * ==================================================================== + * 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.usermodel.examples; + +import java.io.FileInputStream; +import java.io.InputStream; + +import org.apache.poi.crypt.examples.AesZipFileZipEntrySource; +import org.apache.poi.crypt.examples.EncryptionUtils; +import org.apache.poi.examples.util.TempFileUtils; +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +/** + * An example that loads a password protected workbook and counts the sheets. + *

+ */ +public class LoadPasswordProtectedXlsx { + + public static void main(String[] args) { + try { + if(args.length != 2) { + throw new Exception("Expected 2 params: filename and password"); + } + TempFileUtils.checkTempFiles(); + String filename = args[0]; + String password = args[1]; + FileInputStream fis = new FileInputStream(filename); + try { + InputStream unencryptedStream = EncryptionUtils.decrypt(fis, password); + try { + printSheetCount(unencryptedStream); + } finally { + IOUtils.closeQuietly(unencryptedStream); + } + } finally { + IOUtils.closeQuietly(fis); + } + TempFileUtils.checkTempFiles(); + } catch(Throwable t) { + t.printStackTrace(); + } + } + + public static void printSheetCount(final InputStream inputStream) throws Exception { + AesZipFileZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(inputStream); + try { + OPCPackage pkg = OPCPackage.open(source); + try { + XSSFWorkbook workbook = new XSSFWorkbook(pkg); + try { + System.out.println("sheet count: " + workbook.getNumberOfSheets()); + } finally { + IOUtils.closeQuietly(workbook); + } + } finally { + IOUtils.closeQuietly(pkg); + } + } finally { + IOUtils.closeQuietly(source); + } + } + +}