]> source.dussan.org Git - poi.git/commitdiff
#62994 - IBM JCE workarounds
authorAndreas Beeker <kiwiwings@apache.org>
Sun, 9 Dec 2018 21:45:47 +0000 (21:45 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sun, 9 Dec 2018 21:45:47 +0000 (21:45 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1848538 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java
src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureOutputStream.java

index 9da03cf2e2609d575f5f68460d81af59ebbaa9eb..0aa73fd670a3fca74104069d739b4948217e9074 100644 (file)
@@ -99,6 +99,13 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
         return initCipherForBlock(cipher, block, lastChunk);
     }
 
+    // helper method to break a recursion loop introduced because of an IBMJCE bug, i.e. not resetting on Cipher.doFinal()
+    @Internal
+    protected Cipher initCipherForBlockNoFlush(Cipher existing, int block, boolean lastChunk)
+    throws IOException, GeneralSecurityException {
+        return initCipherForBlock(cipher, block, lastChunk);
+    }
+
     protected abstract Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk)
     throws IOException, GeneralSecurityException;
 
@@ -212,13 +219,30 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
      * @throws IllegalBlockSizeException 
      * @throws ShortBufferException
      */
-    protected int invokeCipher(int posInChunk, boolean doFinal) throws GeneralSecurityException {
+    protected int invokeCipher(int posInChunk, boolean doFinal) throws GeneralSecurityException, IOException {
         byte plain[] = (plainByteFlags.isEmpty()) ? null : chunk.clone();
 
         int ciLen = (doFinal)
             ? cipher.doFinal(chunk, 0, posInChunk, chunk)
             : cipher.update(chunk, 0, posInChunk, chunk);
 
+        if (doFinal && "IBMJCE".equals(cipher.getProvider().getName()) && "RC4".equals(cipher.getAlgorithm())) {
+            // workaround for IBMs cipher not resetting on doFinal
+
+            int index = (int)(pos >> chunkBits);
+            boolean lastChunk;
+            if (posInChunk==0) {
+                index--;
+                posInChunk = chunk.length;
+                lastChunk = false;
+            } else {
+                // pad the last chunk
+                lastChunk = true;
+            }
+
+            cipher = initCipherForBlockNoFlush(cipher, index, lastChunk);
+        }
+
         if (plain != null) {
             int i = plainByteFlags.nextSetBit(0);
             while (i >= 0 && i < posInChunk) {
index b412585261c46f8805e10303b9e93817510611e9..9221d4a3900446d49b3c9f7d18a0f69fdbf23e45 100644 (file)
@@ -207,9 +207,15 @@ public class CryptoAPIEncryptor extends Encryptor implements Cloneable {
         protected Cipher initCipherForBlock(Cipher cipher, int block, boolean lastChunk)
         throws IOException, GeneralSecurityException {
             flush();
+            return initCipherForBlockNoFlush(cipher, block, lastChunk);
+        }
+
+        @Override
+        protected Cipher initCipherForBlockNoFlush(Cipher existing, int block, boolean lastChunk)
+        throws GeneralSecurityException {
             EncryptionInfo ei = getEncryptionInfo();
             SecretKey sk = getSecretKey();
-            return CryptoAPIDecryptor.initCipherForBlock(cipher, block, ei, sk, Cipher.ENCRYPT_MODE);
+            return CryptoAPIDecryptor.initCipherForBlock(existing, block, ei, sk, Cipher.ENCRYPT_MODE);
         }
 
         @Override
index 0a00e29f1a520f3073b3c34b9615e0623ae54315..0ba11fbd34ea613da10f5f926361ddca0a571a48 100644 (file)
@@ -20,6 +20,7 @@ package org.apache.poi.poifs.crypt.dsig;
 import java.io.IOException;
 import java.security.GeneralSecurityException;
 import java.security.PrivateKey;
+import java.security.Security;
 import java.security.Signature;
 import java.security.SignatureException;
 
@@ -35,7 +36,12 @@ import org.apache.poi.poifs.crypt.HashAlgorithm;
     @Override
     public void init() throws GeneralSecurityException {
         final String provider = isMSCapi(key) ? "SunMSCAPI" : "SunRsaSign";
-        signature = Signature.getInstance(algo.ecmaString+"withRSA", provider);
+        if (Security.getProvider(provider) != null) {
+            signature = Signature.getInstance(algo.ecmaString + "withRSA", provider);
+        } else {
+            signature = Signature.getInstance(algo.ecmaString + "withRSA");
+        }
+
         signature.initSign(key);
     }