8020081: Cipher with OAEPPadding and OAEPParameterSpec can't be created
Reviewed-by: mullan
--- 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");
+ }
+ }
+}