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:
Andreas Beeker 2014-04-21 12:16:54 +00:00
parent d3ad1a9bb8
commit 821d3ca5bd
7 changed files with 60 additions and 59 deletions

View File

@ -195,16 +195,18 @@ public class CryptoFunctions {
try {
// 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");
}
Cipher cipher;
if (cipherAlgorithm.needsBouncyCastle) {
if (cipherAlgorithm == CipherAlgorithm.rc4) {
cipher = Cipher.getInstance(cipherAlgorithm.jceId);
} else if (cipherAlgorithm.needsBouncyCastle) {
registerBouncyCastle();
cipher = Cipher.getInstance(key.getAlgorithm() + "/" + chain.jceId + "/" + padding, "BC");
cipher = Cipher.getInstance(cipherAlgorithm.jceId + "/" + chain.jceId + "/" + padding, "BC");
} else {
cipher = Cipher.getInstance(key.getAlgorithm() + "/" + chain.jceId + "/" + padding);
cipher = Cipher.getInstance(cipherAlgorithm.jceId + "/" + chain.jceId + "/" + padding);
}
if (vec == null) {
@ -282,7 +284,6 @@ public class CryptoFunctions {
}
}
private static final int InitialCodeArray[] = {
0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE,
0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A,

View File

@ -16,14 +16,11 @@
==================================================================== */
package org.apache.poi.poifs.crypt.agile;
import java.io.IOException;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.crypt.ChainingMode;
import org.apache.poi.poifs.crypt.CipherAlgorithm;
import org.apache.poi.poifs.crypt.EncryptionHeader;
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.CTKeyData;
@ -33,14 +30,11 @@ import com.microsoft.schemas.office.x2006.encryption.STCipherChaining;
public class AgileEncryptionHeader extends EncryptionHeader {
private byte encryptedHmacKey[], encryptedHmacValue[];
public AgileEncryptionHeader(String descriptor) throws IOException {
EncryptionDocument ed;
try {
ed = EncryptionDocument.Factory.parse(descriptor);
} catch (XmlException e) {
throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);
}
public AgileEncryptionHeader(String descriptor) {
this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor));
}
protected AgileEncryptionHeader(EncryptionDocument ed) {
CTKeyData keyData;
try {
keyData = ed.getEncryption().getKeyData();

View File

@ -17,14 +17,19 @@
package org.apache.poi.poifs.crypt.agile;
import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.crypt.ChainingMode;
import org.apache.poi.poifs.crypt.CipherAlgorithm;
import org.apache.poi.poifs.crypt.EncryptionInfo;
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.filesystem.DocumentInputStream;
import org.apache.xmlbeans.XmlException;
import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
@ -37,15 +42,11 @@ public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
public void initialize(EncryptionInfo info, DocumentInputStream dis) throws IOException {
this.info = info;
StringBuilder builder = new StringBuilder();
byte[] xmlDescriptor = new byte[dis.available()];
dis.read(xmlDescriptor);
for (byte b : xmlDescriptor)
builder.append((char)b);
String descriptor = builder.toString();
header = new AgileEncryptionHeader(descriptor);
verifier = new AgileEncryptionVerifier(descriptor);
if (info.getVersionMajor() == 4 && info.getVersionMinor() == 4) {
EncryptionDocument ed = parseDescriptor(dis);
header = new AgileEncryptionHeader(ed);
verifier = new AgileEncryptionVerifier(ed);
if (info.getVersionMajor() == EncryptionMode.agile.versionMajor
&& info.getVersionMinor() == EncryptionMode.agile.versionMinor) {
decryptor = new AgileDecryptor(this);
}
}
@ -107,5 +108,19 @@ public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
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);
}
}
}

View File

@ -29,7 +29,6 @@ import org.apache.poi.poifs.crypt.ChainingMode;
import org.apache.poi.poifs.crypt.CipherAlgorithm;
import org.apache.poi.poifs.crypt.EncryptionVerifier;
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.EncryptionDocument;
@ -50,15 +49,11 @@ public class AgileEncryptionVerifier extends EncryptionVerifier {
private List<AgileCertificateEntry> certList = new ArrayList<AgileCertificateEntry>();
public AgileEncryptionVerifier(String descriptor) {
EncryptionDocument ed;
try {
ed = EncryptionDocument.Factory.parse(descriptor);
} catch (XmlException e) {
throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);
}
this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor));
}
protected AgileEncryptionVerifier(EncryptionDocument ed) {
Iterator<CTKeyEncryptor> encList = ed.getEncryption().getKeyEncryptors().getKeyEncryptorList().iterator();
CTPasswordKeyEncryptor keyData;
try {

View File

@ -403,6 +403,11 @@ public class AgileEncryptor extends Encryptor {
}
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();
AgileEncryptionHeader header = builder.getHeader();
@ -412,7 +417,7 @@ public class AgileEncryptor extends Encryptor {
CTKeyData keyData = edRoot.addNewKeyData();
CTKeyEncryptors keyEncList = edRoot.addNewKeyEncryptors();
CTKeyEncryptor keyEnc = keyEncList.addNewKeyEncryptor();
keyEnc.setUri(CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_PASSWORD);
keyEnc.setUri(passwordUri);
CTPasswordKeyEncryptor keyPass = keyEnc.addNewEncryptedPasswordKey();
keyPass.setSpinCount(ver.getSpinCount());
@ -469,7 +474,7 @@ public class AgileEncryptor extends Encryptor {
for (AgileCertificateEntry ace : ver.getCertificates()) {
keyEnc = keyEncList.addNewKeyEncryptor();
keyEnc.setUri(CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_CERTIFICATE);
keyEnc.setUri(certificateUri);
CTCertificateKeyEncryptor certData = keyEnc.addNewEncryptedCertificateKey();
try {
certData.setX509Certificate(ace.x509.getEncoded());
@ -479,13 +484,13 @@ public class AgileEncryptor extends Encryptor {
certData.setEncryptedKeyValue(ace.encryptedKey);
certData.setCertVerifier(ace.certVerifier);
}
XmlOptions xo = new XmlOptions();
xo.setCharacterEncoding("UTF-8");
Map<String,String> nsMap = new HashMap<String,String>();
nsMap.put("http://schemas.microsoft.com/office/2006/keyEncryptor/password","p");
nsMap.put("http://schemas.microsoft.com/office/2006/keyEncryptor/certificate", "c");
nsMap.put("http://schemas.microsoft.com/office/2006/encryption","");
nsMap.put(passwordUri.toString(),"p");
nsMap.put(certificateUri.toString(), "c");
xo.setUseDefaultNamespace();
xo.setSaveSuggestedPrefixes(nsMap);
xo.setSaveNamespacesFirst();
xo.setSaveAggressiveNamespaces();
@ -505,7 +510,7 @@ public class AgileEncryptor extends Encryptor {
leos.writeShort(info.getVersionMajor());
leos.writeShort(info.getVersionMinor());
// Reserved (4 bytes): A value that MUST be 0x00000040
leos.writeInt(0x40);
leos.writeInt(info.getEncryptionFlags());
leos.write(bos.toByteArray());
dir.createDocument("EncryptionInfo", leos.getWriteIndex(), new POIFSWriterListener() {

View File

@ -21,7 +21,6 @@ import java.awt.Graphics2D;
import java.io.IOException;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.poi.hslf.blip.BitmapPainter;
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.PNG;
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.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -138,14 +138,9 @@ public abstract class PictureData {
* Compute 16-byte checksum of this picture using MD5 algorithm.
*/
public static byte[] getChecksum(byte[] data) {
MessageDigest sha;
try {
sha = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e){
throw new HSLFException(e.getMessage());
}
sha.update(data);
return sha.digest();
MessageDigest md5 = CryptoFunctions.getMessageDigest(HashAlgorithm.md5);
md5.update(data);
return md5.digest();
}
/**

View File

@ -31,7 +31,6 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -43,6 +42,8 @@ import java.util.Stack;
import java.util.zip.ZipException;
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.ContentHandler;
import org.xml.sax.InputSource;
@ -542,12 +543,7 @@ public final class ExcelFileFormatDocFunctionExtractor {
* Helps identify the source file
*/
private static String getFileMD5(File f) {
MessageDigest m;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
MessageDigest m = CryptoFunctions.getMessageDigest(HashAlgorithm.md5);
byte[]buf = new byte[2048];
try {