8149070: Enforce update ordering
Summary: Make sure that ISE is thrown when updateAAD is called after update.
Reviewed-by: mullan
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java Thu Jan 28 11:03:09 2016 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java Fri Mar 11 23:54:17 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -172,6 +172,11 @@
*/
private final int fixedKeySize; // in bytes, -1 if no restriction
+ /*
+ * needed to enforce ISE thrown when updateAAD is called after update for GCM mode.
+ */
+ private boolean updateCalled;
+
/**
* Creates an instance of AES cipher with default ECB mode and
* PKCS5Padding.
@@ -304,6 +309,7 @@
protected void engineInit(int opmode, Key key, SecureRandom random)
throws InvalidKeyException {
checkKeySize(key, fixedKeySize);
+ updateCalled = false;
core.init(opmode, key, random);
}
@@ -336,6 +342,7 @@
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
checkKeySize(key, fixedKeySize);
+ updateCalled = false;
core.init(opmode, key, params, random);
}
@@ -344,6 +351,7 @@
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
checkKeySize(key, fixedKeySize);
+ updateCalled = false;
core.init(opmode, key, params, random);
}
@@ -368,6 +376,7 @@
*/
protected byte[] engineUpdate(byte[] input, int inputOffset,
int inputLen) {
+ updateCalled = true;
return core.update(input, inputOffset, inputLen);
}
@@ -397,6 +406,7 @@
protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset)
throws ShortBufferException {
+ updateCalled = true;
return core.update(input, inputOffset, inputLen, output,
outputOffset);
}
@@ -433,7 +443,9 @@
*/
protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException {
- return core.doFinal(input, inputOffset, inputLen);
+ byte[] out = core.doFinal(input, inputOffset, inputLen);
+ updateCalled = false;
+ return out;
}
/**
@@ -476,8 +488,10 @@
byte[] output, int outputOffset)
throws IllegalBlockSizeException, ShortBufferException,
BadPaddingException {
- return core.doFinal(input, inputOffset, inputLen, output,
- outputOffset);
+ int outLen = core.doFinal(input, inputOffset, inputLen, output,
+ outputOffset);
+ updateCalled = false;
+ return outLen;
}
/**
@@ -574,6 +588,9 @@
*/
@Override
protected void engineUpdateAAD(byte[] src, int offset, int len) {
+ if (core.getMode() == CipherCore.GCM_MODE && updateCalled) {
+ throw new IllegalStateException("AAD must be supplied before encryption/decryption starts");
+ }
core.updateAAD(src, offset, len);
}
@@ -606,6 +623,9 @@
*/
@Override
protected void engineUpdateAAD(ByteBuffer src) {
+ if (core.getMode() == CipherCore.GCM_MODE && updateCalled) {
+ throw new IllegalStateException("AAD must be supplied before encryption/decryption starts");
+ }
if (src != null) {
int aadLen = src.limit() - src.position();
if (aadLen != 0) {
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java Thu Jan 28 11:03:09 2016 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java Fri Mar 11 23:54:17 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -124,7 +124,7 @@
private static final int PCBC_MODE = 4;
private static final int CTR_MODE = 5;
private static final int CTS_MODE = 6;
- private static final int GCM_MODE = 7;
+ static final int GCM_MODE = 7;
/*
* variables used for performing the GCM (key+iv) uniqueness check.
@@ -196,7 +196,7 @@
cipher = new CounterMode(rawImpl);
unitBytes = 1;
padding = null;
- } else if (modeUpperCase.startsWith("GCM")) {
+ } else if (modeUpperCase.equals("GCM")) {
// can only be used for block ciphers w/ 128-bit block size
if (blockSize != 16) {
throw new NoSuchAlgorithmException
@@ -223,6 +223,15 @@
}
}
+ /**
+ * Returns the mode of this cipher.
+ *
+ * @return the parsed cipher mode
+ */
+ int getMode() {
+ return cipherMode;
+ }
+
private static int getNumOfUnit(String mode, int offset, int blockSize)
throws NoSuchAlgorithmException {
int result = blockSize; // use blockSize as default value
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java Thu Jan 28 11:03:09 2016 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java Fri Mar 11 23:54:17 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -319,20 +319,22 @@
// Feed the AAD data to GHASH, pad if necessary
void processAAD() {
- if (aadBuffer != null && aadBuffer.size() > 0) {
- byte[] aad = aadBuffer.toByteArray();
- sizeOfAAD = aad.length;
- aadBuffer = null;
+ if (aadBuffer != null) {
+ if (aadBuffer.size() > 0) {
+ byte[] aad = aadBuffer.toByteArray();
+ sizeOfAAD = aad.length;
- int lastLen = aad.length % AES_BLOCK_SIZE;
- if (lastLen != 0) {
- ghashAllToS.update(aad, 0, aad.length - lastLen);
- byte[] padded = expandToOneBlock(aad, aad.length - lastLen,
- lastLen);
- ghashAllToS.update(padded);
- } else {
- ghashAllToS.update(aad);
+ int lastLen = aad.length % AES_BLOCK_SIZE;
+ if (lastLen != 0) {
+ ghashAllToS.update(aad, 0, aad.length - lastLen);
+ byte[] padded = expandToOneBlock(aad, aad.length - lastLen,
+ lastLen);
+ ghashAllToS.update(padded);
+ } else {
+ ghashAllToS.update(aad);
+ }
}
+ aadBuffer = null;
}
}
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java Thu Jan 28 11:03:09 2016 +0100
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java Fri Mar 11 23:54:17 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -59,10 +59,10 @@
// buffer for storing AAD data; if null, meaning buffer content has been
// supplied to native context
- private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream();
+ private ByteArrayOutputStream aadBuffer;
// buffer for storing input in decryption, not used for encryption
- private ByteArrayOutputStream ibuffer = null;
+ private ByteArrayOutputStream ibuffer;
private int tagLen = DEFAULT_TAG_LEN;
@@ -75,7 +75,7 @@
* key + iv values used in previous encryption.
* For decryption operations, no checking is necessary.
*/
- private boolean requireReinit = false;
+ private boolean requireReinit;
private byte[] lastEncKey = null;
private byte[] lastEncIv = null;
@@ -86,12 +86,14 @@
@Override
protected void ensureInitialized() {
if (!initialized) {
- if (aadBuffer != null && aadBuffer.size() > 0) {
- init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
- aadBuffer = null;
- } else {
- init(encrypt, keyValue, iv, tagLen, null);
+ byte[] aad = null;
+ if (aadBuffer != null) {
+ if (aadBuffer.size() > 0) {
+ aad = aadBuffer.toByteArray();
+ }
}
+ init(encrypt, keyValue, iv, tagLen, aad);
+ aadBuffer = null;
if (!initialized) {
throw new UcryptoException("Cannot initialize Cipher");
}
@@ -185,6 +187,7 @@
throw new InvalidAlgorithmParameterException
("Unsupported mode: " + opmode);
}
+ aadBuffer = new ByteArrayOutputStream();
boolean doEncrypt = (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE);
byte[] keyBytes = key.getEncoded().clone();
byte[] ivBytes = null;
@@ -219,6 +222,7 @@
}
lastEncIv = ivBytes;
lastEncKey = keyBytes;
+ ibuffer = null;
} else {
requireReinit = false;
ibuffer = new ByteArrayOutputStream();
@@ -246,9 +250,11 @@
// see JCE spec
@Override
protected synchronized byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
- if (aadBuffer != null && aadBuffer.size() > 0) {
- // init again with AAD data
- init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+ if (aadBuffer != null) {
+ if (aadBuffer.size() > 0) {
+ // init again with AAD data
+ init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+ }
aadBuffer = null;
}
if (requireReinit) {
@@ -274,9 +280,11 @@
"(at least) " + len + " bytes long. Got: " +
(out.length - outOfs));
}
- if (aadBuffer != null && aadBuffer.size() > 0) {
- // init again with AAD data
- init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+ if (aadBuffer != null) {
+ if (aadBuffer.size() > 0) {
+ // init again with AAD data
+ init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+ }
aadBuffer = null;
}
if (requireReinit) {
@@ -374,9 +382,11 @@
+ "(at least) " + len + " bytes long. Got: " +
(out.length - outOfs));
}
- if (aadBuffer != null && aadBuffer.size() > 0) {
- // init again with AAD data
- init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+ if (aadBuffer != null) {
+ if (aadBuffer.size() > 0) {
+ // init again with AAD data
+ init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+ }
aadBuffer = null;
}
if (requireReinit) {