From fc86b15f13a0e31b39ad498414f05c116124d4cc Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Fri, 11 Nov 2016 23:22:43 +0000 Subject: [PATCH] - SonarCube fixes - moved SecureTempFile classes to OOXML, because of duplicated code in test and examples packages git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1769363 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/crypt/examples/EncryptionUtils.java | 3 + .../poi/examples/util/TempFileUtils.java | 7 +- .../LoadPasswordProtectedXlsxStreaming.java | 43 +++--- .../examples/SavePasswordProtectedXlsx.java | 61 ++++---- .../examples/LoadPasswordProtectedXlsx.java | 42 +++--- .../poi/hssf/OldExcelFormatException.java | 5 + .../poi/hssf/record/FilePassRecord.java | 16 +- .../poifs/crypt/ChunkedCipherInputStream.java | 96 ++++++------ .../crypt/ChunkedCipherOutputStream.java | 133 +++++++++-------- .../org/apache/poi/poifs/crypt/Decryptor.java | 6 +- .../org/apache/poi/poifs/crypt/Encryptor.java | 5 +- .../crypt/binaryrc4/BinaryRC4Decryptor.java | 18 +-- .../crypt/binaryrc4/BinaryRC4Encryptor.java | 8 +- .../crypt/cryptoapi/CryptoAPIDecryptor.java | 13 +- .../CryptoAPIDocumentOutputStream.java | 10 +- .../crypt/cryptoapi/CryptoAPIEncryptor.java | 8 +- .../poi/poifs/crypt/xor/XORDecryptor.java | 31 ++-- .../crypt/xor/XOREncryptionVerifier.java | 4 +- .../poi/poifs/crypt/xor/XOREncryptor.java | 22 +-- .../org/apache/poi/POIXMLDocumentPart.java | 3 +- .../poi/poifs/crypt/agile/AgileDecryptor.java | 2 +- .../crypt/agile/AgileEncryptionVerifier.java | 9 +- .../crypt/temp}/AesZipFileZipEntrySource.java | 20 ++- .../poifs/crypt/temp}/EncryptedTempData.java | 21 ++- ...SXSSFWorkbookWithCustomZipEntrySource.java | 60 ++------ .../temp/SheetDataWriterWithDecorator.java | 73 +++++++++ .../poi/xssf/eventusermodel/XSSFReader.java | 5 +- .../poi/xssf/streaming/SheetDataWriter.java | 2 +- .../xwpf/model/XWPFHeaderFooterPolicy.java | 6 +- .../poi/xwpf/usermodel/XWPFDocument.java | 4 +- .../poifs/crypt/AesZipFileZipEntrySource.java | 140 ------------------ .../poi/poifs/crypt/TestSecureTempZip.java | 1 + ...SXSSFWorkbookWithCustomZipEntrySource.java | 4 +- ...SXSSFWorkbookWithCustomZipEntrySource.java | 120 +-------------- .../apache/poi/hdgf/pointers/PointerV5.java | 20 ++- .../src/org/apache/poi/hslf/blip/PICT.java | 2 +- .../poi/hslf/usermodel/HSLFFreeformShape.java | 4 +- 37 files changed, 415 insertions(+), 612 deletions(-) rename src/{examples/src/org/apache/poi/crypt/examples => ooxml/java/org/apache/poi/poifs/crypt/temp}/AesZipFileZipEntrySource.java (91%) rename src/{examples/src/org/apache/poi/crypt/examples => ooxml/java/org/apache/poi/poifs/crypt/temp}/EncryptedTempData.java (80%) rename src/{examples/src/org/apache/poi/xssf/streaming/examples => ooxml/java/org/apache/poi/poifs/crypt/temp}/SXSSFWorkbookWithCustomZipEntrySource.java (55%) create mode 100644 src/ooxml/java/org/apache/poi/poifs/crypt/temp/SheetDataWriterWithDecorator.java delete mode 100644 src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java diff --git a/src/examples/src/org/apache/poi/crypt/examples/EncryptionUtils.java b/src/examples/src/org/apache/poi/crypt/examples/EncryptionUtils.java index acbfdd189..c2b795cb5 100644 --- a/src/examples/src/org/apache/poi/crypt/examples/EncryptionUtils.java +++ b/src/examples/src/org/apache/poi/crypt/examples/EncryptionUtils.java @@ -27,6 +27,9 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.IOUtils; public class EncryptionUtils { + private EncryptionUtils() { + } + public static InputStream decrypt(final InputStream inputStream, final String pwd) throws Exception { try { POIFSFileSystem fs = new POIFSFileSystem(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 index f34f35d3c..5d4f7ab53 100644 --- a/src/examples/src/org/apache/poi/examples/util/TempFileUtils.java +++ b/src/examples/src/org/apache/poi/examples/util/TempFileUtils.java @@ -25,14 +25,17 @@ import java.io.IOException; import org.apache.poi.util.TempFile; public class TempFileUtils { + private 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) { + if(tempFiles != null && tempFiles.length > 0) { System.out.println("found files in poi temp dir " + tempDir.getAbsolutePath()); - for(String filename : tempDir.list()) { + for(String filename : tempFiles) { System.out.println("file: " + filename); } } 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 index aa7d0ceee..80e4c7320 100644 --- a/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/LoadPasswordProtectedXlsxStreaming.java +++ b/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/LoadPasswordProtectedXlsxStreaming.java @@ -20,12 +20,13 @@ package org.apache.poi.xssf.eventusermodel.examples; import java.io.FileInputStream; +import java.io.IOException; 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.poifs.crypt.temp.AesZipFileZipEntrySource; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.eventusermodel.XSSFReader.SheetIterator; @@ -40,29 +41,25 @@ import org.apache.poi.xssf.eventusermodel.XSSFReader.SheetIterator; */ 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 main(String[] args) throws Exception { + if(args.length != 2) { + throw new IllegalArgumentException("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(); } public static void printSheetCount(final InputStream inputStream) throws Exception { 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 index 4c741873a..9aaa8bf27 100644 --- a/src/examples/src/org/apache/poi/xssf/streaming/examples/SavePasswordProtectedXlsx.java +++ b/src/examples/src/org/apache/poi/xssf/streaming/examples/SavePasswordProtectedXlsx.java @@ -24,13 +24,14 @@ 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.crypt.temp.EncryptedTempData; +import org.apache.poi.poifs.crypt.temp.SXSSFWorkbookWithCustomZipEntrySource; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.streaming.SXSSFCell; @@ -47,42 +48,38 @@ import org.apache.poi.xssf.streaming.SXSSFSheet; */ public class SavePasswordProtectedXlsx { - public static void main(String[] args) { + public static void main(String[] args) throws Exception { + if(args.length != 2) { + throw new IllegalArgumentException("Expected 2 params: filename and password"); + } + TempFileUtils.checkTempFiles(); + String filename = args[0]; + String password = args[1]; + SXSSFWorkbookWithCustomZipEntrySource wb = new SXSSFWorkbookWithCustomZipEntrySource(); 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"); - } + 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(); + 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(); } public static void save(final InputStream inputStream, final String filename, final String pwd) 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 index 7bb677bf2..da6032f86 100644 --- a/src/examples/src/org/apache/poi/xssf/usermodel/examples/LoadPasswordProtectedXlsx.java +++ b/src/examples/src/org/apache/poi/xssf/usermodel/examples/LoadPasswordProtectedXlsx.java @@ -22,10 +22,10 @@ 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.poifs.crypt.temp.AesZipFileZipEntrySource; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.usermodel.XSSFWorkbook; @@ -38,29 +38,25 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook; */ 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 main(String[] args) throws Exception { + if(args.length != 2) { + throw new IllegalArgumentException("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(); } public static void printSheetCount(final InputStream inputStream) throws Exception { diff --git a/src/java/org/apache/poi/hssf/OldExcelFormatException.java b/src/java/org/apache/poi/hssf/OldExcelFormatException.java index e42e613d8..beb8c02c7 100644 --- a/src/java/org/apache/poi/hssf/OldExcelFormatException.java +++ b/src/java/org/apache/poi/hssf/OldExcelFormatException.java @@ -17,7 +17,12 @@ package org.apache.poi.hssf; import org.apache.poi.OldFileFormatException; +import org.apache.poi.util.Removal; +/** + * @deprecated POI 3.16 beta 1. Use {@link org.apache.poi.OldFileFormatException} + */ +@Removal(version="3.18") public class OldExcelFormatException extends OldFileFormatException { public OldExcelFormatException(String s) { super(s); diff --git a/src/java/org/apache/poi/hssf/record/FilePassRecord.java b/src/java/org/apache/poi/hssf/record/FilePassRecord.java index 99f37e535..ab941fad5 100644 --- a/src/java/org/apache/poi/hssf/record/FilePassRecord.java +++ b/src/java/org/apache/poi/hssf/record/FilePassRecord.java @@ -110,7 +110,7 @@ public final class FilePassRecord extends StandardRecord implements Cloneable { ((CryptoAPIEncryptionVerifier)encryptionInfo.getVerifier()).write(bos); break; default: - throw new RuntimeException("not supported"); + throw new EncryptedDocumentException("not supported"); } out.write(data, 0, bos.getWriteIndex()); @@ -140,16 +140,16 @@ public final class FilePassRecord extends StandardRecord implements Cloneable { @Override public String toString() { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); buffer.append("[FILEPASS]\n"); - buffer.append(" .type = ").append(HexDump.shortToHex(encryptionType)).append("\n"); + buffer.append(" .type = ").append(HexDump.shortToHex(encryptionType)).append('\n'); String prefix = " ."+encryptionInfo.getEncryptionMode(); - buffer.append(prefix+".info = ").append(HexDump.shortToHex(encryptionInfo.getVersionMajor())).append("\n"); - buffer.append(prefix+".ver = ").append(HexDump.shortToHex(encryptionInfo.getVersionMinor())).append("\n"); - buffer.append(prefix+".salt = ").append(HexDump.toHex(encryptionInfo.getVerifier().getSalt())).append("\n"); - buffer.append(prefix+".verifier = ").append(HexDump.toHex(encryptionInfo.getVerifier().getEncryptedVerifier())).append("\n"); - buffer.append(prefix+".verifierHash = ").append(HexDump.toHex(encryptionInfo.getVerifier().getEncryptedVerifierHash())).append("\n"); + buffer.append(prefix+".info = ").append(HexDump.shortToHex(encryptionInfo.getVersionMajor())).append('\n'); + buffer.append(prefix+".ver = ").append(HexDump.shortToHex(encryptionInfo.getVersionMinor())).append('\n'); + buffer.append(prefix+".salt = ").append(HexDump.toHex(encryptionInfo.getVerifier().getSalt())).append('\n'); + buffer.append(prefix+".verifier = ").append(HexDump.toHex(encryptionInfo.getVerifier().getEncryptedVerifier())).append('\n'); + buffer.append(prefix+".verifierHash = ").append(HexDump.toHex(encryptionInfo.getVerifier().getEncryptedVerifierHash())).append('\n'); buffer.append("[/FILEPASS]\n"); return buffer.toString(); } diff --git a/src/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java b/src/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java index 1045b3058..db3d724e4 100644 --- a/src/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java +++ b/src/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java @@ -32,16 +32,16 @@ import org.apache.poi.util.LittleEndianInputStream; @Internal public abstract class ChunkedCipherInputStream extends LittleEndianInputStream { - private final int _chunkSize; - private final int _chunkBits; + private final int chunkSize; + private final int chunkBits; - private final long _size; - private final byte[] _chunk, _plain; - private final Cipher _cipher; + private final long size; + private final byte[] chunk, plain; + private final Cipher cipher; - private int _lastIndex; - private long _pos; - private boolean _chunkIsValid = false; + private int lastIndex; + private long pos; + private boolean chunkIsValid = false; public ChunkedCipherInputStream(InputStream stream, long size, int chunkSize) throws GeneralSecurityException { @@ -51,24 +51,24 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream { public ChunkedCipherInputStream(InputStream stream, long size, int chunkSize, int initialPos) throws GeneralSecurityException { super(stream); - _size = size; - _pos = initialPos; - this._chunkSize = chunkSize; + this.size = size; + this.pos = initialPos; + this.chunkSize = chunkSize; int cs = chunkSize == -1 ? 4096 : chunkSize; - _chunk = new byte[cs]; - _plain = new byte[cs]; - _chunkBits = Integer.bitCount(_chunk.length-1); - _lastIndex = (int)(_pos >> _chunkBits); - _cipher = initCipherForBlock(null, _lastIndex); + this.chunk = new byte[cs]; + this.plain = new byte[cs]; + this.chunkBits = Integer.bitCount(chunk.length-1); + this.lastIndex = (int)(pos >> chunkBits); + this.cipher = initCipherForBlock(null, lastIndex); } public final Cipher initCipherForBlock(int block) throws IOException, GeneralSecurityException { - if (_chunkSize != -1) { + if (chunkSize != -1) { throw new GeneralSecurityException("the cipher block can only be set for streaming encryption, e.g. CryptoAPI..."); } - _chunkIsValid = false; - return initCipherForBlock(_cipher, block); + chunkIsValid = false; + return initCipherForBlock(cipher, block); } protected abstract Cipher initCipherForBlock(Cipher existing, int block) @@ -100,28 +100,28 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream { final int chunkMask = getChunkMask(); while (len > 0) { - if (!_chunkIsValid) { + if (!chunkIsValid) { try { nextChunk(); - _chunkIsValid = true; + chunkIsValid = true; } catch (GeneralSecurityException e) { throw new EncryptedDocumentException(e.getMessage(), e); } } - int count = (int)(_chunk.length - (_pos & chunkMask)); + int count = (int)(chunk.length - (pos & chunkMask)); int avail = available(); if (avail == 0) { return total; } count = Math.min(avail, Math.min(count, len)); - System.arraycopy(readPlain ? _plain : _chunk, (int)(_pos & chunkMask), b, off, count); + System.arraycopy(readPlain ? plain : chunk, (int)(pos & chunkMask), b, off, count); off += count; len -= count; - _pos += count; - if ((_pos & chunkMask) == 0) { - _chunkIsValid = false; + pos += count; + if ((pos & chunkMask) == 0) { + chunkIsValid = false; } total += count; } @@ -131,13 +131,13 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream { @Override public long skip(final long n) throws IOException { - long start = _pos; + long start = pos; long skip = Math.min(remainingBytes(), n); - if ((((_pos + skip) ^ start) & ~getChunkMask()) != 0) { - _chunkIsValid = false; + if ((((pos + skip) ^ start) & ~getChunkMask()) != 0) { + chunkIsValid = false; } - _pos += skip; + pos += skip; return skip; } @@ -152,7 +152,7 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream { * @return the remaining byte until EOF */ private int remainingBytes() { - return (int)(_size - _pos); + return (int)(size - pos); } @Override @@ -171,35 +171,35 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream { } protected int getChunkMask() { - return _chunk.length-1; + return chunk.length-1; } private void nextChunk() throws GeneralSecurityException, IOException { - if (_chunkSize != -1) { - int index = (int)(_pos >> _chunkBits); - initCipherForBlock(_cipher, index); + if (chunkSize != -1) { + int index = (int)(pos >> chunkBits); + initCipherForBlock(cipher, index); - if (_lastIndex != index) { - super.skip((index - _lastIndex) << _chunkBits); + if (lastIndex != index) { + super.skip((index - lastIndex) << chunkBits); } - _lastIndex = index + 1; + lastIndex = index + 1; } - final int todo = (int)Math.min(_size, _chunk.length); + final int todo = (int)Math.min(size, chunk.length); int readBytes = 0, totalBytes = 0; do { - readBytes = super.read(_plain, totalBytes, todo-totalBytes); + readBytes = super.read(plain, totalBytes, todo-totalBytes); totalBytes += Math.max(0, readBytes); } while (readBytes != -1 && totalBytes < todo); - if (readBytes == -1 && _pos+totalBytes < _size && _size < Integer.MAX_VALUE) { + if (readBytes == -1 && pos+totalBytes < size && size < Integer.MAX_VALUE) { throw new EOFException("buffer underrun"); } - System.arraycopy(_plain, 0, _chunk, 0, totalBytes); + System.arraycopy(plain, 0, chunk, 0, totalBytes); - invokeCipher(totalBytes, totalBytes == _chunkSize); + invokeCipher(totalBytes, totalBytes == chunkSize); } /** @@ -212,9 +212,9 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream { */ protected int invokeCipher(int totalBytes, boolean doFinal) throws GeneralSecurityException { if (doFinal) { - return _cipher.doFinal(_chunk, 0, totalBytes, _chunk); + return cipher.doFinal(chunk, 0, totalBytes, chunk); } else { - return _cipher.update(_chunk, 0, totalBytes, _chunk); + return cipher.update(chunk, 0, totalBytes, chunk); } } @@ -258,20 +258,20 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream { * @return the chunk bytes */ protected byte[] getChunk() { - return _chunk; + return chunk; } /** * @return the plain bytes */ protected byte[] getPlain() { - return _plain; + return plain; } /** * @return the absolute position in the stream */ public long getPos() { - return _pos; + return pos; } } diff --git a/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java b/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java index 836aae2bb..a8e920dc1 100644 --- a/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java +++ b/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java @@ -49,47 +49,50 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream { private static final POILogger LOG = POILogFactory.getLogger(ChunkedCipherOutputStream.class); private static final int STREAMING = -1; - private final int _chunkSize; - private final int _chunkBits; + private final int chunkSize; + private final int chunkBits; - private final byte[] _chunk; - private final BitSet _plainByteFlags; - private final File _fileOut; - private final DirectoryNode _dir; + private final byte[] chunk; + private final BitSet plainByteFlags; + private final File fileOut; + private final DirectoryNode dir; - private long _pos = 0; - private long _totalPos = 0; - private long _written = 0; - private Cipher _cipher; + private long pos = 0; + private long totalPos = 0; + private long written = 0; + + // the cipher can't be final, because for the last chunk we change the padding + // and therefore need to change the cipher too + private Cipher cipher; public ChunkedCipherOutputStream(DirectoryNode dir, int chunkSize) throws IOException, GeneralSecurityException { super(null); - this._chunkSize = chunkSize; + this.chunkSize = chunkSize; int cs = chunkSize == STREAMING ? 4096 : chunkSize; - _chunk = new byte[cs]; - _plainByteFlags = new BitSet(cs); - _chunkBits = Integer.bitCount(cs-1); - _fileOut = TempFile.createTempFile("encrypted_package", "crypt"); - _fileOut.deleteOnExit(); - this.out = new FileOutputStream(_fileOut); - this._dir = dir; - _cipher = initCipherForBlock(null, 0, false); + this.chunk = new byte[cs]; + this.plainByteFlags = new BitSet(cs); + this.chunkBits = Integer.bitCount(cs-1); + this.fileOut = TempFile.createTempFile("encrypted_package", "crypt"); + this.fileOut.deleteOnExit(); + this.out = new FileOutputStream(fileOut); + this.dir = dir; + this.cipher = initCipherForBlock(null, 0, false); } public ChunkedCipherOutputStream(OutputStream stream, int chunkSize) throws IOException, GeneralSecurityException { super(stream); - this._chunkSize = chunkSize; + this.chunkSize = chunkSize; int cs = chunkSize == STREAMING ? 4096 : chunkSize; - _chunk = new byte[cs]; - _plainByteFlags = new BitSet(cs); - _chunkBits = Integer.bitCount(cs-1); - _fileOut = null; - _dir = null; - _cipher = initCipherForBlock(null, 0, false); + this.chunk = new byte[cs]; + this.plainByteFlags = new BitSet(cs); + this.chunkBits = Integer.bitCount(cs-1); + this.fileOut = null; + this.dir = null; + this.cipher = initCipherForBlock(null, 0, false); } public final Cipher initCipherForBlock(int block, boolean lastChunk) throws IOException, GeneralSecurityException { - return initCipherForBlock(_cipher, block, lastChunk); + return initCipherForBlock(cipher, block, lastChunk); } protected abstract Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk) @@ -131,40 +134,40 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream { final int chunkMask = getChunkMask(); while (len > 0) { - int posInChunk = (int)(_pos & chunkMask); - int nextLen = Math.min(_chunk.length-posInChunk, len); - System.arraycopy(b, off, _chunk, posInChunk, nextLen); + int posInChunk = (int)(pos & chunkMask); + int nextLen = Math.min(chunk.length-posInChunk, len); + System.arraycopy(b, off, chunk, posInChunk, nextLen); if (writePlain) { - _plainByteFlags.set(posInChunk, posInChunk+nextLen); + plainByteFlags.set(posInChunk, posInChunk+nextLen); } - _pos += nextLen; - _totalPos += nextLen; + pos += nextLen; + totalPos += nextLen; off += nextLen; len -= nextLen; - if ((_pos & chunkMask) == 0) { + if ((pos & chunkMask) == 0) { writeChunk(len > 0); } } } protected int getChunkMask() { - return _chunk.length-1; + return chunk.length-1; } protected void writeChunk(boolean continued) throws IOException { - if (_pos == 0 || _totalPos == _written) { + if (pos == 0 || totalPos == written) { return; } - int posInChunk = (int)(_pos & getChunkMask()); + int posInChunk = (int)(pos & getChunkMask()); // normally posInChunk is 0, i.e. on the next chunk (-> index-1) // but if called on close(), posInChunk is somewhere within the chunk data - int index = (int)(_pos >> _chunkBits); + int index = (int)(pos >> chunkBits); boolean lastChunk; if (posInChunk==0) { index--; - posInChunk = _chunk.length; + posInChunk = chunk.length; lastChunk = false; } else { // pad the last chunk @@ -174,27 +177,27 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream { int ciLen; try { boolean doFinal = true; - long oldPos = _pos; + long oldPos = pos; // reset stream (not only) in case we were interrupted by plain stream parts // this also needs to be set to prevent an endless loop - _pos = 0; - if (_chunkSize == STREAMING) { + pos = 0; + if (chunkSize == STREAMING) { if (continued) { doFinal = false; } } else { - _cipher = initCipherForBlock(_cipher, index, lastChunk); + cipher = initCipherForBlock(cipher, index, lastChunk); // restore pos - only streaming chunks will be reset - _pos = oldPos; + pos = oldPos; } ciLen = invokeCipher(posInChunk, doFinal); } catch (GeneralSecurityException e) { throw new IOException("can't re-/initialize cipher", e); } - out.write(_chunk, 0, ciLen); - _plainByteFlags.clear(); - _written += ciLen; + out.write(chunk, 0, ciLen); + plainByteFlags.clear(); + written += ciLen; } /** @@ -206,14 +209,14 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream { * @throws ShortBufferException */ protected int invokeCipher(int posInChunk, boolean doFinal) throws GeneralSecurityException { - byte plain[] = (_plainByteFlags.isEmpty()) ? null : _chunk.clone(); + byte plain[] = (plainByteFlags.isEmpty()) ? null : chunk.clone(); int ciLen = (doFinal) - ? _cipher.doFinal(_chunk, 0, posInChunk, _chunk) - : _cipher.update(_chunk, 0, posInChunk, _chunk); + ? cipher.doFinal(chunk, 0, posInChunk, chunk) + : cipher.update(chunk, 0, posInChunk, chunk); - for (int i = _plainByteFlags.nextSetBit(0); i >= 0 && i < posInChunk; i = _plainByteFlags.nextSetBit(i+1)) { - _chunk[i] = plain[i]; + for (int i = plainByteFlags.nextSetBit(0); i >= 0 && i < posInChunk; i = plainByteFlags.nextSetBit(i+1)) { + chunk[i] = plain[i]; } return ciLen; @@ -226,11 +229,11 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream { super.close(); - if (_fileOut != null) { - int oleStreamSize = (int)(_fileOut.length()+LittleEndianConsts.LONG_SIZE); - calculateChecksum(_fileOut, (int)_pos); - _dir.createDocument(DEFAULT_POIFS_ENTRY, oleStreamSize, new EncryptedPackageWriter()); - createEncryptionInfoEntry(_dir, _fileOut); + if (fileOut != null) { + int oleStreamSize = (int)(fileOut.length()+LittleEndianConsts.LONG_SIZE); + calculateChecksum(fileOut, (int)pos); + dir.createDocument(DEFAULT_POIFS_ENTRY, oleStreamSize, new EncryptedPackageWriter()); + createEncryptionInfoEntry(dir, fileOut); } } catch (GeneralSecurityException e) { throw new IOException(e); @@ -238,19 +241,19 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream { } protected byte[] getChunk() { - return _chunk; + return chunk; } protected BitSet getPlainByteFlags() { - return _plainByteFlags; + return plainByteFlags; } protected long getPos() { - return _pos; + return pos; } protected long getTotalPos() { - return _totalPos; + return totalPos; } /** @@ -274,17 +277,17 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream { // Note that the actual size of the \EncryptedPackage stream (1) can be larger than this // value, depending on the block size of the chosen encryption algorithm byte buf[] = new byte[LittleEndianConsts.LONG_SIZE]; - LittleEndian.putLong(buf, 0, _pos); + LittleEndian.putLong(buf, 0, pos); os.write(buf); - FileInputStream fis = new FileInputStream(_fileOut); + FileInputStream fis = new FileInputStream(fileOut); IOUtils.copy(fis, os); fis.close(); os.close(); - if (!_fileOut.delete()) { - LOG.log(POILogger.ERROR, "Can't delete temporary encryption file: "+_fileOut); + if (!fileOut.delete()) { + LOG.log(POILogger.ERROR, "Can't delete temporary encryption file: "+fileOut); } } catch (IOException e) { throw new EncryptedDocumentException(e); diff --git a/src/java/org/apache/poi/poifs/crypt/Decryptor.java b/src/java/org/apache/poi/poifs/crypt/Decryptor.java index 203002955..da746d896 100644 --- a/src/java/org/apache/poi/poifs/crypt/Decryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/Decryptor.java @@ -67,7 +67,7 @@ public abstract class Decryptor implements Cloneable { */ public InputStream getDataStream(InputStream stream, int size, int initialPos) throws IOException, GeneralSecurityException { - throw new RuntimeException("this decryptor doesn't support reading from a stream"); + throw new EncryptedDocumentException("this decryptor doesn't support reading from a stream"); } /** @@ -78,7 +78,7 @@ public abstract class Decryptor implements Cloneable { * @param chunkSize the chunk size, i.e. the block size with the same encryption key */ public void setChunkSize(int chunkSize) { - throw new RuntimeException("this decryptor doesn't support changing the chunk size"); + throw new EncryptedDocumentException("this decryptor doesn't support changing the chunk size"); } /** @@ -91,7 +91,7 @@ public abstract class Decryptor implements Cloneable { */ public Cipher initCipherForBlock(Cipher cipher, int block) throws GeneralSecurityException { - throw new RuntimeException("this decryptor doesn't support initCipherForBlock"); + throw new EncryptedDocumentException("this decryptor doesn't support initCipherForBlock"); } public abstract boolean verifyPassword(String password) diff --git a/src/java/org/apache/poi/poifs/crypt/Encryptor.java b/src/java/org/apache/poi/poifs/crypt/Encryptor.java index 546c96628..f4c0c1639 100644 --- a/src/java/org/apache/poi/poifs/crypt/Encryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/Encryptor.java @@ -23,6 +23,7 @@ import java.security.GeneralSecurityException; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; +import org.apache.poi.EncryptedDocumentException; import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.OPOIFSFileSystem; @@ -63,7 +64,7 @@ public abstract class Encryptor implements Cloneable { public ChunkedCipherOutputStream getDataStream(OutputStream stream, int initialOffset) throws IOException, GeneralSecurityException { - throw new RuntimeException("this decryptor doesn't support writing directly to a stream"); + throw new EncryptedDocumentException("this decryptor doesn't support writing directly to a stream"); } public SecretKey getSecretKey() { @@ -90,7 +91,7 @@ public abstract class Encryptor implements Cloneable { * @param chunkSize the chunk size, i.e. the block size with the same encryption key */ public void setChunkSize(int chunkSize) { - throw new RuntimeException("this decryptor doesn't support changing the chunk size"); + throw new EncryptedDocumentException("this decryptor doesn't support changing the chunk size"); } @Override diff --git a/src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4Decryptor.java b/src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4Decryptor.java index b6d8eda00..e02273407 100644 --- a/src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4Decryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4Decryptor.java @@ -35,8 +35,8 @@ import org.apache.poi.util.LittleEndian; import org.apache.poi.util.StringUtil; public class BinaryRC4Decryptor extends Decryptor implements Cloneable { - private long _length = -1L; - private int _chunkSize = 512; + private long length = -1L; + private int chunkSize = 512; private class BinaryRC4CipherInputStream extends ChunkedCipherInputStream { @@ -48,12 +48,12 @@ public class BinaryRC4Decryptor extends Decryptor implements Cloneable { public BinaryRC4CipherInputStream(DocumentInputStream stream, long size) throws GeneralSecurityException { - super(stream, size, _chunkSize); + super(stream, size, chunkSize); } public BinaryRC4CipherInputStream(InputStream stream) throws GeneralSecurityException { - super(stream, Integer.MAX_VALUE, _chunkSize); + super(stream, Integer.MAX_VALUE, chunkSize); } } @@ -134,8 +134,8 @@ public class BinaryRC4Decryptor extends Decryptor implements Cloneable { public ChunkedCipherInputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException { DocumentInputStream dis = dir.createDocumentInputStream(DEFAULT_POIFS_ENTRY); - _length = dis.readLong(); - return new BinaryRC4CipherInputStream(dis, _length); + length = dis.readLong(); + return new BinaryRC4CipherInputStream(dis, length); } @Override @@ -147,16 +147,16 @@ public class BinaryRC4Decryptor extends Decryptor implements Cloneable { @Override public long getLength() { - if (_length == -1L) { + if (length == -1L) { throw new IllegalStateException("Decryptor.getDataStream() was not called"); } - return _length; + return length; } @Override public void setChunkSize(int chunkSize) { - _chunkSize = chunkSize; + this.chunkSize = chunkSize; } @Override diff --git a/src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4Encryptor.java b/src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4Encryptor.java index 9545cbab0..15bb476ea 100644 --- a/src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4Encryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4Encryptor.java @@ -41,7 +41,7 @@ import org.apache.poi.util.LittleEndianByteArrayOutputStream; public class BinaryRC4Encryptor extends Encryptor implements Cloneable { - private int _chunkSize = 512; + private int chunkSize = 512; protected BinaryRC4Encryptor() { } @@ -115,7 +115,7 @@ public class BinaryRC4Encryptor extends Encryptor implements Cloneable { @Override public void setChunkSize(int chunkSize) { - _chunkSize = chunkSize; + this.chunkSize = chunkSize; } @Override @@ -127,12 +127,12 @@ public class BinaryRC4Encryptor extends Encryptor implements Cloneable { public BinaryRC4CipherOutputStream(OutputStream stream) throws IOException, GeneralSecurityException { - super(stream, BinaryRC4Encryptor.this._chunkSize); + super(stream, BinaryRC4Encryptor.this.chunkSize); } public BinaryRC4CipherOutputStream(DirectoryNode dir) throws IOException, GeneralSecurityException { - super(dir, BinaryRC4Encryptor.this._chunkSize); + super(dir, BinaryRC4Encryptor.this.chunkSize); } @Override diff --git a/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIDecryptor.java b/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIDecryptor.java index 451708c6e..e781c9d89 100644 --- a/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIDecryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIDecryptor.java @@ -50,8 +50,8 @@ import org.apache.poi.util.StringUtil; public class CryptoAPIDecryptor extends Decryptor implements Cloneable { - private long _length; - private int _chunkSize = -1; + private long length = -1L; + private int chunkSize = -1; static class StreamDescriptorEntry { static BitField flagStream = BitFieldFactory.getInstance(1); @@ -65,7 +65,6 @@ public class CryptoAPIDecryptor extends Decryptor implements Cloneable { } protected CryptoAPIDecryptor() { - _length = -1L; } @Override @@ -209,14 +208,14 @@ public class CryptoAPIDecryptor extends Decryptor implements Cloneable { */ @Override public long getLength() { - if (_length == -1L) { + if (length == -1L) { throw new IllegalStateException("Decryptor.getDataStream() was not called"); } - return _length; + return length; } public void setChunkSize(int chunkSize) { - _chunkSize = chunkSize; + this.chunkSize = chunkSize; } @Override @@ -234,7 +233,7 @@ public class CryptoAPIDecryptor extends Decryptor implements Cloneable { public CryptoAPICipherInputStream(InputStream stream, long size, int initialPos) throws GeneralSecurityException { - super(stream, size, _chunkSize, initialPos); + super(stream, size, chunkSize, initialPos); } } } diff --git a/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIDocumentOutputStream.java b/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIDocumentOutputStream.java index 6bf04871d..5fa9564a4 100644 --- a/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIDocumentOutputStream.java +++ b/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIDocumentOutputStream.java @@ -29,13 +29,13 @@ import org.apache.poi.util.Internal; */ @Internal /* package */ class CryptoAPIDocumentOutputStream extends ByteArrayOutputStream { - private Cipher cipher; - private CryptoAPIEncryptor encryptor; - private byte oneByte[] = { 0 }; + private final Cipher cipher; + private final CryptoAPIEncryptor encryptor; + private final byte oneByte[] = { 0 }; public CryptoAPIDocumentOutputStream(CryptoAPIEncryptor encryptor) throws GeneralSecurityException { this.encryptor = encryptor; - setBlock(0); + cipher = encryptor.initCipherForBlock(null, 0); } public byte[] getBuf() { @@ -47,7 +47,7 @@ import org.apache.poi.util.Internal; } public void setBlock(int block) throws GeneralSecurityException { - cipher = encryptor.initCipherForBlock(cipher, block); + encryptor.initCipherForBlock(cipher, block); } @Override diff --git a/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java b/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java index e15558405..d04096c39 100644 --- a/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java @@ -53,7 +53,7 @@ import org.apache.poi.util.StringUtil; public class CryptoAPIEncryptor extends Encryptor implements Cloneable { - private int _chunkSize = 512; + private int chunkSize = 512; protected CryptoAPIEncryptor() { } @@ -215,7 +215,7 @@ public class CryptoAPIEncryptor extends Encryptor implements Cloneable { @Override public void setChunkSize(int chunkSize) { - _chunkSize = chunkSize; + this.chunkSize = chunkSize; } protected void createEncryptionInfoEntry(DirectoryNode dir) throws IOException { @@ -259,12 +259,12 @@ public class CryptoAPIEncryptor extends Encryptor implements Cloneable { @Override protected void createEncryptionInfoEntry(DirectoryNode dir, File tmpFile) throws IOException, GeneralSecurityException { - throw new RuntimeException("createEncryptionInfoEntry not supported"); + throw new EncryptedDocumentException("createEncryptionInfoEntry not supported"); } public CryptoAPICipherOutputStream(OutputStream stream) throws IOException, GeneralSecurityException { - super(stream, CryptoAPIEncryptor.this._chunkSize); + super(stream, CryptoAPIEncryptor.this.chunkSize); } @Override diff --git a/src/java/org/apache/poi/poifs/crypt/xor/XORDecryptor.java b/src/java/org/apache/poi/poifs/crypt/xor/XORDecryptor.java index 01725f48b..3eb66b549 100644 --- a/src/java/org/apache/poi/poifs/crypt/xor/XORDecryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/xor/XORDecryptor.java @@ -25,6 +25,7 @@ import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; +import org.apache.poi.EncryptedDocumentException; import org.apache.poi.poifs.crypt.ChunkedCipherInputStream; import org.apache.poi.poifs.crypt.CryptoFunctions; import org.apache.poi.poifs.crypt.Decryptor; @@ -33,8 +34,8 @@ import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.util.LittleEndian; public class XORDecryptor extends Decryptor implements Cloneable { - private long _length = -1L; - private int _chunkSize = 512; + private long length = -1L; + private int chunkSize = 512; protected XORDecryptor() { } @@ -69,7 +70,7 @@ public class XORDecryptor extends Decryptor implements Cloneable { @Override public ChunkedCipherInputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException { - throw new RuntimeException("not supported"); + throw new EncryptedDocumentException("not supported"); } @Override @@ -81,16 +82,16 @@ public class XORDecryptor extends Decryptor implements Cloneable { @Override public long getLength() { - if (_length == -1L) { + if (length == -1L) { throw new IllegalStateException("Decryptor.getDataStream() was not called"); } - return _length; + return length; } @Override public void setChunkSize(int chunkSize) { - _chunkSize = chunkSize; + this.chunkSize = chunkSize; } @Override @@ -99,14 +100,14 @@ public class XORDecryptor extends Decryptor implements Cloneable { } private class XORCipherInputStream extends ChunkedCipherInputStream { - private final int _initialOffset; - private int _recordStart = 0; - private int _recordEnd = 0; + private final int initialOffset; + private int recordStart = 0; + private int recordEnd = 0; public XORCipherInputStream(InputStream stream, int initialPos) throws GeneralSecurityException { - super(stream, Integer.MAX_VALUE, _chunkSize); - _initialOffset = initialPos; + super(stream, Integer.MAX_VALUE, chunkSize); + this.initialOffset = initialPos; } @Override @@ -133,9 +134,9 @@ public class XORDecryptor extends Decryptor implements Cloneable { * the time we are about to write each of the bytes of the record data. * This (the value) is then incremented after each byte is written. */ - final int xorArrayIndex = _initialOffset+_recordEnd+(pos-_recordStart); + final int xorArrayIndex = initialOffset+recordEnd+(pos-recordStart); - for (int i=0; pos+i < _recordEnd && i < totalBytes; i++) { + for (int i=0; pos+i < recordEnd && i < totalBytes; i++) { // The following is taken from the Libre Office implementation // It seems that the encrypt and decrypt method is mixed up // in the MS-OFFCRYPTO docs @@ -165,8 +166,8 @@ public class XORDecryptor extends Decryptor implements Cloneable { final int pos = (int)getPos(); final byte chunk[] = getChunk(); final int chunkMask = getChunkMask(); - _recordStart = pos; - _recordEnd = _recordStart+recordSize; + recordStart = pos; + recordEnd = recordStart+recordSize; int nextBytes = Math.min(recordSize, chunk.length-(pos & chunkMask)); invokeCipher(nextBytes, true); } diff --git a/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptionVerifier.java b/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptionVerifier.java index 388e3d872..ba0645cb7 100644 --- a/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptionVerifier.java +++ b/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptionVerifier.java @@ -60,12 +60,12 @@ public class XOREncryptionVerifier extends EncryptionVerifier implements Encrypt } @Override - protected void setEncryptedVerifier(byte[] encryptedVerifier) { + protected final void setEncryptedVerifier(byte[] encryptedVerifier) { super.setEncryptedVerifier(encryptedVerifier); } @Override - protected void setEncryptedKey(byte[] encryptedKey) { + protected final void setEncryptedKey(byte[] encryptedKey) { super.setEncryptedKey(encryptedKey); } } diff --git a/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptor.java b/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptor.java index 4a0b48801..1c0834c8c 100644 --- a/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptor.java @@ -61,8 +61,7 @@ public class XOREncryptor extends Encryptor implements Cloneable { @Override public OutputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException { - OutputStream countStream = new XORCipherOutputStream(dir); - return countStream; + return new XORCipherOutputStream(dir); } @Override @@ -89,19 +88,15 @@ public class XOREncryptor extends Encryptor implements Cloneable { } private class XORCipherOutputStream extends ChunkedCipherOutputStream { - private final int _initialOffset; - private int _recordStart = 0; - private int _recordEnd = 0; - private boolean _isPlain = false; + private int recordStart = 0; + private int recordEnd = 0; public XORCipherOutputStream(OutputStream stream, int initialPos) throws IOException, GeneralSecurityException { super(stream, -1); - _initialOffset = initialPos; } public XORCipherOutputStream(DirectoryNode dir) throws IOException, GeneralSecurityException { super(dir, -1); - _initialOffset = 0; } @Override @@ -122,13 +117,12 @@ public class XOREncryptor extends Encryptor implements Cloneable { @Override public void setNextRecordSize(int recordSize, boolean isPlain) { - if (_recordEnd > 0 && !_isPlain) { + if (recordEnd > 0 && !isPlain) { // encrypt last record invokeCipher((int)getPos(), true); } - _recordStart = (int)getTotalPos()+4; - _recordEnd = _recordStart+recordSize; - _isPlain = isPlain; + recordStart = (int)getTotalPos()+4; + recordEnd = recordStart+recordSize; } @Override @@ -143,7 +137,7 @@ public class XOREncryptor extends Encryptor implements Cloneable { return 0; } - final int start = Math.max(posInChunk-(_recordEnd-_recordStart), 0); + final int start = Math.max(posInChunk-(recordEnd-recordStart), 0); final BitSet plainBytes = getPlainByteFlags(); final byte xorArray[] = getEncryptionInfo().getEncryptor().getSecretKey().getEncoded(); @@ -161,7 +155,7 @@ public class XOREncryptor extends Encryptor implements Cloneable { * This (the value) is then incremented after each byte is written. */ // ... also need to handle invocation in case of a filled chunk - int xorArrayIndex = _recordEnd+(start-_recordStart); + int xorArrayIndex = recordEnd+(start-recordStart); for (int i=start; i < posInChunk; i++) { byte value = chunk[i]; diff --git a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java index e6a77f854..e1b94b64e 100644 --- a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java +++ b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java @@ -573,8 +573,7 @@ public class POIXMLDocumentPart { } // Default to searching from 1, unless they asked for 0+ - int idx = minIdx; - if (minIdx < 0) idx = 1; + int idx = (minIdx < 0) ? 1 : minIdx; int maxIdx = minIdx + pkg.getParts().size(); while (idx <= maxIdx) { name = descriptor.getFileName(idx); diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java index ffe0cdf3f..0263790df 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java @@ -312,7 +312,7 @@ public class AgileDecryptor extends Decryptor implements Cloneable { } else { aps = new IvParameterSpec(iv); } - + existing.init(encryptionMode, skey, aps); return existing; diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java index 6d9ec6d66..186b27da5 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java @@ -21,7 +21,6 @@ import java.security.GeneralSecurityException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import java.util.List; @@ -68,11 +67,11 @@ public class AgileEncryptionVerifier extends EncryptionVerifier implements Clone throw new EncryptedDocumentException("Unable to parse keyData", e); } - int keyBits = (int)keyData.getKeyBits(); - CipherAlgorithm ca = CipherAlgorithm.fromXmlId(keyData.getCipherAlgorithm().toString(), keyBits); + int kb = (int)keyData.getKeyBits(); + CipherAlgorithm ca = CipherAlgorithm.fromXmlId(keyData.getCipherAlgorithm().toString(), kb); setCipherAlgorithm(ca); - setKeySize(keyBits); + setKeySize(kb); int blockSize = keyData.getBlockSize(); setBlockSize(blockSize); @@ -230,7 +229,7 @@ public class AgileEncryptionVerifier extends EncryptionVerifier implements Clone } @Override - protected void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) { + protected final void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) { super.setCipherAlgorithm(cipherAlgorithm); if (cipherAlgorithm.allowedKeySize.length == 1) { setKeySize(cipherAlgorithm.defaultKeySize); diff --git a/src/examples/src/org/apache/poi/crypt/examples/AesZipFileZipEntrySource.java b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java similarity index 91% rename from src/examples/src/org/apache/poi/crypt/examples/AesZipFileZipEntrySource.java rename to src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java index af281e259..5e1f4b383 100644 --- a/src/examples/src/org/apache/poi/crypt/examples/AesZipFileZipEntrySource.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java @@ -17,7 +17,7 @@ * ==================================================================== */ -package org.apache.poi.crypt.examples; +package org.apache.poi.poifs.crypt.temp; import java.io.File; import java.io.FileOutputStream; @@ -42,18 +42,24 @@ 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.Beta; import org.apache.poi.util.IOUtils; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; 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. */ +@Beta public class AesZipFileZipEntrySource implements ZipEntrySource { - final File tmpFile; - final ZipFile zipFile; - final Cipher ci; - boolean closed; + private static POILogger LOG = POILogFactory.getLogger(AesZipFileZipEntrySource.class); + + private final File tmpFile; + private final ZipFile zipFile; + private final Cipher ci; + private boolean closed; public AesZipFileZipEntrySource(File tmpFile, Cipher ci) throws IOException { this.tmpFile = tmpFile; @@ -81,7 +87,9 @@ public class AesZipFileZipEntrySource implements ZipEntrySource { public void close() throws IOException { if(!closed) { zipFile.close(); - tmpFile.delete(); + if (!tmpFile.delete()) { + LOG.log(POILogger.WARN, tmpFile.getAbsolutePath()+" can't be removed (or was already removed."); + }; } closed = true; } diff --git a/src/examples/src/org/apache/poi/crypt/examples/EncryptedTempData.java b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java similarity index 80% rename from src/examples/src/org/apache/poi/crypt/examples/EncryptedTempData.java rename to src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java index e4c5796d6..7a3981dc5 100644 --- a/src/examples/src/org/apache/poi/crypt/examples/EncryptedTempData.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java @@ -17,7 +17,7 @@ * ==================================================================== */ -package org.apache.poi.crypt.examples; +package org.apache.poi.poifs.crypt.temp; import java.io.File; import java.io.FileInputStream; @@ -35,16 +35,23 @@ 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.Beta; +import org.apache.poi.util.Internal; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; import org.apache.poi.util.TempFile; /** * EncryptedTempData can be used to buffer binary data in a secure way, by using encrypted temp files. */ +@Beta public class EncryptedTempData { - final static CipherAlgorithm cipherAlgorithm = CipherAlgorithm.aes128; - final SecretKeySpec skeySpec; - final byte[] ivBytes; - final File tempFile; + private static POILogger LOG = POILogFactory.getLogger(EncryptedTempData.class); + + private final static CipherAlgorithm cipherAlgorithm = CipherAlgorithm.aes128; + private final SecretKeySpec skeySpec; + private final byte[] ivBytes; + private final File tempFile; public EncryptedTempData() throws IOException { SecureRandom sr = new SecureRandom(); @@ -67,6 +74,8 @@ public class EncryptedTempData { } public void dispose() { - tempFile.delete(); + if (!tempFile.delete()) { + LOG.log(POILogger.WARN, tempFile.getAbsolutePath()+" can't be removed (or was already removed."); + } } } diff --git a/src/examples/src/org/apache/poi/xssf/streaming/examples/SXSSFWorkbookWithCustomZipEntrySource.java b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/SXSSFWorkbookWithCustomZipEntrySource.java similarity index 55% rename from src/examples/src/org/apache/poi/xssf/streaming/examples/SXSSFWorkbookWithCustomZipEntrySource.java rename to src/ooxml/java/org/apache/poi/poifs/crypt/temp/SXSSFWorkbookWithCustomZipEntrySource.java index 48f3f3a82..54600684e 100644 --- a/src/examples/src/org/apache/poi/xssf/streaming/examples/SXSSFWorkbookWithCustomZipEntrySource.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/SXSSFWorkbookWithCustomZipEntrySource.java @@ -17,33 +17,24 @@ * ==================================================================== */ -package org.apache.poi.xssf.streaming.examples; +package org.apache.poi.poifs.crypt.temp; -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.Beta; import org.apache.poi.util.IOUtils; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.streaming.SheetDataWriter; +@Beta public class SXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbook { - + private static final POILogger LOG = POILogFactory.getLogger(SXSSFWorkbookWithCustomZipEntrySource.class); + public SXSSFWorkbookWithCustomZipEntrySource() { super(20); setCompressTempFiles(true); @@ -74,40 +65,9 @@ public class SXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbook { @Override protected SheetDataWriter createSheetDataWriter() throws IOException { + //log values to ensure these values are accessible to subclasses + LOG.log(POILogger.INFO, "isCompressTempFiles: " + isCompressTempFiles()); + LOG.log(POILogger.INFO, "SharedStringSource: " + getSharedStringSource()); 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/ooxml/java/org/apache/poi/poifs/crypt/temp/SheetDataWriterWithDecorator.java b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/SheetDataWriterWithDecorator.java new file mode 100644 index 000000000..08163ead9 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/temp/SheetDataWriterWithDecorator.java @@ -0,0 +1,73 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.apache.poi.poifs.crypt.temp; + +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.Beta; +import org.apache.poi.xssf.streaming.SheetDataWriter; + +@Beta +public 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/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFReader.java b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFReader.java index 2accb0265..71942a132 100644 --- a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFReader.java +++ b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFReader.java @@ -230,9 +230,8 @@ public class XSSFReader { List validSheets = new ArrayList(); for (CTSheet ctSheet : wbBean.getSheets().getSheetList()) { //if there's no relationship id, silently skip the sheet - if ("".equals(ctSheet.getId())) { - //skip it - } else { + String sheetId = ctSheet.getId(); + if (sheetId != null && sheetId.length() > 0) { validSheets.add(ctSheet); } } 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 30c54b910..9820ddd0f 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java @@ -127,7 +127,7 @@ public class SheetDataWriter { _out.close(); } - File getTempFile(){ + protected File getTempFile(){ return _fd; } diff --git a/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java b/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java index 682b1cfd4..68799fdca 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java +++ b/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java @@ -16,8 +16,6 @@ ==================================================================== */ package org.apache.poi.xwpf.model; -import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; - import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.POIXMLDocumentPart.RelationPart; import org.apache.poi.util.POILogFactory; @@ -65,8 +63,6 @@ import com.microsoft.schemas.vml.STTrueFalse; * the right headers and footers for the document. */ public class XWPFHeaderFooterPolicy { - private static final POILogger LOG = POILogFactory.getLogger(XWPFHeaderFooterPolicy.class); - public static final Enum DEFAULT = STHdrFtr.DEFAULT; public static final Enum EVEN = STHdrFtr.EVEN; public static final Enum FIRST = STHdrFtr.FIRST; @@ -282,7 +278,7 @@ public class XWPFHeaderFooterPolicy { CTP p = ftr.addNewP(); ftr.setPArray(i, paragraphs[i].getCTP()); } - } else { +// } else { // CTP p = ftr.addNewP(); // CTBody body = doc.getDocument().getBody(); // if (body.sizeOfPArray() > 0) { diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java index eb9da3c33..9afde2caf 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java @@ -449,7 +449,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { CTOnOff titlePg = ctSectPr.addNewTitlePg(); titlePg.setVal(STOnOff.ON); } - } else if (type == HeaderFooterType.EVEN) { + // } else if (type == HeaderFooterType.EVEN) { // TODO Add support for Even/Odd headings and footers } return hfPolicy.createHeader(STHdrFtr.Enum.forInt(type.toInt())); @@ -471,7 +471,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { CTOnOff titlePg = ctSectPr.addNewTitlePg(); titlePg.setVal(STOnOff.ON); } - } else if (type == HeaderFooterType.EVEN) { + // } else if (type == HeaderFooterType.EVEN) { // TODO Add support for Even/Odd headings and footers } return hfPolicy.createFooter(STHdrFtr.Enum.forInt(type.toInt())); diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java deleted file mode 100644 index 4582c2ffd..000000000 --- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java +++ /dev/null @@ -1,140 +0,0 @@ -/* ==================================================================== - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -==================================================================== */ - -package org.apache.poi.poifs.crypt; - -import 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! - */ - @Override - public Enumeration getEntries() { - return zipFile.entries(); - } - - @Override - @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 { - if(!closed) { - 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 - @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 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 77ae0033a..e6224adf4 100644 --- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java +++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java @@ -29,6 +29,7 @@ import java.security.GeneralSecurityException; 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.crypt.temp.AesZipFileZipEntrySource; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.xssf.XSSFTestDataSamples; import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor; diff --git a/src/ooxml/testcases/org/apache/poi/xssf/streaming/TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource.java b/src/ooxml/testcases/org/apache/poi/xssf/streaming/TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource.java index 6c5a6c87e..cb90efb32 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/streaming/TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/streaming/TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource.java @@ -21,8 +21,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import org.apache.poi.xssf.streaming.TestSXSSFWorkbookWithCustomZipEntrySource.SXSSFWorkbookWithCustomZipEntrySource; -import org.apache.poi.xssf.streaming.TestSXSSFWorkbookWithCustomZipEntrySource.SheetDataWriterWithDecorator; +import org.apache.poi.poifs.crypt.temp.SXSSFWorkbookWithCustomZipEntrySource; +import org.apache.poi.poifs.crypt.temp.SheetDataWriterWithDecorator; // a class to record a list of temporary files that are written to disk // afterwards, a test function can check whether these files were encrypted or not diff --git a/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java b/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java index 7523f775e..b477c8b10 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java @@ -27,31 +27,19 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; 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.nio.charset.Charset; import java.security.GeneralSecurityException; -import java.security.SecureRandom; import java.util.List; -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.CipherOutputStream; -import javax.crypto.spec.SecretKeySpec; - import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.opc.OPCPackage; 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.poifs.crypt.temp.AesZipFileZipEntrySource; +import org.apache.poi.poifs.crypt.temp.EncryptedTempData; +import org.apache.poi.poifs.crypt.temp.SXSSFWorkbookWithCustomZipEntrySource; import org.apache.poi.util.IOUtils; -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; -import org.apache.poi.util.TempFile; import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; @@ -145,104 +133,4 @@ public final class TestSXSSFWorkbookWithCustomZipEntrySource { workbook.dispose(); assertFalse("tempFile deleted after dispose?", tempFile.exists()); } - - static class SXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbook { - - private static final POILogger logger = POILogFactory.getLogger(SXSSFWorkbookWithCustomZipEntrySource.class); - - @Override - public void write(OutputStream stream) throws IOException { - flushSheets(); - EncryptedTempData tempData = new EncryptedTempData(); - OutputStream os = tempData.getOutputStream(); - getXSSFWorkbook().write(os); - os.close(); - ZipEntrySource source = null; - try { - // 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 { - //log values to ensure these values are accessible to subclasses - logger.log(POILogger.INFO, "isCompressTempFiles: " + isCompressTempFiles()); - logger.log(POILogger.INFO, "SharedStringSource: " + getSharedStringSource()); - 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); - } - } - - // a class to save and read an AES-encrypted workbook - static class EncryptedTempData { - final static CipherAlgorithm cipherAlgorithm = CipherAlgorithm.aes128; - final SecretKeySpec skeySpec; - final byte[] ivBytes; - final File tempFile; - - 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"); - } - - OutputStream getOutputStream() throws IOException { - Cipher ciEnc = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.ENCRYPT_MODE, null); - return new CipherOutputStream(new FileOutputStream(tempFile), ciEnc); - } - - InputStream getInputStream() throws IOException { - Cipher ciDec = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.DECRYPT_MODE, null); - return new CipherInputStream(new FileInputStream(tempFile), ciDec); - } - - void dispose() { - assertTrue("Could not delete tempfile " + tempFile + ": " + tempFile.exists(), - !tempFile.exists() || tempFile.delete()); - } - } -} +} \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerV5.java b/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerV5.java index 6873d7599..6eaf0d44e 100644 --- a/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerV5.java +++ b/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerV5.java @@ -28,14 +28,24 @@ public final class PointerV5 extends Pointer { return (0x40 <= format && format < 0x50); } public boolean destinationHasPointers() { - if(type == 20) return true; - if(type == 22) return false; - if(format == 0x1d || format == 0x1e) return true; + if(type == 20) { + return true; + } + if(type == 22) { + return false; + } + if(format == 0x1d || format == 0x1e) { + return true; + } return (0x50 <= format && format < 0x60); } public boolean destinationHasChunks() { - if (type == 21) return true; - if (type == 24) return true; + if (type == 21) { + return true; + } + if (type == 24) { + return true; + } return (0xd0 <= format && format < 0xdf); } diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java b/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java index b0ce968e6..d68b4f701 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java +++ b/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java @@ -33,7 +33,7 @@ import org.apache.poi.util.Units; * Represents Macintosh PICT picture data. */ public final class PICT extends Metafile { - private static POILogger LOG = POILogFactory.getLogger(PICT.class); + private static final POILogger LOG = POILogFactory.getLogger(PICT.class); public static class NativeHeader { /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java index 5e045f526..740d9532d 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java @@ -346,7 +346,9 @@ public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformSh } private void fillPoint(byte xyMaster[], double xyPoints[]) { - if (xyMaster == null || xyPoints == null || (xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) { + int masterCnt = (xyMaster == null) ? 0 : xyMaster.length; + int pointCnt = (xyPoints == null) ? 0 : xyPoints.length; + if ((masterCnt != 4 && masterCnt != 8) || pointCnt != 2) { logger.log(POILogger.WARN, "Invalid number of master bytes for a single point - ignore point"); return; }