Bugzilla 52690 - added a getter for length of encrypted data in Ecma and Agile decryptors
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1293784 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a6aa1fd99e
commit
582ea1c54c
@ -34,6 +34,7 @@
|
||||
|
||||
<changes>
|
||||
<release version="3.8-beta6" date="2012-??-??">
|
||||
<action dev="poi-developers" type="fix">52690 - added a getter for length of encrypted data in Ecma and Agile decryptors</action>
|
||||
<action dev="poi-developers" type="fix">52255 - support adding TIFF,EPS and WPG pictures in OOXML documents </action>
|
||||
<action dev="poi-developers" type="fix">52078 - avoid OutOfMemoryError when rendering groupped pictures in HSLF </action>
|
||||
<action dev="poi-developers" type="fix">52745 - fixed XSSFRichtextString.append to preserve leading / trailing spaces </action>
|
||||
|
@ -19,24 +19,18 @@ package org.apache.poi.poifs.crypt;
|
||||
import java.util.Arrays;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherInputStream;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
||||
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
@ -46,6 +40,7 @@ public class AgileDecryptor extends Decryptor {
|
||||
|
||||
private final EncryptionInfo _info;
|
||||
private SecretKey _secretKey;
|
||||
private long _length = -1;
|
||||
|
||||
private static final byte[] kVerifierInputBlock;
|
||||
private static final byte[] kHashedVerifierBlock;
|
||||
@ -104,8 +99,13 @@ public class AgileDecryptor extends Decryptor {
|
||||
|
||||
public InputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException {
|
||||
DocumentInputStream dis = dir.createDocumentInputStream("EncryptedPackage");
|
||||
long size = dis.readLong();
|
||||
return new ChunkedCipherInputStream(dis, size);
|
||||
_length = dis.readLong();
|
||||
return new ChunkedCipherInputStream(dis, _length);
|
||||
}
|
||||
|
||||
public long getLength(){
|
||||
if(_length == -1) throw new IllegalStateException("EcmaDecryptor.getDataStream() was not called");
|
||||
return _length;
|
||||
}
|
||||
|
||||
protected AgileDecryptor(EncryptionInfo info) {
|
||||
@ -182,7 +182,7 @@ public class AgileDecryptor extends Decryptor {
|
||||
private byte[] nextChunk() throws GeneralSecurityException, IOException {
|
||||
int index = (int)(_pos >> 12);
|
||||
byte[] blockKey = new byte[4];
|
||||
LittleEndian.putInt(blockKey, index);
|
||||
LittleEndian.putInt(blockKey, 0, index);
|
||||
byte[] iv = generateIv(_info.getHeader().getAlgorithm(),
|
||||
_info.getHeader().getKeySalt(), blockKey);
|
||||
_cipher.init(Cipher.DECRYPT_MODE, _secretKey, new IvParameterSpec(iv));
|
||||
|
@ -31,12 +31,40 @@ import org.apache.poi.util.LittleEndian;
|
||||
public abstract class Decryptor {
|
||||
public static final String DEFAULT_PASSWORD="VelvetSweatshop";
|
||||
|
||||
/**
|
||||
* Return a stream with decrypted data.
|
||||
* <p>
|
||||
* Use {@link #getLength()} to get the size of that data that can be safely read from the stream.
|
||||
* Just reading to the end of the input stream is not sufficient because there are
|
||||
* normally padding bytes that must be discarded
|
||||
* </p>
|
||||
*
|
||||
* @param dir the node to read from
|
||||
* @return decrypted stream
|
||||
*/
|
||||
public abstract InputStream getDataStream(DirectoryNode dir)
|
||||
throws IOException, GeneralSecurityException;
|
||||
|
||||
public abstract boolean verifyPassword(String password)
|
||||
throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Returns the length of the encytpted data that can be safely read with
|
||||
* {@link #getDataStream(org.apache.poi.poifs.filesystem.DirectoryNode)}.
|
||||
* Just reading to the end of the input stream is not sufficient because there are
|
||||
* normally padding bytes that must be discarded
|
||||
*
|
||||
* <p>
|
||||
* The length variable is initialized in {@link #getDataStream(org.apache.poi.poifs.filesystem.DirectoryNode)},
|
||||
* an attempt to call getLength() prior to getDataStream() will result in IllegalStateException.
|
||||
* </p>
|
||||
*
|
||||
* @return length of the encrypted data
|
||||
* @throws IllegalStateException if {@link #getDataStream(org.apache.poi.poifs.filesystem.DirectoryNode)}
|
||||
* was not called
|
||||
*/
|
||||
public abstract long getLength();
|
||||
|
||||
public static Decryptor getInstance(EncryptionInfo info) {
|
||||
int major = info.getVersionMajor();
|
||||
int minor = info.getVersionMinor();
|
||||
@ -82,7 +110,7 @@ public abstract class Decryptor {
|
||||
|
||||
for (int i = 0; i < info.getVerifier().getSpinCount(); i++) {
|
||||
sha1.reset();
|
||||
LittleEndian.putInt(iterator, i);
|
||||
LittleEndian.putInt(iterator, 0, i);
|
||||
sha1.update(iterator);
|
||||
hash = sha1.digest(hash);
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ package org.apache.poi.poifs.crypt;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@ -31,7 +30,6 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
@ -41,6 +39,7 @@ import org.apache.poi.util.LittleEndian;
|
||||
public class EcmaDecryptor extends Decryptor {
|
||||
private final EncryptionInfo info;
|
||||
private byte[] passwordHash;
|
||||
private long _length = -1;
|
||||
|
||||
public EcmaDecryptor(EncryptionInfo info) {
|
||||
this.info = info;
|
||||
@ -51,7 +50,7 @@ public class EcmaDecryptor extends Decryptor {
|
||||
|
||||
sha1.update(passwordHash);
|
||||
byte[] blockValue = new byte[4];
|
||||
LittleEndian.putInt(blockValue, block);
|
||||
LittleEndian.putInt(blockValue, 0, block);
|
||||
byte[] finalHash = sha1.digest(blockValue);
|
||||
|
||||
int requiredKeyLength = info.getHeader().getKeySize()/8;
|
||||
@ -125,8 +124,13 @@ public class EcmaDecryptor extends Decryptor {
|
||||
public InputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException {
|
||||
DocumentInputStream dis = dir.createDocumentInputStream("EncryptedPackage");
|
||||
|
||||
long size = dis.readLong();
|
||||
_length = dis.readLong();
|
||||
|
||||
return new CipherInputStream(dis, getCipher());
|
||||
}
|
||||
|
||||
public long getLength(){
|
||||
if(_length == -1) throw new IllegalStateException("EcmaDecryptor.getDataStream() was not called");
|
||||
return _length;
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,9 @@ import junit.framework.TestCase;
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
@ -80,4 +82,36 @@ public class TestDecryptor extends TestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
public void testDataLength() throws Exception {
|
||||
POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_agile.docx"));
|
||||
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
|
||||
d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
|
||||
|
||||
InputStream is = d.getDataStream(fs);
|
||||
|
||||
long len = d.getLength();
|
||||
assertEquals(12810, len);
|
||||
|
||||
byte[] buf = new byte[(int)len];
|
||||
|
||||
is.read(buf);
|
||||
|
||||
ZipInputStream zin = new ZipInputStream(new ByteArrayInputStream(buf));
|
||||
|
||||
while (true) {
|
||||
ZipEntry entry = zin.getNextEntry();
|
||||
if (entry==null) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (zin.available()>0) {
|
||||
zin.skip(zin.available());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user