|
|
@@ -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) { |