--- /dev/null
+/*
+ * ====================================================================
+ * 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 <code>ZipEntrySource</code> 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
--- /dev/null
+/*
+ * ====================================================================
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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");
+ }
+ }
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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.
+ * <p><ul>
+ * <li>The example demonstrates that all temp files are removed.
+ * <li><code>AesZipFileZipEntrySource</code> is used to ensure that temp files are encrypted.
+ * </ul><p>
+ */
+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);
+ }
+ }
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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.
+ * <p><ul>
+ * <li>The example demonstrates that all temp files are removed.
+ * <li><code>SXSSFWorkbookWithCustomZipEntrySource</code> extends SXSSFWorkbook to ensure temp files are encrypted.
+ * </ul><p>
+ */
+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);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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.
+ * <p><ul>
+ * <li>The example demonstrates that all temp files are removed.
+ * <li><code>AesZipFileZipEntrySource</code> is used to ensure that temp files are encrypted.
+ * </ul><p>
+ */
+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);
+ }
+ }
+
+}