8020081: Cipher with OAEPPadding and OAEPParameterSpec can't be created
authorascarpino
Mon, 12 Aug 2013 11:25:42 -0700
changeset 19390 071b67eb2d0d
parent 19389 044bdfe2b361
child 19392 c08a64a9a5f1
child 19396 20ddd34c2abe
8020081: Cipher with OAEPPadding and OAEPParameterSpec can't be created Reviewed-by: mullan
jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java
jdk/test/com/sun/crypto/provider/Cipher/RSA/TestOAEPPadding.java
--- a/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java	Mon Aug 12 16:09:24 2013 -0400
+++ b/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java	Mon Aug 12 11:25:42 2013 -0700
@@ -124,7 +124,8 @@
                     put("Cipher.RSA", "com.sun.crypto.provider.RSACipher");
                     put("Cipher.RSA SupportedModes", "ECB");
                     put("Cipher.RSA SupportedPaddings",
-                            "NOPADDING|PKCS1PADDING|OAEPWITHMD5ANDMGF1PADDING"
+                            "NOPADDING|PKCS1PADDING|OAEPPADDING"
+                            + "|OAEPWITHMD5ANDMGF1PADDING"
                             + "|OAEPWITHSHA1ANDMGF1PADDING"
                             + "|OAEPWITHSHA-1ANDMGF1PADDING"
                             + "|OAEPWITHSHA-224ANDMGF1PADDING"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/crypto/provider/Cipher/RSA/TestOAEPPadding.java	Mon Aug 12 11:25:42 2013 -0700
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2013, 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 8020081
+ * @summary encryption/decryption test for using OAEPPadding with
+ * OAEPParameterSpec specified and not specified during a Cipher.init().
+ * @author Anthony Scarpino
+ */
+
+import java.util.Arrays;
+
+import java.security.Security;
+import java.security.Provider;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.spec.PSource;
+
+
+public class TestOAEPPadding {
+    private static RSAPrivateKey privateKey;
+    private static RSAPublicKey publicKey;
+    static Provider cp;
+    static boolean failed = false;
+
+    public static void main(String args[]) throws Exception {
+        cp = Security.getProvider("SunJCE");
+        System.out.println("Testing provider " + cp.getName() + "...");
+        Provider kfp = Security.getProvider("SunRsaSign");
+        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", kfp);
+        kpg.initialize(2048);
+        KeyPair kp = kpg.generateKeyPair();
+        privateKey = (RSAPrivateKey)kp.getPrivate();
+        publicKey = (RSAPublicKey)kp.getPublic();
+
+        // Test using a spec with each digest algorithm case
+        test(new OAEPParameterSpec("MD5", "MGF1",
+                MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
+        test(new OAEPParameterSpec("SHA1", "MGF1",
+                MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
+        // For default OAEPParameterSpec case (SHA1)
+        test(null);
+        test(new OAEPParameterSpec("SHA-224", "MGF1",
+                MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
+        test(new OAEPParameterSpec("SHA-256", "MGF1",
+                MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
+        test(new OAEPParameterSpec("SHA-384", "MGF1",
+                MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
+        test(new OAEPParameterSpec("SHA-512", "MGF1",
+                MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
+        if (failed) {
+            throw new Exception("Test failed");
+        }
+    }
+
+    /*
+     * Test with one byte, the max bytes, and the max + 1 bytes allowed by
+     * the RSA key size and the digest algorithm
+     */
+    static void test(OAEPParameterSpec spec) throws Exception {
+        int dlen = 0;
+        String algo;
+
+        // For default OAEPParameterSpec case (SHA1)
+        if (spec == null) {
+            dlen = 20;
+            algo = "Default";
+        } else {
+            // Use the digest algorith provided in the spec
+            algo = spec.getDigestAlgorithm();
+            if (algo.equals("MD5")) {
+                dlen = 16;
+            } else if (algo.equals("SHA1")) {
+                dlen = 20;
+            } else if (algo.equals("SHA-224")) {
+                dlen = 28;
+            } else if (algo.equals("SHA-256")) {
+                dlen = 32;
+            } else if (algo.equals("SHA-384")) {
+                dlen = 48;
+            } else if (algo.equals("SHA-512")) {
+                dlen = 64;
+            }
+        }
+
+        // OAEP maximum length for a given digest algorith & RSA key length
+        int max = ((publicKey.getModulus().bitLength() / 8) - (2 * dlen) - 2);
+
+        // Test with data length of 1
+        try {
+            testEncryptDecrypt(spec, 1);
+        } catch (Exception e) {
+            System.out.println(algo + " failed with data length of 1");
+            e.printStackTrace();
+            failed = true;
+        }
+
+        // Test with data length of maximum allowed
+        try {
+            testEncryptDecrypt(spec, max);
+        } catch (Exception e) {
+            System.out.println(algo + " failed with data length of " + max);
+            e.printStackTrace();
+            failed = true;
+        }
+
+        // Test with data length of maximum allowed + 1
+        try {
+            testEncryptDecrypt(spec, max + 1);
+            throw new Exception();
+        } catch (IllegalBlockSizeException ie) {
+                // expected to fail
+        } catch (Exception e) {
+            System.err.println(algo + " failed with data length of " +
+                    (max + 1));
+            e.printStackTrace();
+            failed = true;
+
+        }
+    }
+
+    private static void testEncryptDecrypt(OAEPParameterSpec spec,
+            int dataLength) throws Exception {
+        System.out.println("Testing OAEP with hash " +
+                ((spec != null) ? spec.getDigestAlgorithm() : "Default") +
+                ", " + dataLength + " bytes");
+
+        Cipher c = Cipher.getInstance("RSA/ECB/OAEPPadding", cp);
+        if (spec != null) {
+            c.init(Cipher.ENCRYPT_MODE, publicKey, spec);
+        } else {
+            c.init(Cipher.ENCRYPT_MODE, publicKey);
+        }
+
+        byte[] data = new byte[dataLength];
+        byte[] enc = c.doFinal(data);
+        if (spec != null) {
+            c.init(Cipher.DECRYPT_MODE, privateKey, spec);
+        } else {
+            c.init(Cipher.DECRYPT_MODE, privateKey);
+        }
+        byte[] dec = c.doFinal(enc);
+        if (Arrays.equals(data, dec) == false) {
+            throw new Exception("Data does not match");
+        }
+    }
+}