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 extends ZipEntry> 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.
+ *
AesZipFileZipEntrySource
is used to ensure that temp files are encrypted.
+ * + */ +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. + *
SXSSFWorkbookWithCustomZipEntrySource
extends SXSSFWorkbook to ensure temp files are encrypted.
+ * + */ +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. + *
AesZipFileZipEntrySource
is used to ensure that temp files are encrypted.
+ * + */ +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); + } + } + +}