Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2014-03-11 00:28:11 +0400
committerDavid Hook <dgh@cryptoworkshop.com>2014-03-11 00:28:11 +0400
commit6f6de836df25632bc4f8f291d9dc7dfa121f9e1f (patch)
treea6ba03424e3cefe9d5e0a0933c00a04428b8707d /core/src/main/java/org/bouncycastle
parent2a53be10f552694fdd48d70152012c7ea899141c (diff)
parent23955bbc35d9712b1fec023d32f2e1f1d578df3a (diff)
Merge branch 'feature/update-size-testing' of https://github.com/timw/bc-java into timw-feature/update-size-testing
Diffstat (limited to 'core/src/main/java/org/bouncycastle')
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java26
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java71
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java39
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java13
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java22
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java39
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java49
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java23
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java18
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java2
10 files changed, 216 insertions, 86 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java
new file mode 100644
index 00000000..beeb60bc
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.IOException;
+
+/**
+ * {@link IOException} wrapper around an exception indicating a problem with the use of a cipher.
+ */
+public class CipherIOException
+ extends IOException
+{
+ private static final long serialVersionUID = 1L;
+
+ private final Throwable cause;
+
+ public CipherIOException(String message, Throwable cause)
+ {
+ super(message);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+} \ No newline at end of file
diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
index 66772df5..f80add1a 100644
--- a/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
+++ b/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
@@ -12,28 +12,28 @@ import org.bouncycastle.crypto.modes.AEADBlockCipher;
/**
* A CipherInputStream is composed of an InputStream and a cipher so that read() methods return data
* that are read in from the underlying InputStream but have been additionally processed by the
- * Cipher. The cipher must be fully initialized before being used by a CipherInputStream.
+ * cipher. The cipher must be fully initialized before being used by a CipherInputStream.
* <p/>
- * For example, if the Cipher is initialized for decryption, the
+ * For example, if the cipher is initialized for decryption, the
* CipherInputStream will attempt to read in data and decrypt them,
* before returning the decrypted data.
*/
public class CipherInputStream
extends FilterInputStream
{
+ private static final int INPUT_BUF_SIZE = 2048;
+
private BufferedBlockCipher bufferedBlockCipher;
private StreamCipher streamCipher;
private AEADBlockCipher aeadBlockCipher;
- private final byte[] buf;
- private final byte[] inBuf;
+ private byte[] buf;
+ private final byte[] inBuf = new byte[INPUT_BUF_SIZE];
private int bufOff;
private int maxBuf;
private boolean finalized;
- private static final int INPUT_BUF_SIZE = 2048;
-
/**
* Constructs a CipherInputStream from an InputStream and a
* BufferedBlockCipher.
@@ -45,11 +45,6 @@ public class CipherInputStream
super(is);
this.bufferedBlockCipher = cipher;
-
- int outSize = cipher.getOutputSize(INPUT_BUF_SIZE);
-
- buf = new byte[(outSize > INPUT_BUF_SIZE) ? outSize : INPUT_BUF_SIZE];
- inBuf = new byte[INPUT_BUF_SIZE];
}
public CipherInputStream(
@@ -59,9 +54,6 @@ public class CipherInputStream
super(is);
this.streamCipher = cipher;
-
- buf = new byte[INPUT_BUF_SIZE];
- inBuf = new byte[INPUT_BUF_SIZE];
}
/**
@@ -72,11 +64,6 @@ public class CipherInputStream
super(is);
this.aeadBlockCipher = cipher;
-
- int outSize = cipher.getOutputSize(INPUT_BUF_SIZE);
-
- buf = new byte[(outSize > INPUT_BUF_SIZE) ? outSize : INPUT_BUF_SIZE];
- inBuf = new byte[INPUT_BUF_SIZE];
}
/**
@@ -112,6 +99,7 @@ public class CipherInputStream
try
{
+ ensureCapacity(read, false);
if (bufferedBlockCipher != null)
{
maxBuf = bufferedBlockCipher.processBytes(inBuf, 0, read, buf, 0);
@@ -128,7 +116,7 @@ public class CipherInputStream
}
catch (Exception e)
{
- throw new IOException("Error processing stream " + e);
+ throw new CipherIOException("Error processing stream ", e);
}
}
return maxBuf;
@@ -140,6 +128,7 @@ public class CipherInputStream
try
{
finalized = true;
+ ensureCapacity(0, true);
if (bufferedBlockCipher != null)
{
maxBuf = bufferedBlockCipher.doFinal(buf, 0);
@@ -159,7 +148,7 @@ public class CipherInputStream
}
catch (Exception e)
{
- throw new IOException("Error finalising cipher " + e);
+ throw new CipherIOException("Error finalising cipher ", e);
}
}
@@ -263,11 +252,49 @@ public class CipherInputStream
}
/**
+ * Ensure the ciphertext buffer has space sufficient to accept an upcoming output.
+ *
+ * @param updateSize the size of the pending update.
+ * @param <code>true</code> iff this the cipher is to be finalised.
+ */
+ private void ensureCapacity(int updateSize, boolean finalOutput)
+ {
+ int bufLen = updateSize;
+ if (finalOutput)
+ {
+ if (bufferedBlockCipher != null)
+ {
+ bufLen = bufferedBlockCipher.getOutputSize(updateSize);
+ }
+ else if (aeadBlockCipher != null)
+ {
+ bufLen = aeadBlockCipher.getOutputSize(updateSize);
+ }
+ }
+ else
+ {
+ 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];
+ }
+ }
+
+ /**
* Closes the underlying input stream and finalises the processing of the data by the cipher.
*
* @throws IOException if there was an error closing the input stream.
* @throws InvalidCipherTextIOException if the data read from the stream was invalid ciphertext
- * (e.g. the cipher is an AEAD cipher and the ciphertext tag check fails).
+ * (e.g. the cipher is an AEAD cipher and the ciphertext tag check fails).
*/
public void close()
throws IOException
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
diff --git a/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java b/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java
index b601d4c1..46561c67 100644
--- a/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java
+++ b/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java
@@ -8,21 +8,12 @@ import java.io.IOException;
* expose invalid ciphertext errors.
*/
public class InvalidCipherTextIOException
- extends IOException
+ extends CipherIOException
{
private static final long serialVersionUID = 1L;
- private final Throwable cause;
-
public InvalidCipherTextIOException(String message, Throwable cause)
{
- super(message);
-
- this.cause = cause;
- }
-
- public Throwable getCause()
- {
- return cause;
+ super(message, cause);
}
} \ No newline at end of file
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
index 71b75954..3a2f73a3 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
@@ -7,6 +7,15 @@ import org.bouncycastle.crypto.InvalidCipherTextException;
/**
* A block cipher mode that includes authenticated encryption with a streaming mode and optional associated data.
+ * <p/>
+ * Implementations of this interface may operate in a packet mode (where all input data is buffered and
+ * processed dugin the call to {@link #doFinal(byte[], int)}), or in a streaming mode (where output data is
+ * incrementally produced with each call to {@link #processByte(byte, byte[], int)} or
+ * {@link #processBytes(byte[], int, int, byte[], int)}.
+ * <br/>This is important to consider during decryption: in a streaming mode, unauthenticated plaintext data
+ * may be output prior to the call to {@link #doFinal(byte[], int)} that results in an authentication
+ * failure. The higher level protocol utilising this cipher must ensure the plaintext data is handled
+ * appropriately until the end of data is reached and the entire ciphertext is authenticated.
* @see org.bouncycastle.crypto.params.AEADParameters
*/
public interface AEADBlockCipher
@@ -101,7 +110,11 @@ public interface AEADBlockCipher
/**
* return the size of the output buffer required for a processBytes
* an input of len bytes.
- *
+ * <p/>
+ * The returned size may be dependent on the initialisation of this cipher
+ * and may not be accurate once subsequent input data is processed - this method
+ * should be invoked immediately prior to input data being processed.
+ *
* @param len the length of the input.
* @return the space required to accommodate a call to processBytes
* with len bytes of input.
@@ -111,7 +124,12 @@ public interface AEADBlockCipher
/**
* return the size of the output buffer required for a processBytes plus a
* doFinal with an input of len bytes.
- *
+ * <p/>
+ * The returned size may be dependent on the initialisation of this cipher
+ * and may not be accurate once subsequent input data is processed - this method
+ * should be invoked immediately prior to a call to final processing of input data
+ * and a call to {@link #doFinal(byte[], int)}.
+ *
* @param len the length of the input.
* @return the space required to accommodate a call to processBytes and doFinal
* with len bytes of input.
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
index fef51fdb..7f870ca2 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
@@ -7,6 +7,7 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.ParametersWithIV;
@@ -42,7 +43,7 @@ public class CCMBlockCipher
this.cipher = c;
this.blockSize = c.getBlockSize();
this.macBlock = new byte[blockSize];
-
+
if (blockSize != 16)
{
throw new IllegalArgumentException("cipher required with a block size of 16.");
@@ -99,7 +100,7 @@ public class CCMBlockCipher
{
throw new IllegalArgumentException("nonce must have length from 7 to 13 octets");
}
-
+
reset();
}
@@ -130,6 +131,10 @@ public class CCMBlockCipher
public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff)
throws DataLengthException, IllegalStateException
{
+ if (in.length < (inOff + inLen))
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
data.write(in, inOff, inLen);
return 0;
@@ -155,15 +160,15 @@ public class CCMBlockCipher
/**
* Returns a byte array containing the mac calculated as part of the
* last encrypt or decrypt operation.
- *
+ *
* @return the last mac calculated.
*/
public byte[] getMac()
{
byte[] mac = new byte[macSize];
-
+
System.arraycopy(macBlock, 0, mac, 0, mac.length);
-
+
return mac;
}
@@ -267,7 +272,7 @@ public class CCMBlockCipher
outputLen = inLen + macSize;
if (output.length < (outputLen + outOff))
{
- throw new DataLengthException("Output buffer too short.");
+ throw new OutputLengthException("Output buffer too short.");
}
calculateMac(in, inOff, inLen, macBlock);
@@ -300,7 +305,7 @@ public class CCMBlockCipher
outputLen = inLen - macSize;
if (output.length < (outputLen + outOff))
{
- throw new DataLengthException("Output buffer too short.");
+ throw new OutputLengthException("Output buffer too short.");
}
System.arraycopy(in, inOff + outputLen, macBlock, 0, macSize);
@@ -350,18 +355,18 @@ public class CCMBlockCipher
// build b0
//
byte[] b0 = new byte[16];
-
+
if (hasAssociatedText())
{
b0[0] |= 0x40;
}
-
+
b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3;
b0[0] |= ((15 - nonce.length) - 1) & 0x7;
-
+
System.arraycopy(nonce, 0, b0, 1, nonce.length);
-
+
int q = dataLen;
int count = 1;
while (q > 0)
@@ -370,22 +375,22 @@ public class CCMBlockCipher
q >>>= 8;
count++;
}
-
+
cMac.update(b0, 0, b0.length);
-
+
//
// process associated text
//
if (hasAssociatedText())
{
int extra;
-
+
int textLength = getAssociatedTextLength();
if (textLength < ((1 << 16) - (1 << 8)))
{
cMac.update((byte)(textLength >> 8));
cMac.update((byte)textLength);
-
+
extra = 2;
}
else // can't go any higher than 2^32
@@ -396,7 +401,7 @@ public class CCMBlockCipher
cMac.update((byte)(textLength >> 16));
cMac.update((byte)(textLength >> 8));
cMac.update((byte)textLength);
-
+
extra = 6;
}
@@ -418,7 +423,7 @@ public class CCMBlockCipher
}
}
}
-
+
//
// add the text
//
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java
index 8f740006..209d5cdb 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java
@@ -5,22 +5,23 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.macs.CMac;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;
/**
- * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and
+ * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and
* Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
- *
+ *
* http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
- *
- * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block
- * cipher to encrypt and authenticate data. It's on-line (the length of a
+ *
+ * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block
+ * cipher to encrypt and authenticate data. It's on-line (the length of a
* message isn't needed to begin processing it), has good performances, it's
* simple and provably secure (provided the underlying block cipher is secure).
- *
+ *
* Of course, this implementations is NOT thread-safe.
*/
public class EAXBlockCipher
@@ -43,7 +44,7 @@ public class EAXBlockCipher
private byte[] nonceMac;
private byte[] associatedTextMac;
private byte[] macBlock;
-
+
private int macSize;
private byte[] bufBlock;
private int bufOff;
@@ -61,7 +62,6 @@ public class EAXBlockCipher
blockSize = cipher.getBlockSize();
mac = new CMac(cipher);
macBlock = new byte[blockSize];
- bufBlock = new byte[blockSize * 2];
associatedTextMac = new byte[mac.getMacSize()];
nonceMac = new byte[mac.getMacSize()];
this.cipher = new SICBlockCipher(cipher);
@@ -113,6 +113,8 @@ public class EAXBlockCipher
throw new IllegalArgumentException("invalid parameters passed to EAX");
}
+ bufBlock = new byte[forEncryption ? blockSize : (blockSize + macSize)];
+
byte[] tag = new byte[blockSize];
// Key reuse implemented in CBC mode of underlying CMac
@@ -123,9 +125,9 @@ public class EAXBlockCipher
mac.update(nonce, 0, nonce.length);
mac.doFinal(nonceMac, 0);
- // Same BlockCipher underlies this and the mac, so reuse last key on cipher
+ // Same BlockCipher underlies this and the mac, so reuse last key on cipher
cipher.init(true, new ParametersWithIV(null, nonceMac));
-
+
reset();
}
@@ -218,6 +220,11 @@ public class EAXBlockCipher
{
initCipher();
+ if (in.length < (inOff + len))
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
+
int resultLen = 0;
for (int i = 0; i != len; i++)
@@ -240,12 +247,11 @@ public class EAXBlockCipher
if (forEncryption)
{
- if (out.length < (outOff + extra))
+ if (out.length < (outOff + extra + macSize))
{
- throw new DataLengthException("Output buffer too short");
+ throw new OutputLengthException("Output buffer too short");
}
cipher.processBlock(bufBlock, 0, tmp, 0);
- cipher.processBlock(bufBlock, blockSize, tmp, blockSize);
System.arraycopy(tmp, 0, out, outOff, extra);
@@ -261,6 +267,10 @@ public class EAXBlockCipher
}
else
{
+ if (out.length < (outOff + extra - macSize))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
if (extra < macSize)
{
throw new InvalidCipherTextException("data too short");
@@ -270,7 +280,6 @@ public class EAXBlockCipher
mac.update(bufBlock, 0, extra - macSize);
cipher.processBlock(bufBlock, 0, tmp, 0);
- cipher.processBlock(bufBlock, blockSize, tmp, blockSize);
System.arraycopy(tmp, 0, out, outOff, extra - macSize);
}
@@ -329,6 +338,10 @@ public class EAXBlockCipher
if (bufOff == bufBlock.length)
{
+ if (out.length < (outOff + blockSize))
+ {
+ throw new OutputLengthException("Output buffer is too short");
+ }
// TODO Could move the processByte(s) calls to here
// initCipher();
@@ -347,8 +360,12 @@ public class EAXBlockCipher
size = cipher.processBlock(bufBlock, 0, out, outOff);
}
- bufOff = blockSize;
- System.arraycopy(bufBlock, blockSize, bufBlock, 0, blockSize);
+ bufOff = 0;
+ if (!forEncryption)
+ {
+ System.arraycopy(bufBlock, blockSize, bufBlock, 0, macSize);
+ bufOff = macSize;
+ }
return size;
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
index 9e617ec9..59c2eb36 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
@@ -4,6 +4,7 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.modes.gcm.GCMExponentiator;
import org.bouncycastle.crypto.modes.gcm.GCMMultiplier;
import org.bouncycastle.crypto.modes.gcm.Tables1kGCMExponentiator;
@@ -23,7 +24,7 @@ public class GCMBlockCipher
{
private static final int BLOCK_SIZE = 16;
- // not final due to a compiler bug
+ // not final due to a compiler bug
private BlockCipher cipher;
private GCMMultiplier multiplier;
private GCMExponentiator exp;
@@ -102,7 +103,7 @@ public class GCMBlockCipher
throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits);
}
- macSize = macSizeBits / 8;
+ macSize = macSizeBits / 8;
keyParam = param.getKey();
}
else if (params instanceof ParametersWithIV)
@@ -119,7 +120,7 @@ public class GCMBlockCipher
throw new IllegalArgumentException("invalid parameters passed to GCM");
}
- int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
+ int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
this.bufBlock = new byte[bufLength];
if (nonce == null || nonce.length < 1)
@@ -271,6 +272,10 @@ public class GCMBlockCipher
public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
throws DataLengthException
{
+ if (in.length < (inOff + len))
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
int resultLen = 0;
for (int i = 0; i < len; ++i)
@@ -288,6 +293,10 @@ public class GCMBlockCipher
private void outputBlock(byte[] output, int offset)
{
+ if (output.length < (offset + BLOCK_SIZE))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
if (totalLength == 0)
{
initCipher();
@@ -324,6 +333,10 @@ public class GCMBlockCipher
if (extra > 0)
{
+ if (out.length < (outOff + extra))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
gCTRPartial(bufBlock, 0, extra, out, outOff);
}
@@ -390,6 +403,10 @@ public class GCMBlockCipher
if (forEncryption)
{
+ if (out.length < (outOff + extra + macSize))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
// Append T to the message
System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize);
resultLen += macSize;
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java
index d0345c4b..66db8beb 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java
@@ -6,6 +6,7 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
@@ -317,6 +318,10 @@ public class OCBBlockCipher
public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
throws DataLengthException
{
+ if (input.length < (inOff + len))
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
int resultLen = 0;
for (int i = 0; i < len; ++i)
@@ -378,6 +383,10 @@ public class OCBBlockCipher
xor(mainBlock, Pad);
+ if (output.length < (outOff + mainBlockPos))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
System.arraycopy(mainBlock, 0, output, outOff, mainBlockPos);
if (!forEncryption)
@@ -405,6 +414,10 @@ public class OCBBlockCipher
if (forEncryption)
{
+ if (output.length < (outOff + resultLen + macSize))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
// Append tag to the message
System.arraycopy(macBlock, 0, output, outOff + resultLen, macSize);
resultLen += macSize;
@@ -456,6 +469,11 @@ public class OCBBlockCipher
protected void processMainBlock(byte[] output, int outOff)
{
+ if (output.length < (outOff + BLOCK_SIZE))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
+
/*
* OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks
*/
diff --git a/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
index ee3fd60e..d5928f70 100644
--- a/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
@@ -125,7 +125,7 @@ public class PaddedBufferedBlockCipher
if (leftOver == 0)
{
- return total - buf.length;
+ return Math.max(0, total - buf.length);
}
return total - leftOver;