8156059: Update/Develop new tests for JEP 287: SHA-3 Hash Algorithms
authoramjiang
Tue, 31 May 2016 22:41:56 +0000
changeset 38761 e31b47204f64
parent 38760 bd8975d946b8
child 38762 2956ccc7cb77
8156059: Update/Develop new tests for JEP 287: SHA-3 Hash Algorithms Summary: Update existing MessageDigest tests with SHA-3 Hash Algorithms and add one test case to check supported providers Reviewed-by: valeriep, rhalade
jdk/test/java/security/MessageDigest/TestDigestIOStream.java
jdk/test/java/security/MessageDigest/TestSameLength.java
jdk/test/java/security/MessageDigest/TestSameValue.java
jdk/test/java/security/MessageDigest/UnsupportedProvider.java
--- a/jdk/test/java/security/MessageDigest/TestDigestIOStream.java	Tue May 31 13:15:48 2016 -0700
+++ b/jdk/test/java/security/MessageDigest/TestDigestIOStream.java	Tue May 31 22:41:56 2016 +0000
@@ -1,5 +1,6 @@
+
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -27,16 +28,21 @@
 import java.security.DigestInputStream;
 import java.security.DigestOutputStream;
 import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
 import java.util.Arrays;
 import java.util.Random;
+import jdk.testlibrary.RandomFactory;
 import static java.lang.System.out;
 
 /**
  * @test
- * @bug 8050370
+ * @bug 8050370 8156059
  * @summary MessageDigest tests with DigestIOStream
  * @author Kevin Liu
  * @key randomness
+ * @library /lib/testlibrary
+ * @run main/timeout=180 TestDigestIOStream
  */
 
 enum ReadModel {
@@ -45,12 +51,11 @@
 
 public class TestDigestIOStream {
 
-    private static final int[] DATA_LEN_ARRAY = {
-        1, 50, 2500, 125000, 6250000
-    };
-    private static final String[] ALGORITHM_ARRAY = {
-        "MD2", "MD5", "SHA1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"
-    };
+    private static final int[] DATA_LEN_ARRAY = { 1, 50, 2500, 125000,
+            6250000 };
+    private static final String[] ALGORITHM_ARRAY = { "MD2", "MD5", "SHA1",
+            "SHA-224", "SHA-256", "SHA-384", "SHA-512", "SHA3-224", "SHA3-256",
+            "SHA3-384", "SHA3-512" };
 
     private static byte[] data;
 
@@ -62,44 +67,69 @@
     }
 
     public void run() throws Exception {
-        for (String algorithm: ALGORITHM_ARRAY) {
+        for (String algorithm : ALGORITHM_ARRAY) {
+            try {
+                md = MessageDigest.getInstance(algorithm);
+                for (int length : DATA_LEN_ARRAY) {
 
-            md = MessageDigest.getInstance(algorithm);
-
-            for (int length: DATA_LEN_ARRAY) {
+                    Random rdm = RandomFactory.getRandom();
+                    data = new byte[length];
+                    rdm.nextBytes(data);
 
-                Random rdm = new Random();
-                data = new byte[length];
-                rdm.nextBytes(data);
-
-                if (!testMDChange(algorithm, length)) {
-                    throw new RuntimeException("testMDChange failed at:"
-                            + algorithm + "/" + length);
+                    if (!testMDChange(algorithm, length)) {
+                        throw new RuntimeException("testMDChange failed at:"
+                                + algorithm + "/" + length);
+                    }
+                    if (!testMDShare(algorithm, length)) {
+                        throw new RuntimeException("testMDShare failed at:"
+                                + algorithm + "/" + length);
+                    }
+                    for (ReadModel readModel : ReadModel.values()) {
+                        // test Digest function when digest switch on
+                        if (!testDigestOnOff(algorithm, readModel, true,
+                                length)) {
+                            throw new RuntimeException(
+                                    "testDigestOn failed at:" + algorithm + "/"
+                                            + length + "/" + readModel);
+                        }
+                        // test Digest function when digest switch off
+                        if (!testDigestOnOff(algorithm, readModel, false,
+                                length)) {
+                            throw new RuntimeException(
+                                    "testDigestOff failed at:" + algorithm + "/"
+                                            + length + "/" + readModel);
+                        }
+                    }
                 }
-                if (!testMDShare(algorithm, length)) {
-                    throw new RuntimeException("testMDShare failed at:"
-                            + algorithm + "/" + length);
-                }
-                for (ReadModel readModel: ReadModel.values()) {
-                    // test Digest function when digest switch on
-                    if (!testDigestOnOff(algorithm, readModel, true, length)) {
-                        throw new RuntimeException("testDigestOn failed at:"
-                                + algorithm + "/" + length + "/" + readModel);
-                    }
-                    // test Digest function when digest switch off
-                    if (!testDigestOnOff(algorithm, readModel, false, length)) {
-                        throw new RuntimeException("testDigestOff failed at:"
-                                + algorithm + "/" + length + "/" + readModel);
-                    }
+            } catch (NoSuchAlgorithmException nae) {
+                if (algorithm.startsWith("SHA3") && !isSHA3supported()) {
+                    continue;
+                } else {
+                    throw nae;
                 }
             }
         }
         int testNumber = ALGORITHM_ARRAY.length * ReadModel.values().length
-                * DATA_LEN_ARRAY.length * 2 + ALGORITHM_ARRAY.length
-                * DATA_LEN_ARRAY.length * 2;
+                * DATA_LEN_ARRAY.length * 2
+                + ALGORITHM_ARRAY.length * DATA_LEN_ARRAY.length * 2;
         out.println("All " + testNumber + " Tests Passed");
     }
 
+    // SHA-3 hash algorithms are only supported by "SUN" provider
+    // and "OracleUcrypto" provider on Solaris 12.0 or later
+    // This method checks if system supports SHA-3
+    private boolean isSHA3supported() {
+        if (Security.getProvider("SUN") != null) {
+            return true;
+        }
+        if (Security.getProvider("OracleUcrypto") != null
+                && "SunOS".equals(System.getProperty("os.name"))
+                && System.getProperty("os.version").compareTo("5.12") >= 0) {
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Test DigestInputStream and DigestOutputStream digest function when digest
      * set on and off
@@ -115,8 +145,8 @@
      * @exception Exception
      *                throw unexpected exception
      */
-    public boolean testDigestOnOff(String algo, ReadModel readModel,
-            boolean on, int dataLength) throws Exception {
+    public boolean testDigestOnOff(String algo, ReadModel readModel, boolean on,
+            int dataLength) throws Exception {
 
         // Generate the DigestInputStream/DigestOutputStream object
         try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
@@ -302,7 +332,8 @@
         try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
                 DigestInputStream dis = new DigestInputStream(bais, mdCommon);
                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                DigestOutputStream dos = new DigestOutputStream(baos, mdCommon);) {
+                DigestOutputStream dos = new DigestOutputStream(baos,
+                        mdCommon);) {
 
             // Perform the update using all available/possible update methods
             int k = 0;
--- a/jdk/test/java/security/MessageDigest/TestSameLength.java	Tue May 31 13:15:48 2016 -0700
+++ b/jdk/test/java/security/MessageDigest/TestSameLength.java	Tue May 31 22:41:56 2016 +0000
@@ -1,5 +1,6 @@
+
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -22,18 +23,20 @@
  */
 
 import static java.lang.System.out;
-
 import java.nio.ByteBuffer;
 import java.security.MessageDigest;
-import java.util.Random;
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import jdk.testlibrary.RandomFactory;
 
 /**
  * @test
- * @bug 8050371
+ * @bug 8050371 8156059
  * @summary Check md.getDigestLength() equal digest output length with various
  *          algorithm/dataLen/(update,digest methods).
  * @author Kevin Liu
  * @key randomness
+ * @library /lib/testlibrary
  */
 
 public class TestSameLength {
@@ -44,20 +47,15 @@
     }
 
     private void run() throws Exception {
-        String[] algorithmArr = {
-                "SHA", "Sha", "SHA-1", "sha-1", "SHA1", "sha1", "MD5", "md5",
-                "SHA-224", "SHA-256", "SHA-384", "SHA-512"
-        };
-        int[] nUpdatesArr = {
-                0, 1, 2, 3
-        };
-        int[] dataLenArr = {
-                1, 50, 2500, 125000, 6250000
-        };
+        String[] algorithmArr = { "SHA", "Sha", "SHA-1", "sha-1", "SHA1",
+                "sha1", "MD5", "md5", "SHA-224", "SHA-256", "SHA-384",
+                "SHA-512", "SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512" };
+        int[] nUpdatesArr = { 0, 1, 2, 3 };
+        int[] dataLenArr = { 1, 50, 2500, 125000, 6250000 };
 
-        for (String algorithm: algorithmArr) {
-            for (UpdateMethod update: UpdateMethod.values()) {
-                for (int dataLen: dataLenArr) {
+        for (String algorithm : algorithmArr) {
+            for (UpdateMethod update : UpdateMethod.values()) {
+                for (int dataLen : dataLenArr) {
                     if (!runTest(algorithm, dataLen, update)) {
                         throw new RuntimeException(
                                 "Test failed at algorithm/dataLen/numUpdate:"
@@ -68,16 +66,17 @@
             }
         }
 
-        out.println("All " + algorithmArr.length * nUpdatesArr.length
-                * dataLenArr.length + " tests Passed");
+        out.println("All "
+                + algorithmArr.length * nUpdatesArr.length * dataLenArr.length
+                + " tests Passed");
     }
 
-    private boolean runTest(String algo, long dataLen,
-            UpdateMethod whichUpdate) throws Exception {
+    private boolean runTest(String algo, long dataLen, UpdateMethod whichUpdate)
+            throws Exception {
         try {
             // Do initialization
             byte[] data = new byte[(int) dataLen];
-            new Random().nextBytes(data);
+            RandomFactory.getRandom().nextBytes(data);
             MessageDigest md = MessageDigest.getInstance(algo);
             int outputLen = md.getDigestLength();
 
@@ -88,6 +87,11 @@
 
             // Compare input and output
             return outputLen == output.length;
+        } catch (NoSuchAlgorithmException nae) {
+            if (algo.startsWith("SHA3") && !isSHA3supported()) {
+                return true;
+            }
+            throw nae;
         } catch (Exception ex) {
             System.err.println("Testing: " + algo + "/" + dataLen + "/"
                     + whichUpdate.toString()
@@ -97,11 +101,26 @@
         }
     }
 
+    // SHA-3 hash algorithms are only supported by "SUN" provider
+    // and "OracleUcrypto" provider on Solaris 12.0 or later
+    // This method checks if system supports SHA-3
+    private boolean isSHA3supported() {
+        if (Security.getProvider("SUN") != null) {
+            return true;
+        }
+        if (Security.getProvider("OracleUcrypto") != null
+                && "SunOS".equals(System.getProperty("os.name"))
+                && System.getProperty("os.version").compareTo("5.12") >= 0) {
+            return true;
+        }
+        return false;
+    }
+
     private static enum UpdateMethod {
         UPDATE_BYTE {
             @Override
-            public void updateDigest(byte[] data,
-                    MessageDigest md, long dataLen) {
+            public void updateDigest(byte[] data, MessageDigest md,
+                    long dataLen) {
 
                 for (int i = 0; i < dataLen; i++) {
                     md.update(data[i]);
@@ -111,8 +130,8 @@
 
         UPDATE_BUFFER {
             @Override
-            public void updateDigest(byte[] data,
-                    MessageDigest md, long dataLen) {
+            public void updateDigest(byte[] data, MessageDigest md,
+                    long dataLen) {
 
                 md.update(data);
             }
@@ -120,8 +139,8 @@
 
         UPDATE_BUFFER_LEN {
             @Override
-            public void updateDigest(byte[] data,
-                    MessageDigest md, long dataLen) {
+            public void updateDigest(byte[] data, MessageDigest md,
+                    long dataLen) {
 
                 for (int i = 0; i < dataLen; i++) {
                     md.update(data, i, 1);
@@ -131,14 +150,14 @@
 
         UPDATE_BYTE_BUFFER {
             @Override
-            public void updateDigest(byte[] data,
-                    MessageDigest md, long dataLen) {
+            public void updateDigest(byte[] data, MessageDigest md,
+                    long dataLen) {
 
                 md.update(ByteBuffer.wrap(data));
             }
         };
 
-        public abstract void updateDigest(byte[] data,
-                    MessageDigest md, long dataLen);
-        }
+        public abstract void updateDigest(byte[] data, MessageDigest md,
+                long dataLen);
+    }
 }
--- a/jdk/test/java/security/MessageDigest/TestSameValue.java	Tue May 31 13:15:48 2016 -0700
+++ b/jdk/test/java/security/MessageDigest/TestSameValue.java	Tue May 31 22:41:56 2016 +0000
@@ -1,5 +1,6 @@
+
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -22,19 +23,21 @@
  */
 
 import static java.lang.System.out;
-
 import java.nio.ByteBuffer;
 import java.security.DigestException;
 import java.security.MessageDigest;
-import java.util.Random;
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import jdk.testlibrary.RandomFactory;
 
 /**
  * @test
- * @bug 8050371
+ * @bug 8050371 8156059
  * @summary Check md.digest(data) value whether same with digest output value
  *          with various update/digest methods.
  * @author Kevin Liu
  * @key randomness
+ * @library /lib/testlibrary
  */
 
 public class TestSameValue {
@@ -49,24 +52,17 @@
         byte[] data = new byte[6706];
         MessageDigest md = null;
         // Initialize input data
-        new Random().nextBytes(data);
+        RandomFactory.getRandom().nextBytes(data);
+
+        String[] algorithmArr = { "SHA", "Sha", "MD5", "md5", "SHA-224",
+                "SHA-256", "SHA-384", "SHA-512", "SHA3-224", "SHA3-256",
+                "SHA3-384", "SHA3-512" };
 
-        String[] providers = {
-                null, "SUN"
-        };
-        String[] algorithmArr = {
-                "SHA", "Sha", "MD5", "md5", "SHA-224", "SHA-256", "SHA-384",
-                "SHA-512"
-        };
+        for (String algorithm : algorithmArr) {
+            try {
+                md = MessageDigest.getInstance(algorithm);
 
-        for (String algorithm: algorithmArr) {
-            for (String provider: providers) {
-                if (provider != null) {
-                    md = MessageDigest.getInstance(algorithm, provider);
-                } else {
-                    md = MessageDigest.getInstance(algorithm);
-                }
-                for (UpdateDigestMethod updateMethod: UpdateDigestMethod
+                for (UpdateDigestMethod updateMethod : UpdateDigestMethod
                         .values()) {
                     byte[] output = updateMethod.updateDigest(data, md);
                     // Get the output and the "correct" one
@@ -75,50 +71,71 @@
                     if (!MessageDigest.isEqual(output, standard)) {
                         throw new RuntimeException(
                                 "Test failed at algorithm/provider/numUpdate:"
-                                        + algorithm + "/" + provider + "/"
-                                        + updateMethod);
+                                        + algorithm + "/" + md.getProvider()
+                                        + "/" + updateMethod);
                     }
                 }
+            } catch (NoSuchAlgorithmException nae) {
+                if (algorithm.startsWith("SHA3") && !isSHA3supported()) {
+                    continue;
+                } else {
+                    throw nae;
+                }
             }
         }
 
-        out.println("All " + algorithmArr.length
-                * UpdateDigestMethod.values().length * providers.length
+        out.println("All "
+                + algorithmArr.length * UpdateDigestMethod.values().length
                 + " tests Passed");
     }
 
+    // SHA-3 hash algorithms are only supported by "SUN" provider
+    // and "OracleUcrypto" provider on Solaris 12.0 or later
+    // This method checks if system supports SHA-3
+    private boolean isSHA3supported() {
+        if (Security.getProvider("SUN") != null) {
+            return true;
+        }
+        if (Security.getProvider("OracleUcrypto") != null
+                && "SunOS".equals(System.getProperty("os.name"))
+                && System.getProperty("os.version").compareTo("5.12") >= 0) {
+            return true;
+        }
+        return false;
+    }
+
     private static enum UpdateDigestMethod {
 
         /*
-         * update the data one by one using method update(byte input) then
-         * do digest (giving the output buffer, offset, and the number of
-         * bytes to put in the output buffer)
+         * update the data one by one using method update(byte input) then do
+         * digest (giving the output buffer, offset, and the number of bytes to
+         * put in the output buffer)
          */
         UPDATE_DIGEST_BUFFER {
             @Override
             public byte[] updateDigest(byte[] data, MessageDigest md)
                     throws DigestException {
-                for (byte element: data) {
+                for (byte element : data) {
                     md.update(element);
                 }
                 byte[] output = new byte[md.getDigestLength()];
                 int len = md.digest(output, 0, output.length);
                 if (len != output.length) {
                     throw new RuntimeException(
-                        "ERROR" + ": digest length differs!");
+                            "ERROR" + ": digest length differs!");
                 }
                 return output;
             }
         },
 
         /*
-         * update the data one by one using method update(byte input)
-         * then do digest
+         * update the data one by one using method update(byte input) then do
+         * digest
          */
         UPDATE_DIGEST {
             @Override
             public byte[] updateDigest(byte[] data, MessageDigest md) {
-                for (byte element: data) {
+                for (byte element : data) {
                     md.update(element);
                 }
                 return md.digest();
@@ -139,7 +156,7 @@
                 int len = md.digest(output, 0, output.length);
                 if (len != output.length) {
                     throw new RuntimeException(
-                        "ERROR" + ": digest length differs!");
+                            "ERROR" + ": digest length differs!");
                 }
                 return output;
             }
@@ -155,10 +172,10 @@
         },
 
         /*
-         * update the leading bytes (length is "data.length-LASTNBYTES")
-         * at once as a block, then do digest (do a final update using
-         * the left LASTNBYTES bytes which is passed as a parameter for
-         * the digest method, then complete the digest)
+         * update the leading bytes (length is "data.length-LASTNBYTES") at once
+         * as a block, then do digest (do a final update using the left
+         * LASTNBYTES bytes which is passed as a parameter for the digest
+         * method, then complete the digest)
          */
         UPDATE_LEADING_BLOCK_DIGEST_REMAIN {
             @Override
@@ -176,9 +193,9 @@
         },
 
         /*
-         * update the data 2 bytes each time, after finishing updating,
-         * do digest (giving the output buffer, offset, and the number
-         * of bytes to put in the output buffer)
+         * update the data 2 bytes each time, after finishing updating, do
+         * digest (giving the output buffer, offset, and the number of bytes to
+         * put in the output buffer)
          */
         UPDATE_BYTES_DIGEST_BUFFER {
             @Override
@@ -192,32 +209,32 @@
                 int len = md.digest(output, 0, output.length);
                 if (len != output.length) {
                     throw new RuntimeException(
-                        "ERROR" + ": digest length differs!");
+                            "ERROR" + ": digest length differs!");
                 }
                 return output;
             }
         },
 
         /*
-         * update the data 2 bytes each time, after finishing updating,
-         * do digest
+         * update the data 2 bytes each time, after finishing updating, do
+         * digest
          */
         UPDATE_BYTES_DIGEST {
             @Override
             public byte[] updateDigest(byte[] data, MessageDigest md) {
-                for (int i=0;i<data.length/2;i++){
-                    md.update(data,i*2,2);
+                for (int i = 0; i < data.length / 2; i++) {
+                    md.update(data, i * 2, 2);
                 }
                 return md.digest();
             }
         },
 
         /*
-         * update the data one by one using method update(byte[] input,
-         * int offset, int len) for the leading bytes (length is
-         * "data.length-LASTNBYTES"), then do digest (do a final
-         * update using the left LASTNBYTES bytes which is passed
-         * as a parameter for digest method then complete the digest)
+         * update the data one by one using method update(byte[] input, int
+         * offset, int len) for the leading bytes (length is
+         * "data.length-LASTNBYTES"), then do digest (do a final update using
+         * the left LASTNBYTES bytes which is passed as a parameter for digest
+         * method then complete the digest)
          */
         UPDATE_BUFFER_LEADING_DIGEST_REMAIN {
             @Override
@@ -233,11 +250,10 @@
         },
 
         /*
-         * update the data one by one using method update(byte input)
-         * for the leading bytes (length is "data.length-LASTNBYTES"),
-         * then do digest (do a final update using the left LASTNBYTES
-         * bytes which is passed as a parameter for digest method,
-         * then complete the digest)
+         * update the data one by one using method update(byte input) for the
+         * leading bytes (length is "data.length-LASTNBYTES"), then do digest
+         * (do a final update using the left LASTNBYTES bytes which is passed as
+         * a parameter for digest method, then complete the digest)
          */
         UPDATE_LEADING_DIGEST_REMAIN {
             @Override
@@ -253,9 +269,9 @@
         },
 
         /*
-         * update all the data at once as a ByteBuffer, then do digest
-         * (giving the output buffer, offset, and the number of bytes
-         * to put in the output buffer)
+         * update all the data at once as a ByteBuffer, then do digest (giving
+         * the output buffer, offset, and the number of bytes to put in the
+         * output buffer)
          */
         UPDATE_BYTE_BUFFER_DIGEST_BUFFER {
             @Override
@@ -266,7 +282,7 @@
                 int len = md.digest(output, 0, output.length);
                 if (len != output.length) {
                     throw new RuntimeException(
-                          "ERROR" + ": digest length differs!");
+                            "ERROR" + ": digest length differs!");
                 }
                 return output;
             }
@@ -282,10 +298,10 @@
         },
 
         /*
-         * update the leading bytes (length is "data.length-LASTNBYTES")
-         * at once as a ByteBuffer, then do digest (do a final update
-         * using the left LASTNBYTES bytes which is passed as a parameter
-         * for the digest method, then complete the digest)
+         * update the leading bytes (length is "data.length-LASTNBYTES") at once
+         * as a ByteBuffer, then do digest (do a final update using the left
+         * LASTNBYTES bytes which is passed as a parameter for the digest
+         * method, then complete the digest)
          */
         UPDATE_BYTE_BUFFER_LEADING_DIGEST_REMAIN {
             @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/MessageDigest/UnsupportedProvider.java	Tue May 31 22:41:56 2016 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+import java.security.Provider;
+import java.security.Security;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/*
+ * @test
+ * @bug 8156059
+ * @summary Test expected NoSuchAlgorithmException is thrown
+ *          if using SHA-3 with unsupported providers
+ */
+
+public class UnsupportedProvider {
+
+    public static void main(String args[]) {
+        String[] algorithms = { "SHA3-224", "SHA3-256", "SHA3-384",
+                "SHA3-512" };
+
+        for (Provider prov : Security.getProviders()) {
+            for (String algo : algorithms) {
+                try {
+                    String provName = prov.getName();
+                    MessageDigest md = MessageDigest.getInstance(algo, prov);
+
+                    if (!isSHA3Supported(provName)) {
+                        throw new RuntimeException("SHA-3 is not supported by "
+                                + provName + " provider, but expected "
+                                + "NoSuchAlgorithmException is not thrown");
+                    }
+                } catch (NoSuchAlgorithmException ex) {
+                    if (isSHA3Supported(prov.getName())) {
+                        throw new RuntimeException("SHA-3 should be supported "
+                                + "by " + prov.getName() + " provider, got"
+                                + " unexpected NoSuchAlgorithmException");
+                    }
+                    continue;
+                }
+            }
+        }
+    }
+
+    // Check if specific provider supports SHA-3 hash algorithms
+    static boolean isSHA3Supported(String provName) {
+        if ("SUN".equals(provName)) {
+            return true;
+        }
+        if ("OracleUcrypto".equals(provName)
+                && "SunOS".equals(System.getProperty("os.name"))
+                && System.getProperty("os.version").compareTo("5.12") >= 0) {
+            return true;
+        }
+        return false;
+    }
+}