# HG changeset patch # User zmajo # Date 1429083471 -7200 # Node ID 72127fbf99743f88b53d21b456d73934bc6aaf89 # Parent ebd762f092242fd349de3620caa6d7f50fc4b558 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 ebd762f09224 -r 72127fbf9974 jdk/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java Fri Apr 03 11:41:26 2015 -0700 +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java Wed Apr 15 09:37:51 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; + } } }