summaryrefslogtreecommitdiff
path: root/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
diff options
context:
space:
mode:
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java')
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java44
1 files changed, 41 insertions, 3 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
index ed89ef7d..54e54cec 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
@@ -38,6 +38,7 @@ public class GCMBlockCipher
// These fields are set by init and not modified by processing
private boolean forEncryption;
private int macSize;
+ private byte[] lastKey;
private byte[] nonce;
private byte[] initialAssociatedText;
private byte[] H;
@@ -48,6 +49,7 @@ public class GCMBlockCipher
private byte[] macBlock;
private byte[] S, S_at, S_atPre;
private byte[] counter;
+ private int blocksRemaining;
private int bufOff;
private long totalLength;
private byte[] atBlock;
@@ -99,12 +101,13 @@ public class GCMBlockCipher
this.macBlock = null;
KeyParameter keyParam;
+ byte[] newNonce = null;
if (params instanceof AEADParameters)
{
AEADParameters param = (AEADParameters)params;
- nonce = param.getNonce();
+ newNonce = param.getNonce();
initialAssociatedText = param.getAssociatedText();
int macSizeBits = param.getMacSize();
@@ -120,7 +123,7 @@ public class GCMBlockCipher
{
ParametersWithIV param = (ParametersWithIV)params;
- nonce = param.getIV();
+ newNonce = param.getIV();
initialAssociatedText = null;
macSize = 16;
keyParam = (KeyParameter)param.getParameters();
@@ -133,11 +136,32 @@ public class GCMBlockCipher
int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
this.bufBlock = new byte[bufLength];
- if (nonce == null || nonce.length < 1)
+ if (newNonce == null || newNonce.length < 1)
{
throw new IllegalArgumentException("IV must be at least 1 byte");
}
+ if (forEncryption)
+ {
+ if (nonce != null && Arrays.areEqual(nonce, newNonce))
+ {
+ if (keyParam == null)
+ {
+ throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
+ }
+ if (lastKey != null && Arrays.areEqual(lastKey, keyParam.getKey()))
+ {
+ throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
+ }
+ }
+ }
+
+ nonce = newNonce;
+ if (keyParam != null)
+ {
+ lastKey = keyParam.getKey();
+ }
+
// TODO Restrict macSize to 16 if nonce length not 12?
// Cipher always used in forward mode
@@ -181,6 +205,7 @@ public class GCMBlockCipher
this.atLength = 0;
this.atLengthPre = 0;
this.counter = Arrays.clone(J0);
+ this.blocksRemaining = -2; // page 8, len(P) <= 2^39 - 256, 1 block used by tag but done on J0
this.bufOff = 0;
this.totalLength = 0;
@@ -192,6 +217,10 @@ public class GCMBlockCipher
public byte[] getMac()
{
+ if (macBlock == null)
+ {
+ return new byte[macSize];
+ }
return Arrays.clone(macBlock);
}
@@ -481,6 +510,8 @@ public class GCMBlockCipher
{
cipher.reset();
+ // note: we do not reset the nonce.
+
S = new byte[BLOCK_SIZE];
S_at = new byte[BLOCK_SIZE];
S_atPre = new byte[BLOCK_SIZE];
@@ -489,6 +520,7 @@ public class GCMBlockCipher
atLength = 0;
atLengthPre = 0;
counter = Arrays.clone(J0);
+ blocksRemaining = -2;
bufOff = 0;
totalLength = 0;
@@ -555,6 +587,12 @@ public class GCMBlockCipher
private byte[] getNextCounterBlock()
{
+ if (blocksRemaining == 0)
+ {
+ throw new IllegalStateException("Attempt to process too many blocks");
+ }
+ blocksRemaining--;
+
int c = 1;
c += counter[15] & 0xFF; counter[15] = (byte)c; c >>>= 8;
c += counter[14] & 0xFF; counter[14] = (byte)c; c >>>= 8;