8177784: Use CounterMode intrinsic for AES/GCM
authorascarpino
Wed, 12 Apr 2017 12:57:49 -0700
changeset 44641 64c16b6d5165
parent 44640 590dec7cadb4
child 44642 331e669007f7
8177784: Use CounterMode intrinsic for AES/GCM Reviewed-by: mullan, psandoz, chegar
jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java
jdk/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java
--- 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;
-        }
-    }
 }