8177784: Use CounterMode intrinsic for AES/GCM
Reviewed-by: mullan, psandoz, chegar
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java Tue Apr 11 14:18:22 2017 -0400
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java Wed Apr 12 12:57:49 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, 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
@@ -42,10 +42,10 @@
* @author Andreas Sterbenz
* @since 1.4.2
*/
-final class CounterMode extends FeedbackCipher {
+class CounterMode extends FeedbackCipher {
// current counter value
- private final byte[] counter;
+ final byte[] counter;
// encrypted bytes of the previous counter value
private final byte[] encryptedCounter;
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java Tue Apr 11 14:18:22 2017 -0400
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java Wed Apr 12 12:57:49 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017 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
@@ -29,52 +29,43 @@
package com.sun.crypto.provider;
-import java.security.*;
-import javax.crypto.*;
+import javax.crypto.IllegalBlockSizeException;
import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
/**
* This class represents the GCTR function defined in NIST 800-38D
- * 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 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.
+ * under section 6.5. With a given cipher object and initial counter
+ * block, a counter mode operation is performed. Blocksize is limited
+ * to 16 bytes.
*
* 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).
*
+ * The counter mode operations can be intrinsified and parallelized
+ * by using CounterMode.implCrypt() if HotSpot VM supports it on the
+ * architecture.
+ *
* <p>This function is used in the implementation of GCM mode.
*
* @since 1.8
*/
-final class GCTR {
-
- // these fields should not change after the object has been constructed
- private final SymmetricCipher aes;
- private final byte[] icb;
+final class GCTR extends CounterMode {
- // the current counter value
- private byte[] counter;
-
- // needed for save/restore calls
- private byte[] counterSave = null;
-
- // NOTE: cipher should already be initialized
GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) {
- this.aes = cipher;
+ super(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();
+
+ iv = initialCounterBlk;
+ reset();
+ }
+
+ @Override
+ String getFeedback() {
+ return "GCTR";
}
// input must be multiples of 128-bit blocks when calling update
@@ -89,23 +80,11 @@
throw new RuntimeException("output buffer too small");
}
- byte[] encryptedCntr = new byte[AES_BLOCK_SIZE];
-
- int numOfCompleteBlocks = inLen / AES_BLOCK_SIZE;
- for (int i = 0; i < numOfCompleteBlocks; i++) {
- aes.encryptBlock(counter, 0, encryptedCntr, 0);
- for (int n = 0; n < AES_BLOCK_SIZE; n++) {
- int index = (i * AES_BLOCK_SIZE + n);
- out[outOfs + index] =
- (byte) ((in[inOfs + index] ^ encryptedCntr[n]));
- }
- GaloisCounterMode.increment32(counter);
- }
- return inLen;
+ return encrypt(in, inOfs, inLen, out, outOfs);
}
// input can be arbitrary size when calling doFinal
- protected int doFinal(byte[] in, int inOfs, int inLen, byte[] out,
+ int doFinal(byte[] in, int inOfs, int inLen, byte[] out,
int outOfs) throws IllegalBlockSizeException {
try {
if (inLen < 0) {
@@ -118,7 +97,7 @@
if (lastBlockSize != 0) {
// do the last partial block
byte[] encryptedCntr = new byte[AES_BLOCK_SIZE];
- aes.encryptBlock(counter, 0, encryptedCntr, 0);
+ embeddedCipher.encryptBlock(counter, 0, encryptedCntr, 0);
for (int n = 0; n < lastBlockSize; n++) {
out[outOfs + completeBlkLen + n] =
(byte) ((in[inOfs + completeBlkLen + n] ^
@@ -131,28 +110,4 @@
}
return inLen;
}
-
- /**
- * Resets the content of this object to when it's first constructed.
- */
- void reset() {
- System.arraycopy(icb, 0, counter, 0, icb.length);
- counterSave = null;
- }
-
- /**
- * Save the current content of this object.
- */
- void save() {
- this.counterSave = this.counter.clone();
- }
-
- /**
- * Restores the content of this object to the previous saved one.
- */
- void restore() {
- if (this.counterSave != null) {
- this.counter = this.counterSave;
- }
- }
}