]> source.dussan.org Git - poi.git/commitdiff
Some encryption fixes:
authorAndreas Beeker <kiwiwings@apache.org>
Mon, 21 Apr 2014 12:16:54 +0000 (12:16 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Mon, 21 Apr 2014 12:16:54 +0000 (12:16 +0000)
- 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

src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java
src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java
src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java
src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java
src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/PictureData.java
src/testcases/org/apache/poi/ss/formula/function/ExcelFileFormatDocFunctionExtractor.java

index 0349c5c67afd0d90e6af397bd889a9db2a17c79c..f5f52b93f4c5892492b73adc36380d5241cce530 100644 (file)
@@ -195,16 +195,18 @@ public class CryptoFunctions {
         \r
         try {\r
             // Ensure the JCE policies files allow for this sized key\r
-            if (Cipher.getMaxAllowedKeyLength(key.getAlgorithm()) < keySizeInBytes*8) {\r
+            if (Cipher.getMaxAllowedKeyLength(cipherAlgorithm.jceId) < keySizeInBytes*8) {\r
                 throw new EncryptedDocumentException("Export Restrictions in place - please install JCE Unlimited Strength Jurisdiction Policy files");\r
             }\r
 \r
             Cipher cipher;\r
-            if (cipherAlgorithm.needsBouncyCastle) {\r
+            if (cipherAlgorithm == CipherAlgorithm.rc4) {\r
+                cipher = Cipher.getInstance(cipherAlgorithm.jceId);\r
+            } else if (cipherAlgorithm.needsBouncyCastle) {\r
                 registerBouncyCastle();\r
-                cipher = Cipher.getInstance(key.getAlgorithm() + "/" + chain.jceId + "/" + padding, "BC");\r
+                cipher = Cipher.getInstance(cipherAlgorithm.jceId + "/" + chain.jceId + "/" + padding, "BC");\r
             } else {\r
-                cipher = Cipher.getInstance(key.getAlgorithm() + "/" + chain.jceId + "/" + padding);\r
+                cipher = Cipher.getInstance(cipherAlgorithm.jceId + "/" + chain.jceId + "/" + padding);\r
             }\r
             \r
             if (vec == null) {\r
@@ -282,7 +284,6 @@ public class CryptoFunctions {
         }\r
     }\r
 \r
-\r
     private static final int InitialCodeArray[] = { \r
         0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, \r
         0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, \r
index 965207ea47c0054663a86beae8d1aa957c095858..de953b8db13aad978494863fdf77bc7758ac0243 100644 (file)
 ==================================================================== */\r
 package org.apache.poi.poifs.crypt.agile;\r
 \r
-import java.io.IOException;\r
-\r
 import org.apache.poi.EncryptedDocumentException;\r
 import org.apache.poi.poifs.crypt.ChainingMode;\r
 import org.apache.poi.poifs.crypt.CipherAlgorithm;\r
 import org.apache.poi.poifs.crypt.EncryptionHeader;\r
 import org.apache.poi.poifs.crypt.HashAlgorithm;\r
-import org.apache.xmlbeans.XmlException;\r
 \r
 import com.microsoft.schemas.office.x2006.encryption.CTDataIntegrity;\r
 import com.microsoft.schemas.office.x2006.encryption.CTKeyData;\r
@@ -33,14 +30,11 @@ import com.microsoft.schemas.office.x2006.encryption.STCipherChaining;
 public class AgileEncryptionHeader extends EncryptionHeader {\r
     private byte encryptedHmacKey[], encryptedHmacValue[];\r
     \r
-    public AgileEncryptionHeader(String descriptor) throws IOException {\r
-        EncryptionDocument ed;\r
-        try {\r
-            ed = EncryptionDocument.Factory.parse(descriptor);\r
-        } catch (XmlException e) {\r
-            throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);\r
-        }\r
-        \r
+    public AgileEncryptionHeader(String descriptor) {\r
+        this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor));\r
+    }\r
+    \r
+    protected AgileEncryptionHeader(EncryptionDocument ed) {\r
         CTKeyData keyData;\r
         try {\r
             keyData = ed.getEncryption().getKeyData();\r
index 12a74620bc1503d89f83024e896f891f9f619f33..ef19cb85dbb2d9513f06bcae71210e4d095a45e0 100644 (file)
 package org.apache.poi.poifs.crypt.agile;\r
 \r
 import java.io.IOException;\r
+import java.io.InputStream;\r
 \r
 import org.apache.poi.EncryptedDocumentException;\r
 import org.apache.poi.poifs.crypt.ChainingMode;\r
 import org.apache.poi.poifs.crypt.CipherAlgorithm;\r
 import org.apache.poi.poifs.crypt.EncryptionInfo;\r
 import org.apache.poi.poifs.crypt.EncryptionInfoBuilder;\r
+import org.apache.poi.poifs.crypt.EncryptionMode;\r
 import org.apache.poi.poifs.crypt.HashAlgorithm;\r
 import org.apache.poi.poifs.filesystem.DocumentInputStream;\r
+import org.apache.xmlbeans.XmlException;\r
+\r
+import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;\r
 \r
 public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {\r
     \r
@@ -37,15 +42,11 @@ public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
     public void initialize(EncryptionInfo info, DocumentInputStream dis) throws IOException {\r
         this.info = info;\r
         \r
-        StringBuilder builder = new StringBuilder();\r
-        byte[] xmlDescriptor = new byte[dis.available()];\r
-        dis.read(xmlDescriptor);\r
-        for (byte b : xmlDescriptor)\r
-            builder.append((char)b);\r
-        String descriptor = builder.toString();\r
-        header = new AgileEncryptionHeader(descriptor);\r
-        verifier = new AgileEncryptionVerifier(descriptor);\r
-        if (info.getVersionMajor() == 4 && info.getVersionMinor() == 4) {\r
+        EncryptionDocument ed = parseDescriptor(dis);\r
+        header = new AgileEncryptionHeader(ed);\r
+        verifier = new AgileEncryptionVerifier(ed);\r
+        if (info.getVersionMajor() == EncryptionMode.agile.versionMajor\r
+            && info.getVersionMinor() == EncryptionMode.agile.versionMinor) {\r
             decryptor = new AgileDecryptor(this);\r
         }\r
     }\r
@@ -107,5 +108,19 @@ public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
         return info;\r
     }\r
     \r
-    \r
+    protected static EncryptionDocument parseDescriptor(String descriptor) {\r
+        try {\r
+            return EncryptionDocument.Factory.parse(descriptor);\r
+        } catch (XmlException e) {\r
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);\r
+        }\r
+    }\r
+\r
+    protected static EncryptionDocument parseDescriptor(InputStream descriptor) {\r
+        try {\r
+            return EncryptionDocument.Factory.parse(descriptor);\r
+        } catch (Exception e) {\r
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);\r
+        }\r
+    }\r
 }\r
index b3d2494c2066ecee5dcc1018b1d7585fe207d9b8..e2910431aad551a825ed45c86550aed4ec5d0152 100644 (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 {
index aa538a99081e6bf81bb67ae51c58adfc3b107696..ee3b71036f31f0728de176e02dbec96dca951da0 100644 (file)
@@ -403,6 +403,11 @@ public class AgileEncryptor extends Encryptor {
     }\r
 \r
     protected void createEncryptionInfoEntry(DirectoryNode dir) throws IOException {\r
+        final CTKeyEncryptor.Uri.Enum passwordUri = \r
+            CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_PASSWORD;\r
+        final CTKeyEncryptor.Uri.Enum certificateUri = \r
+                CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_CERTIFICATE;\r
+        \r
         AgileEncryptionVerifier ver = builder.getVerifier();\r
         AgileEncryptionHeader header = builder.getHeader();\r
         \r
@@ -412,7 +417,7 @@ public class AgileEncryptor extends Encryptor {
         CTKeyData keyData = edRoot.addNewKeyData();\r
         CTKeyEncryptors keyEncList = edRoot.addNewKeyEncryptors();\r
         CTKeyEncryptor keyEnc = keyEncList.addNewKeyEncryptor();\r
-        keyEnc.setUri(CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_PASSWORD);\r
+        keyEnc.setUri(passwordUri);\r
         CTPasswordKeyEncryptor keyPass = keyEnc.addNewEncryptedPasswordKey();\r
 \r
         keyPass.setSpinCount(ver.getSpinCount());\r
@@ -469,7 +474,7 @@ public class AgileEncryptor extends Encryptor {
         \r
         for (AgileCertificateEntry ace : ver.getCertificates()) {\r
             keyEnc = keyEncList.addNewKeyEncryptor();\r
-            keyEnc.setUri(CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_CERTIFICATE);\r
+            keyEnc.setUri(certificateUri);\r
             CTCertificateKeyEncryptor certData = keyEnc.addNewEncryptedCertificateKey();\r
             try {\r
                 certData.setX509Certificate(ace.x509.getEncoded());\r
@@ -479,13 +484,13 @@ public class AgileEncryptor extends Encryptor {
             certData.setEncryptedKeyValue(ace.encryptedKey);\r
             certData.setCertVerifier(ace.certVerifier);\r
         }\r
-\r
+        \r
         XmlOptions xo = new XmlOptions();\r
         xo.setCharacterEncoding("UTF-8");\r
         Map<String,String> nsMap = new HashMap<String,String>();\r
-        nsMap.put("http://schemas.microsoft.com/office/2006/keyEncryptor/password","p");\r
-        nsMap.put("http://schemas.microsoft.com/office/2006/keyEncryptor/certificate", "c");\r
-        nsMap.put("http://schemas.microsoft.com/office/2006/encryption","");\r
+        nsMap.put(passwordUri.toString(),"p");\r
+        nsMap.put(certificateUri.toString(), "c");\r
+        xo.setUseDefaultNamespace();\r
         xo.setSaveSuggestedPrefixes(nsMap);\r
         xo.setSaveNamespacesFirst();\r
         xo.setSaveAggressiveNamespaces();\r
@@ -505,7 +510,7 @@ public class AgileEncryptor extends Encryptor {
         leos.writeShort(info.getVersionMajor());\r
         leos.writeShort(info.getVersionMinor());\r
         // Reserved (4 bytes): A value that MUST be 0x00000040\r
-        leos.writeInt(0x40);\r
+        leos.writeInt(info.getEncryptionFlags());\r
         leos.write(bos.toByteArray());\r
         \r
         dir.createDocument("EncryptionInfo", leos.getWriteIndex(), new POIFSWriterListener() {\r
index 82e3c2060a888b63e4febcb0db00a91974177981..857ad5451e1576bcb5efc9f0dc241bb3b618f0e0 100644 (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();
     }
 
     /**
index 4d6877f0f9e41e5909c1c16b79c619c48ab0bd8e..e6646ae826b278d8c45f0b00a5ebdc82c3db0a42 100644 (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 {