diff options
author | Tim Whittington <bc@whittington.net.nz> | 2014-03-07 00:15:11 +0400 |
---|---|---|
committer | Tim Whittington <bc@whittington.net.nz> | 2014-03-10 12:27:39 +0400 |
commit | f5212359caf7e5931ae0f48f00e328cc3b017317 (patch) | |
tree | 59c9fdb29509651205f28019b1d9c187de515955 /core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java | |
parent | 8eca220a9b2c68938b19ee6b88e0534d0a07c618 (diff) |
Fix buffer underflows in cipher light weight API input/output streams and beef up testing.
Buffer underflows could occur when:
- decrypting data > internal buffer size in output stream (input stream was fixed in prior commit)
- packet mode AE cipher (e.g. CCM) is used with a data size > internal buffer size (since all output is buffered)
Buffer is now sized appropriately to every cipher operation immediately prior to it (using getUpdateOutputSize/getOutputSize as appropriate) in both streams.
Tests now run over boundaries of various block/buffer sizes to try to expose issues (0, 64 bit block, 128 bit block, 1K, 2K, 4K).
Diffstat (limited to 'core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java')
-rw-r--r-- | core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java index 9beb5b95..2fe95bed 100644 --- a/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java +++ b/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java @@ -118,7 +118,7 @@ public class CipherOutputStream int len) throws IOException { - ensureCapacity(len); + ensureCapacity(len, false); if (bufferedBlockCipher != null) { @@ -149,24 +149,35 @@ public class CipherOutputStream /** * Ensure the ciphertext buffer has space sufficient to accept an upcoming output. * - * @param outputSize the size of the pending update. + * @param updateSize the size of the pending update. + * @param <code>true</code> iff this the cipher is to be finalised. */ - private void ensureCapacity(int outputSize) + private void ensureCapacity(int updateSize, boolean finalOutput) { - // This overestimates buffer on updates for AEAD/padded, but keeps it simple. - int bufLen; - if (bufferedBlockCipher != null) + int bufLen = updateSize; + if (finalOutput) { - bufLen = bufferedBlockCipher.getOutputSize(outputSize); - } - else if (aeadBlockCipher != null) - { - bufLen = aeadBlockCipher.getOutputSize(outputSize); + if (bufferedBlockCipher != null) + { + bufLen = bufferedBlockCipher.getOutputSize(updateSize); + } + else if (aeadBlockCipher != null) + { + bufLen = aeadBlockCipher.getOutputSize(updateSize); + } } else { - bufLen = outputSize; + if (bufferedBlockCipher != null) + { + bufLen = bufferedBlockCipher.getUpdateOutputSize(updateSize); + } + else if (aeadBlockCipher != null) + { + bufLen = aeadBlockCipher.getUpdateOutputSize(updateSize); + } } + if ((buf == null) || (buf.length < bufLen)) { buf = new byte[bufLen]; @@ -213,7 +224,7 @@ public class CipherOutputStream public void close() throws IOException { - ensureCapacity(0); + ensureCapacity(0, true); IOException error = null; try { @@ -242,7 +253,7 @@ public class CipherOutputStream } catch (Exception e) { - error = new IOException("Error closing stream: " + e); + error = new CipherIOException("Error closing stream: ", e); } try |