8218723: Use SunJCE Mac in SecretKeyFactory PBKDF2 implementation
authorjnimeh
Mon, 18 Mar 2019 15:26:59 -0700
changeset 54182 2e586b74722e
parent 54181 d265655be483
child 54183 7418b266e1c7
8218723: Use SunJCE Mac in SecretKeyFactory PBKDF2 implementation Reviewed-by: apetcher
src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
test/jdk/javax/crypto/SecretKeyFactory/SecKeyFacSunJCEPrf.java
test/jdk/javax/crypto/SecretKeyFactory/evilprov.jar
test/jdk/javax/crypto/SecretKeyFactory/evilprov/Makefile
test/jdk/javax/crypto/SecretKeyFactory/evilprov/README
test/jdk/javax/crypto/SecretKeyFactory/evilprov/com/evilprovider/EvilHmacSHA1.java
test/jdk/javax/crypto/SecretKeyFactory/evilprov/com/evilprovider/EvilProvider.java
test/jdk/javax/crypto/SecretKeyFactory/evilprov/module-info.java
--- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java	Mon Mar 18 11:50:57 2019 -0700
+++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java	Mon Mar 18 15:26:59 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -113,12 +113,7 @@
             } else if (keyLength < 0) {
                 throw new InvalidKeySpecException("Key length is negative");
             }
-            this.prf = Mac.getInstance(prfAlgo);
-            // SunPKCS11 requires a non-empty PBE password
-            if (passwdBytes.length == 0 &&
-                    this.prf.getProvider().getName().startsWith("SunPKCS11")) {
-                this.prf = Mac.getInstance(prfAlgo, SunJCE.getInstance());
-            }
+            this.prf = Mac.getInstance(prfAlgo, SunJCE.getInstance());
             this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength);
         } catch (NoSuchAlgorithmException nsae) {
             // not gonna happen; re-throw just in case
@@ -207,7 +202,7 @@
                 }
             }
         } catch (GeneralSecurityException gse) {
-            throw new RuntimeException("Error deriving PBKDF2 keys");
+            throw new RuntimeException("Error deriving PBKDF2 keys", gse);
         }
         return key;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/crypto/SecretKeyFactory/SecKeyFacSunJCEPrf.java	Mon Mar 18 15:26:59 2019 -0700
@@ -0,0 +1,76 @@
+/*
+ * 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 8218723
+ * @summary Use SunJCE Mac in SecretKeyFactory PBKDF2 implementation
+ * @library evilprov.jar
+ * @library /test/lib
+ * @build jdk.test.lib.Convert
+ * @run main/othervm SecKeyFacSunJCEPrf
+ */
+
+import java.util.Arrays;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+import java.security.Provider;
+import java.security.Security;
+import com.evilprovider.*;
+import jdk.test.lib.Convert;
+
+public class SecKeyFacSunJCEPrf {
+
+    // One of the PBKDF2 HMAC-SHA1 test vectors from RFC 6070
+    private static final byte[] SALT = "salt".getBytes();
+    private static final char[] PASS = "password".toCharArray();
+    private static final int ITER = 4096;
+    private static final byte[] EXP_OUT = Convert.hexStringToByteArray(
+            "4B007901B765489ABEAD49D926F721D065A429C1");
+
+    public static void main(String[] args) throws Exception {
+        // Instantiate the Evil Provider and insert it in the
+        // most-preferred position.
+        Provider evilProv = new EvilProvider();
+        System.out.println("3rd Party Provider: " + evilProv);
+        Security.insertProviderAt(evilProv, 1);
+
+        SecretKeyFactory pbkdf2 =
+                SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1", "SunJCE");
+        PBEKeySpec pbks = new PBEKeySpec(PASS, SALT, ITER, 160);
+
+        SecretKey secKey1 = pbkdf2.generateSecret(pbks);
+        System.out.println("PBKDF2WithHmacSHA1:\n" +
+                    Convert.byteArrayToHexString(secKey1.getEncoded()));
+        if (Arrays.equals(secKey1.getEncoded(), EXP_OUT)) {
+            System.out.println("Test Vector Passed");
+        } else {
+            System.out.println("Test Vector Failed");
+            System.out.println("Expected Output:\n" +
+                    Convert.byteArrayToHexString(EXP_OUT));
+            throw new RuntimeException();
+        }
+    }
+}
+
Binary file test/jdk/javax/crypto/SecretKeyFactory/evilprov.jar has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/crypto/SecretKeyFactory/evilprov/Makefile	Mon Mar 18 15:26:59 2019 -0700
@@ -0,0 +1,55 @@
+#
+# 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.
+#
+
+# Java paths
+#JAVA_BASE=PATH_TO_JAVA_IMG_DIR
+JAVABIN=$(JAVA_BASE)/bin
+JAVAC=$(JAVABIN)/javac
+JAVA=$(JAVABIN)/java
+JAR=$(JAVABIN)/jar 
+JARSIGNER=$(JAVABIN)/jarsigner
+
+# Compile-time flags and paths
+JFLAGS=-Xlint:all
+SRCPATH=com/evilprovider
+CLASSDST=classes
+
+PROVJAR=evilprov.jar
+KSTORE=PATH_TO_KEYSTORE
+KALIAS=PLACE_SIGNING_ALIAS_HERE
+MODVER=1.0
+
+all: $(PROVJAR)
+
+%.class: %.java
+	mkdir -p $(CLASSDST)
+	$(JAVAC) -d $(CLASSDST) $(JFLAGS) $<
+
+$(PROVJAR): $(SRCPATH)/EvilHmacSHA1.class $(SRCPATH)/EvilProvider.class module-info.class
+	$(JAR) --create --file $(PROVJAR) --module-version $(MODVER) -C $(CLASSDST) .
+
+signed: $(PROVJAR)
+	jarsigner -keystore $(KSTORE) $(PROVJAR).jar $(KALIAS)
+
+clean:
+	rm -rf $(CLASSDST) $(PROVJAR)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/crypto/SecretKeyFactory/evilprov/README	Mon Mar 18 15:26:59 2019 -0700
@@ -0,0 +1,15 @@
+Everything in this directory is dedicated to building the EvilProvider
+used with the SecKeyFacSunJCEPRF test (JDK-8218723).
+
+The makefile does require a JDK image path to be provided through the
+JAVA_BASE makefile variable.  As an example:
+
+make JAVA_BASE=/usr/java/jdk-11.0.1 evilprov
+
+Since the EvilProvider is a modular jar, JDK 9 or later should be used.
+
+For OpenJDK, no signing is required.  If signing is required (for use
+with Oracle JDK, for instance), you must obtain a JCE signing certificate
+and place it in a keystore, then run the "signed" makefile target (it will
+build the jar file if it does not already exist).
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/crypto/SecretKeyFactory/evilprov/com/evilprovider/EvilHmacSHA1.java	Mon Mar 18 15:26:59 2019 -0700
@@ -0,0 +1,90 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.evilprovider;
+
+import java.security.*;
+import java.security.spec.*;
+import java.nio.ByteBuffer;
+
+import javax.crypto.*;
+
+public final class EvilHmacSHA1 extends MacSpi {
+    private final Mac internalMac;
+
+    public EvilHmacSHA1() throws GeneralSecurityException {
+        internalMac = Mac.getInstance("HmacSHA1", "SunJCE");
+    }
+
+    @Override
+    protected byte[] engineDoFinal() {
+        return internalMac.doFinal();
+    }
+
+    @Override
+    protected int engineGetMacLength() {
+        return internalMac.getMacLength();
+    }
+
+    @Override
+    protected void engineInit(Key key, AlgorithmParameterSpec spec)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        SecretKey sKey;
+        if (key instanceof SecretKey) {
+            sKey = (SecretKey)key;
+        } else {
+            throw new IllegalArgumentException("Key must be a SecretKey");
+        }
+
+        byte[] sKeyEnc = sKey.getEncoded();
+        int keyBits = sKeyEnc.length * 8;
+        if (keyBits < 160) {
+            throw new IllegalArgumentException("Key must be at least 160 bits");
+        }
+
+        // Pass through to init
+        internalMac.init(key, spec);
+    }
+
+    @Override
+    protected void engineReset() {
+        internalMac.reset();
+    }
+
+    @Override
+    protected void engineUpdate(byte input) {
+        internalMac.update(input);
+    }
+
+    @Override
+    protected void engineUpdate(byte[] input, int offset, int len) {
+        internalMac.update(input, offset, len);
+    }
+
+    @Override
+    protected void engineUpdate(ByteBuffer input) {
+        internalMac.update(input);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/crypto/SecretKeyFactory/evilprov/com/evilprovider/EvilProvider.java	Mon Mar 18 15:26:59 2019 -0700
@@ -0,0 +1,40 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.evilprovider;
+
+import java.security.*;
+
+public final class EvilProvider extends Provider {
+
+    private static final long serialVersionUID = 11223344550000L;
+
+    public EvilProvider() {
+        super("EvilProvider", "1.0", "Evil Provider");
+        putService(new Provider.Service(this, "Mac", "HmacSHA1",
+                    "com.evilprovider.EvilHmacSHA1", null, null));
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/crypto/SecretKeyFactory/evilprov/module-info.java	Mon Mar 18 15:26:59 2019 -0700
@@ -0,0 +1,35 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+/**
+ * Provides the evil provider
+ *
+ * @provides java.security.Provider
+ *
+ * @moduleGraph
+ */
+module jdk.evilprovider {
+    provides java.security.Provider with com.evilprovider.EvilProvider;
+}