# HG changeset patch # User zmajo # Date 1429603015 -7200 # Node ID a5e8d625d13409fb91a54818d8cd64e09dd4281d # Parent c9987cf52d6a6c99a477aef95867a2826be322fa 8067648: JVM crashes reproducible with GCM cipher suites in GCTR doFinal Summary: Change restore mechanism in GCTR.java to avoid setting counter to null; added length check to constructor Reviewed-by: jrose, kvn, ascarpino diff -r c9987cf52d6a -r a5e8d625d134 src/share/classes/com/sun/crypto/provider/GCTR.java --- a/src/share/classes/com/sun/crypto/provider/GCTR.java Mon May 18 12:17:55 2015 -0700 +++ b/src/share/classes/com/sun/crypto/provider/GCTR.java Tue Apr 21 09:56:55 2015 +0200 @@ -38,7 +38,17 @@ * under section 6.5. It needs to be constructed w/ an initialized * cipher object, and initial counter block(ICB). Given an input X * of arbitrary length, it processes and returns an output which has - * the same length as X. + * the same length as X. The invariants of this class are: + * + * (1) The length of intialCounterBlk (and also of its clones, e.g., + * fields counter and counterSave) is equal to AES_BLOCK_SIZE. + * + * (2) After construction, the field counter never becomes null, it + * always contains a byte array of length AES_BLOCK_SIZE. + * + * If any invariant is broken, failures can occur because the + * AESCrypt.encryptBlock method can be intrinsified on the HotSpot VM + * (see JDK-8067648 for details). * *

This function is used in the implementation of GCM mode. * @@ -59,6 +69,10 @@ // NOTE: cipher should already be initialized GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) { this.aes = cipher; + if (initialCounterBlk.length != AES_BLOCK_SIZE) { + throw new RuntimeException("length of initial counter block (" + initialCounterBlk.length + + ") not equal to AES_BLOCK_SIZE (" + AES_BLOCK_SIZE + ")"); + } this.icb = initialCounterBlk; this.counter = icb.clone(); } @@ -137,6 +151,8 @@ * Restores the content of this object to the previous saved one. */ void restore() { - this.counter = this.counterSave; + if (this.counterSave != null) { + this.counter = this.counterSave; + } } }