8180392: SunJCE provider should throw exceptions for unsupported mode and padding combinations
authorvaleriep
Thu, 25 Jul 2019 02:16:49 +0000
changeset 57538 445c32471dc6
parent 57513 6073b2290c0a
child 57539 e95f52891ce5
8180392: SunJCE provider should throw exceptions for unsupported mode and padding combinations Summary: Change JCA Cipher class to create obj to ensure the mode and padding combination is supported Reviewed-by: xuelei
src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java
src/java.base/share/classes/javax/crypto/Cipher.java
test/jdk/com/sun/crypto/provider/Cipher/AES/Padding.java
test/jdk/com/sun/crypto/provider/Cipher/AES/TestNoPaddingModes.java
test/jdk/com/sun/crypto/provider/Cipher/Blowfish/TestCipherBlowfish.java
test/jdk/com/sun/crypto/provider/Cipher/DES/TestCipherDES.java
test/jdk/com/sun/crypto/provider/Cipher/DES/TestCipherDESede.java
test/jdk/javax/crypto/Cipher/CipherInputStreamExceptions.java
--- a/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java	Wed Jul 24 17:08:14 2019 -0700
+++ b/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java	Thu Jul 25 02:16:49 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2019, 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
@@ -271,7 +271,9 @@
             padding = null;
         } else if (paddingScheme.equalsIgnoreCase("ISO10126Padding")) {
             padding = new ISO10126Padding(blockSize);
-        } else if (!paddingScheme.equalsIgnoreCase("PKCS5Padding")) {
+        } else if (paddingScheme.equalsIgnoreCase("PKCS5Padding")) {
+            padding = new PKCS5Padding(blockSize);
+        } else {
             throw new NoSuchPaddingException("Padding: " + paddingScheme
                                              + " not implemented");
         }
--- a/src/java.base/share/classes/javax/crypto/Cipher.java	Wed Jul 24 17:08:14 2019 -0700
+++ b/src/java.base/share/classes/javax/crypto/Cipher.java	Thu Jul 25 02:16:49 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -559,16 +559,16 @@
                 // does not support mode or padding we need, ignore
                 continue;
             }
-            if (canuse == S_YES) {
+            // S_YES, S_MAYBE
+            // even when mode and padding are both supported, they
+            // may not be used together, try out and see if it works
+            try {
+                CipherSpi spi = (CipherSpi)s.newInstance(null);
+                tr.setModePadding(spi);
+                // specify null instead of spi for delayed provider selection
                 return new Cipher(null, s, t, transformation, transforms);
-            } else { // S_MAYBE, try out if it works
-                try {
-                    CipherSpi spi = (CipherSpi)s.newInstance(null);
-                    tr.setModePadding(spi);
-                    return new Cipher(spi, s, t, transformation, transforms);
-                } catch (Exception e) {
-                    failure = e;
-                }
+            } catch (Exception e) {
+                failure = e;
             }
         }
         throw new NoSuchAlgorithmException
--- a/test/jdk/com/sun/crypto/provider/Cipher/AES/Padding.java	Wed Jul 24 17:08:14 2019 -0700
+++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/Padding.java	Thu Jul 25 02:16:49 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -48,19 +48,24 @@
 
     private static final String ALGORITHM = "AES";
     private static final String PROVIDER = "SunJCE";
-    private static final String[] MODES = { "ECb", "CbC", "PCBC", "OFB",
+    private static final String[] MODES_PKCS5PAD = {
+        "ECb", "CbC", "PCBC", "OFB",
         "OFB150", "cFB", "CFB7", "cFB8", "cFB16", "cFB24", "cFB32",
         "Cfb40", "cfB48", "cfB56", "cfB64", "cfB72", "cfB80", "cfB88",
         "cfB96", "cfb104", "cfB112", "cfB120", "OFB8", "OFB16", "OFB24",
         "OFB32", "OFB40", "OFB48", "OFB56", "OFB64", "OFB72", "OFB80",
-        "OFB88", "OFB96", "OFB104", "OFB112", "OFB120", "GCM" };
-    private static final String PADDING = "PKCS5Padding";
+        "OFB88", "OFB96", "OFB104", "OFB112", "OFB120" };
+    private static final String[] MODES_NOPAD = { "CTR", "CTS", "GCM" };
+
     private static final int KEY_LENGTH = 128;
 
     public static void main(String argv[]) throws Exception {
         Padding test = new Padding();
-        for (String mode : MODES) {
-            test.runTest(ALGORITHM, mode, PADDING);
+        for (String mode : MODES_PKCS5PAD) {
+            test.runTest(ALGORITHM, mode, "PKCS5Padding");
+        }
+        for (String mode : MODES_NOPAD) {
+            test.runTest(ALGORITHM, mode, "NoPadding");
         }
     }
 
@@ -92,7 +97,6 @@
                 int offset = ci.update(plainText, 0, plainText.length,
                         cipherText, 0);
                 ci.doFinal(cipherText, offset);
-
                 if (!mo.equalsIgnoreCase("ECB")) {
                     iv = ci.getIV();
                     aps = new IvParameterSpec(iv);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestNoPaddingModes.java	Thu Jul 25 02:16:49 2019 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8180392
+ * @summary Ensure SunJCE provider throws exception for unsupported modes
+ *          and padding combinations
+ */
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.*;
+
+public class TestNoPaddingModes {
+
+    // SunJCE only supports NoPadding with following modes
+    private static final String[] MODES = {
+        "CTR", "CTS", "GCM"
+    };
+    private static final String[] PADDINGS = {
+        "PKCS5Padding", "ISO10126Padding"
+    };
+
+    public static void main(String[] args) throws Exception {
+        Provider p = Security.getProvider("SunJCE");
+        String transformation;
+        for (String mode : MODES) {
+            for (String padding : PADDINGS) {
+                transformation = "AES/" + mode + "/" + padding;
+
+                System.out.println("Test using " + transformation);
+                try {
+                    Cipher c = Cipher.getInstance(transformation, "SunJCE");
+                    throw new RuntimeException("=> Fail, no exception thrown");
+                } catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {
+                    System.out.println("=> Expected ex: " + ex);
+                }
+                try {
+                    Cipher c = Cipher.getInstance(transformation, p);
+                    throw new RuntimeException("=> Fail, no exception thrown");
+                } catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {
+                    System.out.println("=> Expected ex: " + ex);
+                }
+            }
+        }
+        System.out.println("Test Passed");
+    }
+
+    public static class MyCipImpl extends CipherSpi {
+        public MyCipImpl() {
+            super();
+            System.out.println("MyCipImpl is created");
+        }
+        protected void engineSetMode(String mode)
+            throws NoSuchAlgorithmException {};
+        protected void engineSetPadding(String padding)
+            throws NoSuchPaddingException {};
+        protected int engineGetBlockSize() { return 16; }
+        protected int engineGetOutputSize(int inputLen) { return 0; }
+        protected byte[] engineGetIV() { return null; }
+        protected AlgorithmParameters engineGetParameters() { return null; }
+        protected void engineInit(int opmode, Key key, SecureRandom random)
+            throws InvalidKeyException {};
+        protected void engineInit(int opmode, Key key,
+                                  AlgorithmParameterSpec params,
+                                  SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {};
+        protected void engineInit(int opmode, Key key,
+                                  AlgorithmParameters params,
+                                  SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {};
+        protected byte[] engineUpdate(byte[] input, int inputOffset,
+                                      int inputLen) { return null; }
+        protected int engineUpdate(byte[] input, int inputOffset,
+                                   int inputLen, byte[] output,
+                                   int outputOffset)
+            throws ShortBufferException { return 0; };
+        protected byte[] engineDoFinal(byte[] input, int inputOffset,
+                                       int inputLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+            return null;
+        }
+        protected int engineDoFinal(byte[] input, int inputOffset,
+                                    int inputLen, byte[] output,
+                                    int outputOffset)
+            throws ShortBufferException, IllegalBlockSizeException,
+                   BadPaddingException  { return 0; }
+    }
+}
--- a/test/jdk/com/sun/crypto/provider/Cipher/Blowfish/TestCipherBlowfish.java	Wed Jul 24 17:08:14 2019 -0700
+++ b/test/jdk/com/sun/crypto/provider/Cipher/Blowfish/TestCipherBlowfish.java	Thu Jul 25 02:16:49 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -32,20 +32,20 @@
 
 public class TestCipherBlowfish extends TestCipher {
 
-    TestCipherBlowfish() throws NoSuchAlgorithmException {
-        super("Blowfish",
-                new String[]{"CBC", "CTR", "CTS", "ECB", "PCBC",
-                    //CFBx
-                    "CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40", "CFB48", "CFB56",
-                    "CFB64",
-                    //OFBx
-                    "OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40", "OFB48", "OFB56",
-                    "OFB64"},
-                new String[]{"NoPaDDing", "PKCS5Padding"},
-                32, 448);
+    TestCipherBlowfish(String[] modes, String[] paddings) throws NoSuchAlgorithmException {
+        super("Blowfish", modes, paddings, 32, 448);
     }
 
     public static void main(String[] args) throws Exception {
-        new TestCipherBlowfish().runAll();
+        new TestCipherBlowfish(new String[]{ "CBC", "ECB", "PCBC",
+            //CFBx
+            "CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40",
+            "CFB48", "CFB56", "CFB64",
+            //OFBx
+            "OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40",
+            "OFB48", "OFB56", "OFB64"},
+        new String[]{ "NoPaDDing", "PKCS5Padding"}).runAll();
+        new TestCipherBlowfish(new String[]{ "CTR", "CTS" },
+            new String[]{ "NoPaDDing" }).runAll();
     }
 }
--- a/test/jdk/com/sun/crypto/provider/Cipher/DES/TestCipherDES.java	Wed Jul 24 17:08:14 2019 -0700
+++ b/test/jdk/com/sun/crypto/provider/Cipher/DES/TestCipherDES.java	Thu Jul 25 02:16:49 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -30,19 +30,20 @@
 
 public class TestCipherDES extends TestCipher {
 
-    TestCipherDES() {
-        super("DES",
-                new String[]{"CBC", "CTR", "CTS", "ECB", "PCBC",
-                    //CFBx
-                    "CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40", "CFB48", "CFB56",
-                    "CFB64",
-                    //OFBx
-                    "OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40", "OFB48", "OFB56",
-                    "OFB64"},
-                new String[]{"NoPaDDing", "PKCS5Padding"});
+    TestCipherDES(String[] modes, String[] paddings) {
+        super("DES", modes, paddings);
     }
 
     public static void main(String[] args) throws Exception {
-        new TestCipherDES().runAll();
+        new TestCipherDES(new String[]{ "CBC", "ECB", "PCBC",
+            //CFBx
+            "CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40",
+            "CFB48", "CFB56", "CFB64",
+            //OFBx
+            "OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40",
+            "OFB48", "OFB56", "OFB64" },
+            new String[]{ "NoPaDDing", "PKCS5Padding" }).runAll();
+        new TestCipherDES(new String[]{ "CTR", "CTS" },
+            new String[]{ "NoPaDDing" }).runAll();
     }
 }
--- a/test/jdk/com/sun/crypto/provider/Cipher/DES/TestCipherDESede.java	Wed Jul 24 17:08:14 2019 -0700
+++ b/test/jdk/com/sun/crypto/provider/Cipher/DES/TestCipherDESede.java	Thu Jul 25 02:16:49 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -30,19 +30,22 @@
 
 public class TestCipherDESede extends TestCipher {
 
-    TestCipherDESede() {
-        super("DESede",
-                new String[]{"CBC", "CTR", "CTS", "ECB", "PCBC",
-                    //CFBx
-                    "CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40", "CFB48", "CFB56",
-                    "CFB64",
-                    //OFBx
-                    "OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40", "OFB48", "OFB56",
-                    "OFB64"},
-                new String[]{"NoPaDDing", "PKCS5Padding"});
+    TestCipherDESede(String[] modes, String[] paddings) {
+        super("DESede", modes, paddings);
     }
 
     public static void main(String[] args) throws Exception {
-        new TestCipherDESede().runAll();
+        new TestCipherDESede(
+            new String[]{ "CBC", "ECB", "PCBC",
+                //CFBx
+                "CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40",
+                "CFB48", "CFB56", "CFB64",
+                //OFBx
+                "OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40",
+                "OFB48", "OFB56", "OFB64"},
+                new String[]{ "NoPaDDing", "PKCS5Padding" }).runAll();
+        new TestCipherDESede(
+            new String[]{ "CTR", "CTS" },
+            new String[]{ "NoPaDDing" }).runAll();
     }
 }
--- a/test/jdk/javax/crypto/Cipher/CipherInputStreamExceptions.java	Wed Jul 24 17:08:14 2019 -0700
+++ b/test/jdk/javax/crypto/Cipher/CipherInputStreamExceptions.java	Thu Jul 25 02:16:49 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -55,7 +55,7 @@
 
     /* Full read stream, check that getMoreData() is throwing an exception
      * This test
-     *   1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
+     *   1) Encrypt 100 bytes with AES/GCM/NoPadding
      *   2) Changes the last byte to invalidate the authetication tag.
      *   3) Fully reads CipherInputStream to decrypt the message and closes
      */
@@ -66,7 +66,7 @@
 
         System.out.println("Running gcm_AEADBadTag");
 
-        // Encrypt 100 bytes with AES/GCM/PKCS5Padding
+        // Encrypt 100 bytes with AES/GCM/NoPadding
         byte[] ct = encryptedText("GCM", 100);
         // Corrupt the encrypted message
         ct = corruptGCM(ct);
@@ -92,7 +92,7 @@
 
     /* Short read stream,
      * This test
-     *   1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
+     *   1) Encrypt 100 bytes with AES/GCM/NoPadding
      *   2) Reads 100 bytes from stream to decrypt the message and closes
      *   3) Make sure no value is returned by read()
      *   4) Make sure no exception is thrown
@@ -106,7 +106,7 @@
 
         byte[] pt = new byte[600];
         pt[0] = 1;
-        // Encrypt provided 600 bytes with AES/GCM/PKCS5Padding
+        // Encrypt provided 600 bytes with AES/GCM/NoPadding
         byte[] ct = encryptedText("GCM", pt);
         // Create stream for decryption
         CipherInputStream in = getStream("GCM", ct);
@@ -134,7 +134,7 @@
      * Verify doFinal() exception is suppressed when input stream is not
      * read before it is closed.
      * This test:
-     *   1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
+     *   1) Encrypt 100 bytes with AES/GCM/NoPadding
      *   2) Changes the last byte to invalidate the authetication tag.
      *   3) Opens a CipherInputStream and the closes it. Never reads from it.
      *
@@ -146,7 +146,7 @@
 
         System.out.println("Running supressUnreadCorrupt test");
 
-        // Encrypt 100 bytes with AES/GCM/PKCS5Padding
+        // Encrypt 100 bytes with AES/GCM/NoPadding
         byte[] ct = encryptedText("GCM", 100);
         // Corrupt the encrypted message
         ct = corruptGCM(ct);
@@ -166,7 +166,7 @@
      * Verify noexception thrown when 1 byte is read from a GCM stream
      * and then closed
      * This test:
-     *   1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
+     *   1) Encrypt 100 bytes with AES/GCM/NoPadding
      *   2) Read one byte from the stream, expect no exception thrown.
      *   4) Close stream,expect no exception thrown.
      */
@@ -174,7 +174,7 @@
 
         System.out.println("Running gcm_oneReadByte test");
 
-        // Encrypt 100 bytes with AES/GCM/PKCS5Padding
+        // Encrypt 100 bytes with AES/GCM/NoPadding
         byte[] ct = encryptedText("GCM", 100);
         // Create stream for decryption
         CipherInputStream in = getStream("GCM", ct);
@@ -192,7 +192,7 @@
      * Verify exception thrown when 1 byte is read from a corrupted GCM stream
      * and then closed
      * This test:
-     *   1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
+     *   1) Encrypt 100 bytes with AES/GCM/NoPadding
      *   2) Changes the last byte to invalidate the authetication tag.
      *   3) Read one byte from the stream, expect exception thrown.
      *   4) Close stream,expect no exception thrown.
@@ -201,7 +201,7 @@
 
         System.out.println("Running gcm_oneReadByteCorrupt test");
 
-        // Encrypt 100 bytes with AES/GCM/PKCS5Padding
+        // Encrypt 100 bytes with AES/GCM/NoPadding
         byte[] ct = encryptedText("GCM", 100);
         // Corrupt the encrypted message
         ct = corruptGCM(ct);
@@ -357,7 +357,7 @@
     static byte[] encryptedText(String mode, byte[] pt) throws Exception{
         Cipher c;
         if (mode.compareTo("GCM") == 0) {
-            c = Cipher.getInstance("AES/GCM/PKCS5Padding", "SunJCE");
+            c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
             c.init(Cipher.ENCRYPT_MODE, key, gcmspec);
         } else if (mode.compareTo("CBC") == 0) {
             c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
@@ -380,7 +380,7 @@
         Cipher c;
 
         if (mode.compareTo("GCM") == 0) {
-            c = Cipher.getInstance("AES/GCM/PKCS5Padding", "SunJCE");
+            c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
             c.init(Cipher.DECRYPT_MODE, key, gcmspec);
         } else if (mode.compareTo("CBC") == 0) {
             c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");