mirror of https://github.com/apache/poi.git
Some encryption fixes:
- don't rely on SecretKey object having the right algorithm set - leave encryption-description parsing of string/stream to xmlbeans and refactor it to one location - use namespaces of schema instead of hard-coded strings - use CryptoFunctions.getMessageDigest() instead of code duplication git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1588874 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
740c46ef84
commit
f566b57be0
|
@ -195,16 +195,18 @@ public class CryptoFunctions {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Ensure the JCE policies files allow for this sized key
|
// Ensure the JCE policies files allow for this sized key
|
||||||
if (Cipher.getMaxAllowedKeyLength(key.getAlgorithm()) < keySizeInBytes*8) {
|
if (Cipher.getMaxAllowedKeyLength(cipherAlgorithm.jceId) < keySizeInBytes*8) {
|
||||||
throw new EncryptedDocumentException("Export Restrictions in place - please install JCE Unlimited Strength Jurisdiction Policy files");
|
throw new EncryptedDocumentException("Export Restrictions in place - please install JCE Unlimited Strength Jurisdiction Policy files");
|
||||||
}
|
}
|
||||||
|
|
||||||
Cipher cipher;
|
Cipher cipher;
|
||||||
if (cipherAlgorithm.needsBouncyCastle) {
|
if (cipherAlgorithm == CipherAlgorithm.rc4) {
|
||||||
|
cipher = Cipher.getInstance(cipherAlgorithm.jceId);
|
||||||
|
} else if (cipherAlgorithm.needsBouncyCastle) {
|
||||||
registerBouncyCastle();
|
registerBouncyCastle();
|
||||||
cipher = Cipher.getInstance(key.getAlgorithm() + "/" + chain.jceId + "/" + padding, "BC");
|
cipher = Cipher.getInstance(cipherAlgorithm.jceId + "/" + chain.jceId + "/" + padding, "BC");
|
||||||
} else {
|
} else {
|
||||||
cipher = Cipher.getInstance(key.getAlgorithm() + "/" + chain.jceId + "/" + padding);
|
cipher = Cipher.getInstance(cipherAlgorithm.jceId + "/" + chain.jceId + "/" + padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vec == null) {
|
if (vec == null) {
|
||||||
|
@ -282,7 +284,6 @@ public class CryptoFunctions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static final int InitialCodeArray[] = {
|
private static final int InitialCodeArray[] = {
|
||||||
0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE,
|
0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE,
|
||||||
0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A,
|
0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A,
|
||||||
|
|
|
@ -16,14 +16,11 @@
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
package org.apache.poi.poifs.crypt.agile;
|
package org.apache.poi.poifs.crypt.agile;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.poi.EncryptedDocumentException;
|
import org.apache.poi.EncryptedDocumentException;
|
||||||
import org.apache.poi.poifs.crypt.ChainingMode;
|
import org.apache.poi.poifs.crypt.ChainingMode;
|
||||||
import org.apache.poi.poifs.crypt.CipherAlgorithm;
|
import org.apache.poi.poifs.crypt.CipherAlgorithm;
|
||||||
import org.apache.poi.poifs.crypt.EncryptionHeader;
|
import org.apache.poi.poifs.crypt.EncryptionHeader;
|
||||||
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
|
|
||||||
import com.microsoft.schemas.office.x2006.encryption.CTDataIntegrity;
|
import com.microsoft.schemas.office.x2006.encryption.CTDataIntegrity;
|
||||||
import com.microsoft.schemas.office.x2006.encryption.CTKeyData;
|
import com.microsoft.schemas.office.x2006.encryption.CTKeyData;
|
||||||
|
@ -33,14 +30,11 @@ import com.microsoft.schemas.office.x2006.encryption.STCipherChaining;
|
||||||
public class AgileEncryptionHeader extends EncryptionHeader {
|
public class AgileEncryptionHeader extends EncryptionHeader {
|
||||||
private byte encryptedHmacKey[], encryptedHmacValue[];
|
private byte encryptedHmacKey[], encryptedHmacValue[];
|
||||||
|
|
||||||
public AgileEncryptionHeader(String descriptor) throws IOException {
|
public AgileEncryptionHeader(String descriptor) {
|
||||||
EncryptionDocument ed;
|
this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor));
|
||||||
try {
|
}
|
||||||
ed = EncryptionDocument.Factory.parse(descriptor);
|
|
||||||
} catch (XmlException e) {
|
protected AgileEncryptionHeader(EncryptionDocument ed) {
|
||||||
throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
CTKeyData keyData;
|
CTKeyData keyData;
|
||||||
try {
|
try {
|
||||||
keyData = ed.getEncryption().getKeyData();
|
keyData = ed.getEncryption().getKeyData();
|
||||||
|
|
|
@ -17,14 +17,19 @@
|
||||||
package org.apache.poi.poifs.crypt.agile;
|
package org.apache.poi.poifs.crypt.agile;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.apache.poi.EncryptedDocumentException;
|
import org.apache.poi.EncryptedDocumentException;
|
||||||
import org.apache.poi.poifs.crypt.ChainingMode;
|
import org.apache.poi.poifs.crypt.ChainingMode;
|
||||||
import org.apache.poi.poifs.crypt.CipherAlgorithm;
|
import org.apache.poi.poifs.crypt.CipherAlgorithm;
|
||||||
import org.apache.poi.poifs.crypt.EncryptionInfo;
|
import org.apache.poi.poifs.crypt.EncryptionInfo;
|
||||||
import org.apache.poi.poifs.crypt.EncryptionInfoBuilder;
|
import org.apache.poi.poifs.crypt.EncryptionInfoBuilder;
|
||||||
|
import org.apache.poi.poifs.crypt.EncryptionMode;
|
||||||
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||||
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||||
|
import org.apache.xmlbeans.XmlException;
|
||||||
|
|
||||||
|
import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
|
||||||
|
|
||||||
public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
|
public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
|
||||||
|
|
||||||
|
@ -37,15 +42,11 @@ public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
|
||||||
public void initialize(EncryptionInfo info, DocumentInputStream dis) throws IOException {
|
public void initialize(EncryptionInfo info, DocumentInputStream dis) throws IOException {
|
||||||
this.info = info;
|
this.info = info;
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
EncryptionDocument ed = parseDescriptor(dis);
|
||||||
byte[] xmlDescriptor = new byte[dis.available()];
|
header = new AgileEncryptionHeader(ed);
|
||||||
dis.read(xmlDescriptor);
|
verifier = new AgileEncryptionVerifier(ed);
|
||||||
for (byte b : xmlDescriptor)
|
if (info.getVersionMajor() == EncryptionMode.agile.versionMajor
|
||||||
builder.append((char)b);
|
&& info.getVersionMinor() == EncryptionMode.agile.versionMinor) {
|
||||||
String descriptor = builder.toString();
|
|
||||||
header = new AgileEncryptionHeader(descriptor);
|
|
||||||
verifier = new AgileEncryptionVerifier(descriptor);
|
|
||||||
if (info.getVersionMajor() == 4 && info.getVersionMinor() == 4) {
|
|
||||||
decryptor = new AgileDecryptor(this);
|
decryptor = new AgileDecryptor(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,5 +108,19 @@ public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static EncryptionDocument parseDescriptor(String descriptor) {
|
||||||
|
try {
|
||||||
|
return EncryptionDocument.Factory.parse(descriptor);
|
||||||
|
} catch (XmlException e) {
|
||||||
|
throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static EncryptionDocument parseDescriptor(InputStream descriptor) {
|
||||||
|
try {
|
||||||
|
return EncryptionDocument.Factory.parse(descriptor);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import org.apache.poi.poifs.crypt.ChainingMode;
|
||||||
import org.apache.poi.poifs.crypt.CipherAlgorithm;
|
import org.apache.poi.poifs.crypt.CipherAlgorithm;
|
||||||
import org.apache.poi.poifs.crypt.EncryptionVerifier;
|
import org.apache.poi.poifs.crypt.EncryptionVerifier;
|
||||||
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
|
|
||||||
import com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptor;
|
import com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptor;
|
||||||
import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
|
import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
|
||||||
|
@ -50,15 +49,11 @@ public class AgileEncryptionVerifier extends EncryptionVerifier {
|
||||||
|
|
||||||
private List<AgileCertificateEntry> certList = new ArrayList<AgileCertificateEntry>();
|
private List<AgileCertificateEntry> certList = new ArrayList<AgileCertificateEntry>();
|
||||||
|
|
||||||
|
|
||||||
public AgileEncryptionVerifier(String descriptor) {
|
public AgileEncryptionVerifier(String descriptor) {
|
||||||
EncryptionDocument ed;
|
this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor));
|
||||||
try {
|
}
|
||||||
ed = EncryptionDocument.Factory.parse(descriptor);
|
|
||||||
} catch (XmlException e) {
|
protected AgileEncryptionVerifier(EncryptionDocument ed) {
|
||||||
throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<CTKeyEncryptor> encList = ed.getEncryption().getKeyEncryptors().getKeyEncryptorList().iterator();
|
Iterator<CTKeyEncryptor> encList = ed.getEncryption().getKeyEncryptors().getKeyEncryptorList().iterator();
|
||||||
CTPasswordKeyEncryptor keyData;
|
CTPasswordKeyEncryptor keyData;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -403,6 +403,11 @@ public class AgileEncryptor extends Encryptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createEncryptionInfoEntry(DirectoryNode dir) throws IOException {
|
protected void createEncryptionInfoEntry(DirectoryNode dir) throws IOException {
|
||||||
|
final CTKeyEncryptor.Uri.Enum passwordUri =
|
||||||
|
CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_PASSWORD;
|
||||||
|
final CTKeyEncryptor.Uri.Enum certificateUri =
|
||||||
|
CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_CERTIFICATE;
|
||||||
|
|
||||||
AgileEncryptionVerifier ver = builder.getVerifier();
|
AgileEncryptionVerifier ver = builder.getVerifier();
|
||||||
AgileEncryptionHeader header = builder.getHeader();
|
AgileEncryptionHeader header = builder.getHeader();
|
||||||
|
|
||||||
|
@ -412,7 +417,7 @@ public class AgileEncryptor extends Encryptor {
|
||||||
CTKeyData keyData = edRoot.addNewKeyData();
|
CTKeyData keyData = edRoot.addNewKeyData();
|
||||||
CTKeyEncryptors keyEncList = edRoot.addNewKeyEncryptors();
|
CTKeyEncryptors keyEncList = edRoot.addNewKeyEncryptors();
|
||||||
CTKeyEncryptor keyEnc = keyEncList.addNewKeyEncryptor();
|
CTKeyEncryptor keyEnc = keyEncList.addNewKeyEncryptor();
|
||||||
keyEnc.setUri(CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_PASSWORD);
|
keyEnc.setUri(passwordUri);
|
||||||
CTPasswordKeyEncryptor keyPass = keyEnc.addNewEncryptedPasswordKey();
|
CTPasswordKeyEncryptor keyPass = keyEnc.addNewEncryptedPasswordKey();
|
||||||
|
|
||||||
keyPass.setSpinCount(ver.getSpinCount());
|
keyPass.setSpinCount(ver.getSpinCount());
|
||||||
|
@ -469,7 +474,7 @@ public class AgileEncryptor extends Encryptor {
|
||||||
|
|
||||||
for (AgileCertificateEntry ace : ver.getCertificates()) {
|
for (AgileCertificateEntry ace : ver.getCertificates()) {
|
||||||
keyEnc = keyEncList.addNewKeyEncryptor();
|
keyEnc = keyEncList.addNewKeyEncryptor();
|
||||||
keyEnc.setUri(CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_CERTIFICATE);
|
keyEnc.setUri(certificateUri);
|
||||||
CTCertificateKeyEncryptor certData = keyEnc.addNewEncryptedCertificateKey();
|
CTCertificateKeyEncryptor certData = keyEnc.addNewEncryptedCertificateKey();
|
||||||
try {
|
try {
|
||||||
certData.setX509Certificate(ace.x509.getEncoded());
|
certData.setX509Certificate(ace.x509.getEncoded());
|
||||||
|
@ -479,13 +484,13 @@ public class AgileEncryptor extends Encryptor {
|
||||||
certData.setEncryptedKeyValue(ace.encryptedKey);
|
certData.setEncryptedKeyValue(ace.encryptedKey);
|
||||||
certData.setCertVerifier(ace.certVerifier);
|
certData.setCertVerifier(ace.certVerifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlOptions xo = new XmlOptions();
|
XmlOptions xo = new XmlOptions();
|
||||||
xo.setCharacterEncoding("UTF-8");
|
xo.setCharacterEncoding("UTF-8");
|
||||||
Map<String,String> nsMap = new HashMap<String,String>();
|
Map<String,String> nsMap = new HashMap<String,String>();
|
||||||
nsMap.put("http://schemas.microsoft.com/office/2006/keyEncryptor/password","p");
|
nsMap.put(passwordUri.toString(),"p");
|
||||||
nsMap.put("http://schemas.microsoft.com/office/2006/keyEncryptor/certificate", "c");
|
nsMap.put(certificateUri.toString(), "c");
|
||||||
nsMap.put("http://schemas.microsoft.com/office/2006/encryption","");
|
xo.setUseDefaultNamespace();
|
||||||
xo.setSaveSuggestedPrefixes(nsMap);
|
xo.setSaveSuggestedPrefixes(nsMap);
|
||||||
xo.setSaveNamespacesFirst();
|
xo.setSaveNamespacesFirst();
|
||||||
xo.setSaveAggressiveNamespaces();
|
xo.setSaveAggressiveNamespaces();
|
||||||
|
@ -505,7 +510,7 @@ public class AgileEncryptor extends Encryptor {
|
||||||
leos.writeShort(info.getVersionMajor());
|
leos.writeShort(info.getVersionMajor());
|
||||||
leos.writeShort(info.getVersionMinor());
|
leos.writeShort(info.getVersionMinor());
|
||||||
// Reserved (4 bytes): A value that MUST be 0x00000040
|
// Reserved (4 bytes): A value that MUST be 0x00000040
|
||||||
leos.writeInt(0x40);
|
leos.writeInt(info.getEncryptionFlags());
|
||||||
leos.write(bos.toByteArray());
|
leos.write(bos.toByteArray());
|
||||||
|
|
||||||
dir.createDocument("EncryptionInfo", leos.getWriteIndex(), new POIFSWriterListener() {
|
dir.createDocument("EncryptionInfo", leos.getWriteIndex(), new POIFSWriterListener() {
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.awt.Graphics2D;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
import org.apache.poi.hslf.blip.BitmapPainter;
|
import org.apache.poi.hslf.blip.BitmapPainter;
|
||||||
import org.apache.poi.hslf.blip.DIB;
|
import org.apache.poi.hslf.blip.DIB;
|
||||||
|
@ -31,8 +30,9 @@ import org.apache.poi.hslf.blip.JPEG;
|
||||||
import org.apache.poi.hslf.blip.PICT;
|
import org.apache.poi.hslf.blip.PICT;
|
||||||
import org.apache.poi.hslf.blip.PNG;
|
import org.apache.poi.hslf.blip.PNG;
|
||||||
import org.apache.poi.hslf.blip.WMF;
|
import org.apache.poi.hslf.blip.WMF;
|
||||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
|
||||||
import org.apache.poi.hslf.model.Picture;
|
import org.apache.poi.hslf.model.Picture;
|
||||||
|
import org.apache.poi.poifs.crypt.CryptoFunctions;
|
||||||
|
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
|
@ -138,14 +138,9 @@ public abstract class PictureData {
|
||||||
* Compute 16-byte checksum of this picture using MD5 algorithm.
|
* Compute 16-byte checksum of this picture using MD5 algorithm.
|
||||||
*/
|
*/
|
||||||
public static byte[] getChecksum(byte[] data) {
|
public static byte[] getChecksum(byte[] data) {
|
||||||
MessageDigest sha;
|
MessageDigest md5 = CryptoFunctions.getMessageDigest(HashAlgorithm.md5);
|
||||||
try {
|
md5.update(data);
|
||||||
sha = MessageDigest.getInstance("MD5");
|
return md5.digest();
|
||||||
} catch (NoSuchAlgorithmException e){
|
|
||||||
throw new HSLFException(e.getMessage());
|
|
||||||
}
|
|
||||||
sha.update(data);
|
|
||||||
return sha.digest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -31,7 +31,6 @@ import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -43,6 +42,8 @@ import java.util.Stack;
|
||||||
import java.util.zip.ZipException;
|
import java.util.zip.ZipException;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import org.apache.poi.poifs.crypt.CryptoFunctions;
|
||||||
|
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
import org.xml.sax.ContentHandler;
|
import org.xml.sax.ContentHandler;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
|
@ -542,12 +543,7 @@ public final class ExcelFileFormatDocFunctionExtractor {
|
||||||
* Helps identify the source file
|
* Helps identify the source file
|
||||||
*/
|
*/
|
||||||
private static String getFileMD5(File f) {
|
private static String getFileMD5(File f) {
|
||||||
MessageDigest m;
|
MessageDigest m = CryptoFunctions.getMessageDigest(HashAlgorithm.md5);
|
||||||
try {
|
|
||||||
m = MessageDigest.getInstance("MD5");
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[]buf = new byte[2048];
|
byte[]buf = new byte[2048];
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue