8149070: Enforce update ordering
authorvaleriep
Fri, 11 Mar 2016 23:54:17 +0000
changeset 39750 982b75e31495
parent 39749 ea071138bf61
child 39751 47948cf5c3c5
8149070: Enforce update ordering Summary: Make sure that ISE is thrown when updateAAD is called after update. Reviewed-by: mullan
jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java
jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java
jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java
jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java	Thu Jan 28 11:03:09 2016 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java	Fri Mar 11 23:54:17 2016 +0000
@@ -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 @@
      */
     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 @@
     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 @@
                               SecureRandom random)
         throws InvalidKeyException, InvalidAlgorithmParameterException {
         checkKeySize(key, fixedKeySize);
+        updateCalled = false;
         core.init(opmode, key, params, random);
     }
 
@@ -344,6 +351,7 @@
                               SecureRandom random)
         throws InvalidKeyException, InvalidAlgorithmParameterException {
         checkKeySize(key, fixedKeySize);
+        updateCalled = false;
         core.init(opmode, key, params, random);
     }
 
@@ -368,6 +376,7 @@
      */
     protected byte[] engineUpdate(byte[] input, int inputOffset,
                                   int inputLen) {
+        updateCalled = true;
         return core.update(input, inputOffset, inputLen);
     }
 
@@ -397,6 +406,7 @@
     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 @@
      */
     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 @@
                                 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 @@
      */
     @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 @@
      */
     @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) {
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java	Thu Jan 28 11:03:09 2016 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java	Fri Mar 11 23:54:17 2016 +0000
@@ -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 @@
     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 @@
             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 @@
         }
     }
 
+    /**
+     * 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
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java	Thu Jan 28 11:03:09 2016 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java	Fri Mar 11 23:54:17 2016 +0000
@@ -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 @@
 
     // 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;
         }
     }
 
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java	Thu Jan 28 11:03:09 2016 +0100
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java	Fri Mar 11 23:54:17 2016 +0000
@@ -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 @@
 
     // 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 @@
      * 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 @@
     @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 @@
             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 @@
             }
             lastEncIv = ivBytes;
             lastEncKey = keyBytes;
+            ibuffer = null;
         } else {
             requireReinit = false;
             ibuffer = new ByteArrayOutputStream();
@@ -246,9 +250,11 @@
     // 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 @@
                  "(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 @@
                 + "(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) {