- 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
This commit is contained in:
Andreas Beeker 2016-11-11 23:22:43 +00:00
parent 3820215393
commit fc86b15f13
37 changed files with 415 additions and 612 deletions

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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)

View File

@ -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 {

View File

@ -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);

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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];

View File

@ -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);

View File

@ -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);

View File

@ -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 <code>ZipEntrySource</code> 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;
}

View File

@ -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.");
}
}
}

View File

@ -17,32 +17,23 @@
* ====================================================================
*/
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);
@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -230,9 +230,8 @@ public class XSSFReader {
List<CTSheet> validSheets = new ArrayList<CTSheet>();
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);
}
}

View File

@ -127,7 +127,7 @@ public class SheetDataWriter {
_out.close();
}
File getTempFile(){
protected File getTempFile(){
return _fd;
}

View File

@ -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) {

View File

@ -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()));

View File

@ -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<? extends ZipEntry> 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);
}
}

View File

@ -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;

View File

@ -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

View File

@ -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());
}
}
}

View File

@ -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);
}

View File

@ -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 {
/**

View File

@ -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;
}