From: Andreas Beeker Date: Sun, 9 Dec 2018 21:45:47 +0000 (+0000) Subject: #62994 - IBM JCE workarounds X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=6676b3c5030498d876b28823dcb1830dbaa8f178;p=poi.git #62994 - IBM JCE workarounds git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1848538 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java b/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java index 9da03cf2e2..0aa73fd670 100644 --- a/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java +++ b/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java @@ -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) { diff --git a/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java b/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java index b412585261..9221d4a390 100644 --- a/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java @@ -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 diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureOutputStream.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureOutputStream.java index 0a00e29f1a..0ba11fbd34 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureOutputStream.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureOutputStream.java @@ -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); }