8149070: Enforce update ordering

Make sure that ISE is thrown when updateAAD is called after update.

Reviewed-by: mullan
This commit is contained in:
Valerie Peng 2016-03-11 23:54:17 +00:00
parent 80083759f2
commit 63276540e2
4 changed files with 79 additions and 38 deletions

View File

@ -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 @@ abstract class AESCipher extends CipherSpi {
*/
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 @@ abstract class AESCipher extends CipherSpi {
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 @@ abstract class AESCipher extends CipherSpi {
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
checkKeySize(key, fixedKeySize);
updateCalled = false;
core.init(opmode, key, params, random);
}
@ -344,6 +351,7 @@ abstract class AESCipher extends CipherSpi {
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
checkKeySize(key, fixedKeySize);
updateCalled = false;
core.init(opmode, key, params, random);
}
@ -368,6 +376,7 @@ abstract class AESCipher extends CipherSpi {
*/
protected byte[] engineUpdate(byte[] input, int inputOffset,
int inputLen) {
updateCalled = true;
return core.update(input, inputOffset, inputLen);
}
@ -397,6 +406,7 @@ abstract class AESCipher extends CipherSpi {
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 @@ abstract class AESCipher extends CipherSpi {
*/
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 @@ abstract class AESCipher extends CipherSpi {
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 @@ abstract class AESCipher extends CipherSpi {
*/
@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 @@ abstract class AESCipher extends CipherSpi {
*/
@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) {

View File

@ -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 @@ final class CipherCore {
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 @@ final class CipherCore {
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 @@ final class CipherCore {
}
}
/**
* 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

View File

@ -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 @@ final class GaloisCounterMode extends FeedbackCipher {
// 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;
}
}

View File

@ -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 @@ class NativeGCMCipher extends NativeCipher {
// 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 @@ class NativeGCMCipher extends NativeCipher {
* 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 @@ class NativeGCMCipher extends NativeCipher {
@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 @@ class NativeGCMCipher extends NativeCipher {
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 @@ class NativeGCMCipher extends NativeCipher {
}
lastEncIv = ivBytes;
lastEncKey = keyBytes;
ibuffer = null;
} else {
requireReinit = false;
ibuffer = new ByteArrayOutputStream();
@ -246,9 +250,11 @@ class NativeGCMCipher extends NativeCipher {
// 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 @@ class NativeGCMCipher extends NativeCipher {
"(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 @@ class NativeGCMCipher extends NativeCipher {
+ "(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) {