8000415: Add support for SHA-3
authorvaleriep
Sat, 14 May 2016 03:44:30 +0000
changeset 37909 38b1efe33344
parent 37907 643c10927a1a
child 37910 30c530404433
8000415: Add support for SHA-3 Summary: Add SHA-3 support to SUN and OracleUcrypto provider Reviewed-by: ascarpino, jnimeh
jdk/make/mapfiles/libj2ucrypto/mapfile-vers
jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java
jdk/src/java.base/share/classes/sun/security/provider/SHA3.java
jdk/src/java.base/share/classes/sun/security/provider/SunEntries.java
jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java
jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/LibMDMech.java
jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigest.java
jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigestMD.java
jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.java
jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java
jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/libsoftcrypto.h
jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c
jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.h
jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCryptoMD.c
jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.c
jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.h
jdk/test/com/oracle/security/ucrypto/TestDigest.java
jdk/test/sun/security/provider/MessageDigest/Offsets.java
jdk/test/sun/security/provider/MessageDigest/TestSHAClone.java
--- a/jdk/make/mapfiles/libj2ucrypto/mapfile-vers	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/make/mapfiles/libj2ucrypto/mapfile-vers	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 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
@@ -30,28 +30,35 @@
                 JNI_OnLoad;
                 Java_com_oracle_security_ucrypto_UcryptoProvider_loadLibraries;
                 Java_com_oracle_security_ucrypto_UcryptoProvider_getMechList;
-		Java_com_oracle_security_ucrypto_NativeDigest_nativeInit;
+                Java_com_oracle_security_ucrypto_NativeDigestMD_nativeInit;
+                Java_com_oracle_security_ucrypto_NativeDigestMD_nativeUpdate;
+                Java_com_oracle_security_ucrypto_NativeDigestMD_nativeDigest;
+                Java_com_oracle_security_ucrypto_NativeDigestMD_nativeClone;
+                Java_com_oracle_security_ucrypto_NativeDigestMD_nativeFree;
+                Java_com_oracle_security_ucrypto_NativeDigest_nativeInit;
                 Java_com_oracle_security_ucrypto_NativeDigest_nativeUpdate;
                 Java_com_oracle_security_ucrypto_NativeDigest_nativeDigest;
-                Java_com_oracle_security_ucrypto_NativeDigest_nativeClone;
                 Java_com_oracle_security_ucrypto_NativeDigest_nativeFree;
-		Java_com_oracle_security_ucrypto_NativeCipher_nativeInit;
-		Java_com_oracle_security_ucrypto_NativeCipher_nativeUpdate;
-		Java_com_oracle_security_ucrypto_NativeCipher_nativeFinal;
+                Java_com_oracle_security_ucrypto_NativeCipher_nativeInit;
+                Java_com_oracle_security_ucrypto_NativeCipher_nativeUpdate;
+                Java_com_oracle_security_ucrypto_NativeCipher_nativeFinal;
                 Java_com_oracle_security_ucrypto_NativeKey_nativeFree;
                 Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit;
                 Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivateCrt_nativeInit;
                 Java_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeInit;
-		Java_com_oracle_security_ucrypto_NativeRSASignature_nativeInit;
-		Java_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII;
-		Java_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZJI;
-		Java_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal;
-		Java_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic;
-
+                Java_com_oracle_security_ucrypto_NativeRSASignature_nativeInit;
+                Java_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII;
+                Java_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZJI;
+                Java_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal;
+                Java_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic;
+                JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeInit;
+                JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeUpdate;
+                JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeDigest;
+                JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeClone;
+                JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeFree;
                 JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeInit;
                 JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeUpdate;
                 JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeDigest;
-                JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeClone;
                 JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeFree;
                 JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeInit;
                 JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeUpdate;
@@ -60,10 +67,10 @@
                 JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit;
                 JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivateCrt_nativeInit;
                 JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeInit;
-		JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeInit;
-		JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII;
-		JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZJI;
-		JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal;
+                JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeInit;
+                JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII;
+                JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZJI;
+                JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal;
                 JavaCritical_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic;
 
 	local:
--- a/jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -441,17 +441,89 @@
             (outOfs < 0) || ((out.length - outOfs) < len)) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        len += outOfs;
-        while (outOfs < len) {
-            long i = in[inOfs++];
-            out[outOfs++] = (byte)(i >> 56);
-            out[outOfs++] = (byte)(i >> 48);
-            out[outOfs++] = (byte)(i >> 40);
-            out[outOfs++] = (byte)(i >> 32);
-            out[outOfs++] = (byte)(i >> 24);
-            out[outOfs++] = (byte)(i >> 16);
-            out[outOfs++] = (byte)(i >>  8);
-            out[outOfs++] = (byte)(i      );
+        if (littleEndianUnaligned) {
+            outOfs += byteArrayOfs;
+            len += outOfs;
+            while (outOfs < len) {
+                unsafe.putLong(out, (long)outOfs, reverseBytes(in[inOfs++]));
+                outOfs += 8;
+            }
+        } else {
+            len += outOfs;
+            while (outOfs < len) {
+                long i = in[inOfs++];
+                out[outOfs++] = (byte)(i >> 56);
+                out[outOfs++] = (byte)(i >> 48);
+                out[outOfs++] = (byte)(i >> 40);
+                out[outOfs++] = (byte)(i >> 32);
+                out[outOfs++] = (byte)(i >> 24);
+                out[outOfs++] = (byte)(i >> 16);
+                out[outOfs++] = (byte)(i >>  8);
+                out[outOfs++] = (byte)(i      );
+            }
+        }
+    }
+
+    /**
+     * byte[] to long[] conversion, little endian byte order
+     */
+    static void b2lLittle(byte[] in, int inOfs, long[] out, int outOfs, int len) {
+        if ((inOfs < 0) || ((in.length - inOfs) < len) ||
+            ((outOfs < 0) || (out.length - outOfs) < len/8)) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        if (littleEndianUnaligned) {
+            inOfs += byteArrayOfs;
+            len += inOfs;
+            while (inOfs < len) {
+                out[outOfs++] = unsafe.getLong(in, (long)inOfs);
+                inOfs += 8;
+            }
+       } else {
+            len += inOfs;
+            while (inOfs < len) {
+                out[outOfs++] = ((in[inOfs    ] & 0xffL)
+                   | ((in[inOfs + 1] & 0xffL) <<  8)
+                   | ((in[inOfs + 2] & 0xffL) << 16)
+                   | ((in[inOfs + 3] & 0xffL) << 24)
+                   | ((in[inOfs + 4] & 0xffL) << 32)
+                   | ((in[inOfs + 5] & 0xffL) << 40)
+                   | ((in[inOfs + 6] & 0xffL) << 48)
+                   | ((in[inOfs + 7] & 0xffL) << 56));
+                inOfs += 8;
+            }
+        }
+    }
+
+
+    /**
+     * long[] to byte[] conversion, little endian byte order
+     */
+    static void l2bLittle(long[] in, int inOfs, byte[] out, int outOfs, int len) {
+        if ((inOfs < 0) || ((in.length - inOfs) < len/8) ||
+            (outOfs < 0) || ((out.length - outOfs) < len)) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        if (littleEndianUnaligned) {
+            outOfs += byteArrayOfs;
+            len += outOfs;
+            while (outOfs < len) {
+                unsafe.putLong(out, (long)outOfs, in[inOfs++]);
+                outOfs += 8;
+            }
+        } else {
+            len += outOfs;
+            while (outOfs < len) {
+                long i = in[inOfs++];
+                out[outOfs++] = (byte)(i      );
+                out[outOfs++] = (byte)(i >>  8);
+                out[outOfs++] = (byte)(i >> 16);
+                out[outOfs++] = (byte)(i >> 24);
+                out[outOfs++] = (byte)(i >> 32);
+                out[outOfs++] = (byte)(i >> 40);
+                out[outOfs++] = (byte)(i >> 48);
+                out[outOfs++] = (byte)(i >> 56);
+            }
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/provider/SHA3.java	Sat May 14 03:44:30 2016 +0000
@@ -0,0 +1,300 @@
+/*
+ * 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.  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 sun.security.provider;
+
+import static sun.security.provider.ByteArrayAccess.*;
+import java.nio.*;
+import java.util.*;
+import java.security.*;
+
+/**
+ * This class implements the Secure Hash Algorithm SHA-3 developed by
+ * the National Institute of Standards and Technology along with the
+ * National Security Agency as defined in FIPS PUB 202.
+ *
+ * <p>It implements java.security.MessageDigestSpi, and can be used
+ * through Java Cryptography Architecture (JCA), as a pluggable
+ * MessageDigest implementation.
+ *
+ * @since       9
+ * @author      Valerie Peng
+ */
+abstract class SHA3 extends DigestBase {
+
+    private static final int WIDTH = 200; // in bytes, e.g. 1600 bits
+    private static final int DM = 5; // dimension of lanes
+
+    private static final int NR = 24; // number of rounds
+
+    // precomputed round constants needed by the step mapping Iota
+    private static final long[] RC_CONSTANTS = {
+        0x01L, 0x8082L, 0x800000000000808aL,
+        0x8000000080008000L, 0x808bL, 0x80000001L,
+        0x8000000080008081L, 0x8000000000008009L, 0x8aL,
+        0x88L, 0x80008009L, 0x8000000aL,
+        0x8000808bL, 0x800000000000008bL, 0x8000000000008089L,
+        0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L,
+        0x800aL, 0x800000008000000aL, 0x8000000080008081L,
+        0x8000000000008080L, 0x80000001L, 0x8000000080008008L,
+    };
+
+    private byte[] state;
+
+    /**
+     * Creates a new SHA-3 object.
+     */
+    SHA3(String name, int digestLength) {
+        super(name, digestLength, (WIDTH - (2 * digestLength)));
+        implReset();
+    }
+
+    /**
+     * Core compression function. Processes blockSize bytes at a time
+     * and updates the state of this object.
+     */
+    void implCompress(byte[] b, int ofs) {
+        for (int i = 0; i < buffer.length; i++) {
+            state[i] ^= b[ofs++];
+        }
+        state = keccak(state);
+    }
+
+    /**
+     * Return the digest. Subclasses do not need to reset() themselves,
+     * DigestBase calls implReset() when necessary.
+     */
+    void implDigest(byte[] out, int ofs) {
+        int numOfPadding =
+            setPaddingBytes(buffer, (int)(bytesProcessed % buffer.length));
+        if (numOfPadding < 1) {
+            throw new ProviderException("Incorrect pad size: " + numOfPadding);
+        }
+        for (int i = 0; i < buffer.length; i++) {
+            state[i] ^= buffer[i];
+        }
+        state = keccak(state);
+        System.arraycopy(state, 0, out, ofs, engineGetDigestLength());
+    }
+
+    /**
+     * Resets the internal state to start a new hash.
+     */
+    void implReset() {
+        state = new byte[WIDTH];
+    }
+
+    /**
+     * Utility function for circular shift the specified long
+     * value to the left for n bits.
+     */
+    private static long circularShiftLeft(long lane, int n) {
+        return ((lane << n) | (lane >>> (64 - n)));
+    }
+
+    /**
+     * Utility function for padding the specified data based on the
+     * pad10*1 algorithm (section 5.1) and the 2-bit suffix "01" required
+     * for SHA-3 hash (section 6.1).
+     */
+    private static int setPaddingBytes(byte[] in, int len) {
+        if (len != in.length) {
+            // erase leftover values
+            Arrays.fill(in, len, in.length, (byte)0);
+            // directly store the padding bytes into the input
+            // as the specified buffer is allocated w/ size = rateR
+            in[len] |= (byte) 0x06;
+            in[in.length - 1] |= (byte) 0x80;
+        }
+        return (in.length - len);
+    }
+
+    /**
+     * Utility function for transforming the specified state from
+     * the byte array format into array of lanes as defined in
+     * section 3.1.2.
+     */
+    private static long[][] bytes2Lanes(byte[] s) {
+        if (s.length != WIDTH) {
+            throw new ProviderException("Error: incorrect input size " +
+                s.length);
+        }
+        // The conversion traverses along x-axis before y-axis. So, y is the
+        // first dimension and x is the second dimension.
+        long[][] s2 = new long[DM][DM];
+        int sOfs = 0;
+        for (int y = 0; y < DM; y++, sOfs += 40) {
+            b2lLittle(s, sOfs, s2[y], 0, 40);
+        }
+        return s2;
+    }
+
+    /**
+     * Utility function for transforming the specified arrays of
+     * lanes into a byte array as defined in section 3.1.3.
+     */
+    private static byte[] lanes2Bytes(long[][] m) {
+        byte[] s = new byte[WIDTH];
+        int sOfs = 0;
+        // The conversion traverses along x-axis before y-axis. So, y is the
+        // first dimension and x is the second dimension.
+        for (int y = 0; y < DM; y++, sOfs += 40) {
+            l2bLittle(m[y], 0, s, sOfs, 40);
+        }
+        return s;
+    }
+
+    /**
+     * Step mapping Theta as defined in section 3.2.1 .
+     */
+    private static long[][] smTheta(long[][] a) {
+        long[] c = new long[DM];
+        for (int i = 0; i < DM; i++) {
+            c[i] = a[0][i]^a[1][i]^a[2][i]^a[3][i]^a[4][i];
+        }
+        long[] d = new long[DM];
+        for (int i = 0; i < DM; i++) {
+            long c1 = c[(i + 4) % DM];
+            // left shift and wrap the leftmost bit into the rightmost bit
+            long c2 = circularShiftLeft(c[(i + 1) % DM], 1);
+            d[i] = c1^c2;
+        }
+        for (int y = 0; y < DM; y++) {
+            for (int x = 0; x < DM; x++) {
+                a[y][x] ^= d[x];
+            }
+        }
+        return a;
+    }
+
+    /**
+     * Step mapping Rho as defined in section 3.2.2.
+     */
+    private static long[][] smRho(long[][] a) {
+        long[][] a2 = new long[DM][DM];
+        a2[0][0] = a[0][0];
+        int xNext, yNext;
+        for (int t = 0, x = 1, y = 0; t <= 23; t++, x = xNext, y = yNext) {
+            int numberOfShift = ((t + 1)*(t + 2)/2) % 64;
+            a2[y][x] = circularShiftLeft(a[y][x], numberOfShift);
+            xNext = y;
+            yNext = (2 * x + 3 * y) % DM;
+        }
+        return a2;
+    }
+
+    /**
+     * Step mapping Pi as defined in section 3.2.3.
+     */
+    private static long[][] smPi(long[][] a) {
+        long[][] a2 = new long[DM][DM];
+        for (int y = 0; y < DM; y++) {
+            for (int x = 0; x < DM; x++) {
+                a2[y][x] = a[x][(x + 3 * y) % DM];
+            }
+        }
+        return a2;
+    }
+
+    /**
+     * Step mapping Chi as defined in section 3.2.4.
+     */
+    private static long[][] smChi(long[][] a) {
+        long[][] a2 = new long[DM][DM];
+        for (int y = 0; y < DM; y++) {
+            for (int x = 0; x < DM; x++) {
+                a2[y][x] = a[y][x] ^
+                    ((a[y][(x + 1) % DM] ^ 0xFFFFFFFFFFFFFFFFL) &
+                     a[y][(x + 2) % DM]);
+            }
+        }
+        return a2;
+    }
+
+    /**
+     * Step mapping Iota as defined in section 3.2.5.
+     *
+     * @return the processed state array
+     * @param state the state array to be processed
+     */
+    private static long[][] smIota(long[][] a, int rndIndex) {
+        a[0][0] ^= RC_CONSTANTS[rndIndex];
+        return a;
+    }
+
+    /**
+     * The function Keccak as defined in section 5.2 with
+     * rate r = 1600 and capacity c = (digest length x 2).
+     */
+    private static byte[] keccak(byte[] state) {
+        long[][] lanes = bytes2Lanes(state);
+        for (int ir = 0; ir < NR; ir++) {
+            lanes = smIota(smChi(smPi(smRho(smTheta(lanes)))), ir);
+        }
+        return lanes2Bytes(lanes);
+    }
+
+    public Object clone() throws CloneNotSupportedException {
+        SHA3 copy = (SHA3) super.clone();
+        copy.state = copy.state.clone();
+        return copy;
+    }
+
+    /**
+     * SHA3-224 implementation class.
+     */
+    public static final class SHA224 extends SHA3 {
+        public SHA224() {
+            super("SHA3-224", 28);
+        }
+    }
+
+    /**
+     * SHA3-256 implementation class.
+     */
+    public static final class SHA256 extends SHA3 {
+        public SHA256() {
+            super("SHA3-256", 32);
+        }
+    }
+
+    /**
+     * SHAs-384 implementation class.
+     */
+    public static final class SHA384 extends SHA3 {
+        public SHA384() {
+            super("SHA3-384", 48);
+        }
+    }
+
+    /**
+     * SHA3-512 implementation class.
+     */
+    public static final class SHA512 extends SHA3 {
+        public SHA512() {
+            super("SHA3-512", 64);
+        }
+    }
+}
--- a/jdk/src/java.base/share/classes/sun/security/provider/SunEntries.java	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/provider/SunEntries.java	Sat May 14 03:44:30 2016 +0000
@@ -211,6 +211,25 @@
         map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.6",
                 "SHA-512/256");
 
+        map.put("MessageDigest.SHA3-224", "sun.security.provider.SHA3$SHA224");
+        map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.7", "SHA3-224");
+        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.7",
+                "SHA3-224");
+
+        map.put("MessageDigest.SHA3-256", "sun.security.provider.SHA3$SHA256");
+        map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.8", "SHA3-256");
+        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.8",
+                "SHA3-256");
+        map.put("MessageDigest.SHA3-384", "sun.security.provider.SHA3$SHA384");
+        map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.9", "SHA3-384");
+        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.9",
+                "SHA3-384");
+        map.put("MessageDigest.SHA3-512", "sun.security.provider.SHA3$SHA512");
+        map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.10", "SHA3-512");
+        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.10",
+                "SHA3-512");
+
+
         /*
          * Algorithm Parameter Generator engines
          */
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -108,7 +108,7 @@
      * a hash for the certificate verify message is required.
      */
     HandshakeHash(boolean needCertificateVerify) {
-        clonesNeeded = needCertificateVerify ? 3 : 2;
+        clonesNeeded = needCertificateVerify ? 4 : 3;
     }
 
     void reserve(ByteBuffer input) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/LibMDMech.java	Sat May 14 03:44:30 2016 +0000
@@ -0,0 +1,66 @@
+/**
+ * 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.  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.oracle.security.ucrypto;
+
+/**
+ * Enum for representing the ucrypto mechanisms.
+ *
+ * @since 9
+ */
+public enum LibMDMech {
+
+    MD5(new ServiceDesc[]
+        { sd("MessageDigest", "MD5", "com.oracle.security.ucrypto.NativeDigestMD$MD5")
+        }),
+    SHA_1(new ServiceDesc[]
+        { sd("MessageDigest", "SHA", "com.oracle.security.ucrypto.NativeDigestMD$SHA1",
+             "SHA-1", "SHA1")
+        }),
+    SHA_256(new ServiceDesc[]
+        { sd("MessageDigest", "SHA-256", "com.oracle.security.ucrypto.NativeDigestMD$SHA256",
+             "2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1")
+        }),
+    SHA_384(new ServiceDesc[]
+        { sd("MessageDigest", "SHA-384", "com.oracle.security.ucrypto.NativeDigestMD$SHA384",
+             "2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2")
+        }),
+    SHA_512(new ServiceDesc[]
+        { sd("MessageDigest", "SHA-512", "com.oracle.security.ucrypto.NativeDigestMD$SHA512",
+             "2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3")
+        });
+
+    ServiceDesc[] serviceDescs;
+
+    private static ServiceDesc sd(String type, String algo, String cn, String... aliases) {
+        return new ServiceDesc(type, algo, cn, aliases);
+    }
+
+    LibMDMech(ServiceDesc[] serviceDescs) {
+        this.serviceDescs = serviceDescs;
+    }
+
+    public ServiceDesc[] getServiceDescriptions() { return serviceDescs; }
+}
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigest.java	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigest.java	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -33,23 +33,67 @@
 import java.security.*;
 
 /**
- * MessageDigest implementation class. This class currently supports
- * MD5, SHA1, SHA256, SHA384, and SHA512
+ * MessageDigest implementation class using native Ucrypto API.
+ * This class currently supports: MD5, SHA-2 (224, 256, 384, 512)
+ * and SHA-3 (224, 256, 384, 512) digests
  *
  * @since 9
  */
-public abstract class NativeDigest extends MessageDigestSpi
-        implements Cloneable {
+abstract class NativeDigest extends MessageDigestSpi {
 
-    private static final int MECH_MD5 = 1;
-    private static final int MECH_SHA1 = 2;
-    private static final int MECH_SHA256 = 3;
-    private static final int MECH_SHA224 = 4;
-    private static final int MECH_SHA384 = 5;
-    private static final int MECH_SHA512 = 6;
+    public static final class MD5 extends NativeDigest {
+        public MD5() {
+            super(UcryptoMech.CRYPTO_MD5, 16);
+        }
+    }
+    public static final class SHA1 extends NativeDigest {
+        public SHA1() {
+            super(UcryptoMech.CRYPTO_SHA1, 20);
+        }
+    }
+    public static final class SHA224 extends NativeDigest {
+        public SHA224() {
+            super(UcryptoMech.CRYPTO_SHA224, 28);
+        }
+    }
+    public static final class SHA256 extends NativeDigest {
+        public SHA256() {
+            super(UcryptoMech.CRYPTO_SHA256, 32);
+        }
+    }
+    public static final class SHA384 extends NativeDigest {
+        public SHA384() {
+            super(UcryptoMech.CRYPTO_SHA384, 48);
+        }
+    }
+    public static final class SHA512 extends NativeDigest {
+        public SHA512() {
+            super(UcryptoMech.CRYPTO_SHA512, 64);
+        }
+    }
+    public static final class SHA3_224 extends NativeDigest {
+        public SHA3_224() {
+            super(UcryptoMech.CRYPTO_SHA3_224, 28);
+        }
+    }
+    public static final class SHA3_256 extends NativeDigest {
+        public SHA3_256() {
+            super(UcryptoMech.CRYPTO_SHA3_256, 32);
+        }
+    }
+    public static final class SHA3_384 extends NativeDigest {
+        public SHA3_384() {
+            super(UcryptoMech.CRYPTO_SHA3_384, 48);
+        }
+    }
+    public static final class SHA3_512 extends NativeDigest {
+        public SHA3_512() {
+            super(UcryptoMech.CRYPTO_SHA3_512, 64);
+        }
+    }
 
     private final int digestLen;
-    private final int mech;
+    private final UcryptoMech mech;
 
     // field for ensuring native memory is freed
     private DigestContextRef pCtxt = null;
@@ -64,10 +108,9 @@
         // referents are GC'ed so we can do post-mortem processing
         private static Set<DigestContextRef> refList =
             new ConcurrentSkipListSet<DigestContextRef>();
-            //            Collections.synchronizedSortedSet(new TreeSet<DigestContextRef>());
 
         private final long id;
-        private final int mech;
+        private final UcryptoMech mech;
 
         private static void drainRefQueueBounded() {
             while (true) {
@@ -77,7 +120,7 @@
             }
         }
 
-        DigestContextRef(NativeDigest nc, long id, int mech) {
+        DigestContextRef(NativeDigest nc, long id, UcryptoMech mech) {
             super(nc, refQueue);
             this.id = id;
             this.mech = mech;
@@ -98,18 +141,22 @@
             refList.remove(this);
             try {
                 if (needFree) {
-                    UcryptoProvider.debug("Resource: free Digest Ctxt " + this.id);
-                    NativeDigest.nativeFree(mech, id);
-                } else UcryptoProvider.debug("Resource: stop tracking Digest Ctxt " + this.id);
+                    UcryptoProvider.debug("Resource: free Digest Ctxt " +
+                        this.id);
+                    NativeDigest.nativeFree(mech.value(), id);
+                } else {
+                    UcryptoProvider.debug("Resource: discard Digest Ctxt " +
+                        this.id);
+                }
             } finally {
                 this.clear();
             }
         }
     }
 
-    NativeDigest(int mech, int digestLen) {
+    NativeDigest(UcryptoMech mech, int digestLen) {
+        this.mech = mech;
         this.digestLen = digestLen;
-        this.mech = mech;
     }
 
     // see JCA spec
@@ -153,10 +200,10 @@
         }
 
         if (pCtxt == null) {
-            pCtxt = new DigestContextRef(this, nativeInit(mech), mech);
+            pCtxt = new DigestContextRef(this, nativeInit(mech.value()), mech);
         }
         try {
-            int status = nativeDigest(mech, pCtxt.id, out, ofs, digestLen);
+            int status = nativeDigest(mech.value(), pCtxt.id, out, ofs, digestLen);
             if (status != 0) {
                 throw new DigestException("Internal error: " + status);
             }
@@ -183,64 +230,24 @@
                 + len + ". in.length: " + in.length);
         }
         if (pCtxt == null) {
-            pCtxt = new DigestContextRef(this, nativeInit(mech), mech);
+            pCtxt = new DigestContextRef(this, nativeInit(mech.value()), mech);
         }
-        nativeUpdate(mech, pCtxt.id, in, ofs, len);
+        nativeUpdate(mech.value(), pCtxt.id, in, ofs, len);
     }
 
     /**
      * Clone this digest.
      */
     public synchronized Object clone() throws CloneNotSupportedException {
-        NativeDigest copy = (NativeDigest) super.clone();
-        // re-work the fields that cannot be copied over
-        if (pCtxt != null) {
-            copy.pCtxt = new DigestContextRef(this, nativeClone(mech, pCtxt.id), mech);
-        }
-        return copy;
+        throw new CloneNotSupportedException("Clone is not supported");
     }
 
     // return pointer to the context
-    protected static native long nativeInit(int mech);
-    // return status code; always 0
-    protected static native int nativeUpdate(int mech, long pCtxt, byte[] in, int ofs, int inLen);
+    protected static final native long nativeInit(int mech);
     // return status code; always 0
-    protected static native int nativeDigest(int mech, long pCtxt, byte[] out, int ofs, int digestLen);
-    // return pointer to the duplicated context
-    protected static native long nativeClone(int mech, long pCtxt);
+    protected static final native int nativeUpdate(int mech, long pCtxt, byte[] in, int ofs, int inLen);
+    // return status code; always 0
+    protected static final native int nativeDigest(int mech, long pCtxt, byte[] out, int ofs, int digestLen);
     // free the specified context
-    private native static void nativeFree(int mech, long id);
-
-
-    public static final class MD5 extends NativeDigest {
-        public MD5() {
-            super(MECH_MD5, 16);
-        }
-    }
-
-    public static final class SHA1 extends NativeDigest {
-        public SHA1() {
-            super(MECH_SHA1, 20);
-        }
-    }
-
-    public static final class SHA256 extends NativeDigest {
-        public SHA256() {
-            super(MECH_SHA256, 32);
-        }
-    }
-
-
-    public static final class SHA384 extends NativeDigest {
-        public SHA384() {
-            super(MECH_SHA384, 48);
-        }
-    }
-
-
-    public static final class SHA512 extends NativeDigest {
-        public SHA512() {
-            super(MECH_SHA512, 64);
-        }
-    }
+    private static final native void nativeFree(int mech, long id);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigestMD.java	Sat May 14 03:44:30 2016 +0000
@@ -0,0 +1,246 @@
+/*
+ * 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.  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.oracle.security.ucrypto;
+
+import java.lang.ref.*;
+
+import java.io.ByteArrayOutputStream;
+import java.util.*;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.security.*;
+
+/**
+ * MessageDigest implementation class for libMD API. This class currently supports
+ * MD5, SHA1, SHA256, SHA384, and SHA512
+ *
+ * @since 9
+ */
+public abstract class NativeDigestMD extends MessageDigestSpi
+        implements Cloneable {
+
+    private static final int MECH_MD5 = 1;
+    private static final int MECH_SHA1 = 2;
+    private static final int MECH_SHA256 = 3;
+    private static final int MECH_SHA224 = 4;
+    private static final int MECH_SHA384 = 5;
+    private static final int MECH_SHA512 = 6;
+
+    private final int digestLen;
+    private final int mech;
+
+    // field for ensuring native memory is freed
+    private DigestContextRef pCtxt = null;
+
+    private static class DigestContextRef extends PhantomReference<NativeDigestMD>
+        implements Comparable<DigestContextRef> {
+
+        private static ReferenceQueue<NativeDigestMD> refQueue =
+            new ReferenceQueue<NativeDigestMD>();
+
+        // Needed to keep these references from being GC'ed until when their
+        // referents are GC'ed so we can do post-mortem processing
+        private static Set<DigestContextRef> refList =
+            new ConcurrentSkipListSet<DigestContextRef>();
+            //            Collections.synchronizedSortedSet(new TreeSet<DigestContextRef>());
+
+        private final long id;
+        private final int mech;
+
+        private static void drainRefQueueBounded() {
+            while (true) {
+                DigestContextRef next = (DigestContextRef) refQueue.poll();
+                if (next == null) break;
+                next.dispose(true);
+            }
+        }
+
+        DigestContextRef(NativeDigestMD nc, long id, int mech) {
+            super(nc, refQueue);
+            this.id = id;
+            this.mech = mech;
+            refList.add(this);
+            UcryptoProvider.debug("Resource: track Digest Ctxt " + this.id);
+            drainRefQueueBounded();
+        }
+
+        public int compareTo(DigestContextRef other) {
+            if (this.id == other.id) {
+                return 0;
+            } else {
+                return (this.id < other.id) ? -1 : 1;
+            }
+        }
+
+        void dispose(boolean needFree) {
+            refList.remove(this);
+            try {
+                if (needFree) {
+                    UcryptoProvider.debug("Resource: free Digest Ctxt " + this.id);
+                    NativeDigestMD.nativeFree(mech, id);
+                } else UcryptoProvider.debug("Resource: stop tracking Digest Ctxt " + this.id);
+            } finally {
+                this.clear();
+            }
+        }
+    }
+
+    NativeDigestMD(int mech, int digestLen) {
+        this.digestLen = digestLen;
+        this.mech = mech;
+    }
+
+    // see JCA spec
+    protected int engineGetDigestLength() {
+        return digestLen;
+    }
+
+    // see JCA spec
+    protected synchronized void engineReset() {
+        if (pCtxt != null) {
+            pCtxt.dispose(true);
+            pCtxt = null;
+        }
+    }
+
+    // see JCA spec
+    protected synchronized byte[] engineDigest() {
+        byte[] digest = new byte[digestLen];
+        try {
+            int len = engineDigest(digest, 0, digestLen);
+            if (len != digestLen) {
+                throw new UcryptoException("Digest length mismatch." +
+                    " Len: " + len + ". digestLen: " + digestLen);
+            }
+            return digest;
+        } catch (DigestException de) {
+            throw new UcryptoException("Internal error", de);
+        }
+    }
+
+    // see JCA spec
+    protected synchronized int engineDigest(byte[] out, int ofs, int len)
+            throws DigestException {
+        if (len < digestLen) {
+            throw new DigestException("Output buffer must be at least " +
+                          digestLen + " bytes long. Got: " + len);
+        }
+        if ((ofs < 0) || (len < 0) || (ofs > out.length - len)) {
+            throw new DigestException("Buffer too short to store digest. " +
+                "ofs: " + ofs + ". len: " + len + ". out.length: " + out.length);
+        }
+
+        if (pCtxt == null) {
+            pCtxt = new DigestContextRef(this, nativeInit(mech), mech);
+        }
+        try {
+            int status = nativeDigest(mech, pCtxt.id, out, ofs, digestLen);
+            if (status != 0) {
+                throw new DigestException("Internal error: " + status);
+            }
+        } finally {
+            pCtxt.dispose(false);
+            pCtxt = null;
+        }
+        return digestLen;
+    }
+
+    // see JCA spec
+    protected synchronized void engineUpdate(byte in) {
+        byte[] temp = { in };
+        engineUpdate(temp, 0, 1);
+    }
+
+    // see JCA spec
+    protected synchronized void engineUpdate(byte[] in, int ofs, int len) {
+        if (len == 0) {
+            return;
+        }
+        if ((ofs < 0) || (len < 0) || (ofs > in.length - len)) {
+            throw new ArrayIndexOutOfBoundsException("ofs: " + ofs + ". len: "
+                + len + ". in.length: " + in.length);
+        }
+        if (pCtxt == null) {
+            pCtxt = new DigestContextRef(this, nativeInit(mech), mech);
+        }
+        nativeUpdate(mech, pCtxt.id, in, ofs, len);
+    }
+
+    /**
+     * Clone this digest.
+     */
+    public synchronized Object clone() throws CloneNotSupportedException {
+        NativeDigestMD copy = (NativeDigestMD) super.clone();
+        // re-work the fields that cannot be copied over
+        if (pCtxt != null) {
+            copy.pCtxt = new DigestContextRef(this, nativeClone(mech, pCtxt.id), mech);
+        }
+        return copy;
+    }
+
+    // return pointer to the context
+    protected static final native long nativeInit(int mech);
+    // return status code; always 0
+    protected static final native int nativeUpdate(int mech, long pCtxt, byte[] in, int ofs, int inLen);
+    // return status code; always 0
+    protected static final native int nativeDigest(int mech, long pCtxt, byte[] out, int ofs, int digestLen);
+    // return pointer to the duplicated context
+    protected static final native long nativeClone(int mech, long pCtxt);
+    // free the specified context
+    private static final native void nativeFree(int mech, long id);
+
+
+    public static final class MD5 extends NativeDigestMD {
+        public MD5() {
+            super(MECH_MD5, 16);
+        }
+    }
+
+    public static final class SHA1 extends NativeDigestMD {
+        public SHA1() {
+            super(MECH_SHA1, 20);
+        }
+    }
+
+    public static final class SHA256 extends NativeDigestMD {
+        public SHA256() {
+            super(MECH_SHA256, 32);
+        }
+    }
+
+
+    public static final class SHA384 extends NativeDigestMD {
+        public SHA384() {
+            super(MECH_SHA384, 48);
+        }
+    }
+
+
+    public static final class SHA512 extends NativeDigestMD {
+        public SHA512() {
+            super(MECH_SHA512, 64);
+        }
+    }
+}
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.java	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.java	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -25,8 +25,6 @@
 
 package com.oracle.security.ucrypto;
 
-import java.util.HashMap;
-
 /**
  * Enum for representing the ucrypto mechanisms.
  *
@@ -35,78 +33,126 @@
 // Check /usr/include/libsoftcrypto.h for updates
 public enum UcryptoMech {
 
-    CRYPTO_AES_ECB(1, new ServiceDesc[]
+    CRYPTO_AES_ECB(new ServiceDesc[]
         { sd("Cipher", "AES/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesEcbNoPadding"),
           sd("Cipher", "AES/ECB/PKCS5Padding", "com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesEcbPKCS5",
              "AES"),
-          sd("Cipher", "AES_128/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes128EcbNoPadding",
+          sd("Cipher", "AES_128/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesEcbNoPadding",
              "2.16.840.1.101.3.4.1.1", "OID.2.16.840.1.101.3.4.1.1"),
-          sd("Cipher", "AES_192/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes192EcbNoPadding",
+          sd("Cipher", "AES_192/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesEcbNoPadding",
              "2.16.840.1.101.3.4.1.21", "OID.2.16.840.1.101.3.4.1.21"),
-          sd("Cipher", "AES_256/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes256EcbNoPadding",
+          sd("Cipher", "AES_256/ECB/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesEcbNoPadding",
              "2.16.840.1.101.3.4.1.41", "OID.2.16.840.1.101.3.4.1.41")
         }),
-    CRYPTO_AES_CBC(2, new ServiceDesc[]
+    CRYPTO_AES_CBC(new ServiceDesc[]
         { sd("Cipher", "AES/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCbcNoPadding"),
           sd("Cipher", "AES/CBC/PKCS5Padding", "com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesCbcPKCS5"),
-          sd("Cipher", "AES_128/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes128CbcNoPadding",
+          sd("Cipher", "AES_128/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCbcNoPadding",
              "2.16.840.1.101.3.4.1.2", "OID.2.16.840.1.101.3.4.1.2"),
-          sd("Cipher", "AES_192/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes192CbcNoPadding",
+          sd("Cipher", "AES_192/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCbcNoPadding",
              "2.16.840.1.101.3.4.1.22", "OID.2.16.840.1.101.3.4.1.22"),
-          sd("Cipher", "AES_256/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$Aes256CbcNoPadding",
+          sd("Cipher", "AES_256/CBC/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCbcNoPadding",
              "2.16.840.1.101.3.4.1.42", "OID.2.16.840.1.101.3.4.1.42")
         }),
-    CRYPTO_AES_CBC_PAD(3, null), // No support from Solaris yet
-    CRYPTO_AES_CTR(4, new ServiceDesc[]
+//  CRYPTO_AES_CBC_PAD(null), // Support added since S11.1; however we still use CRYPTO_AES_CBC due to known bug
+    CRYPTO_AES_CTR(new ServiceDesc[]
         { sd("Cipher", "AES/CTR/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCtrNoPadding") }),
-    CRYPTO_AES_CCM(5, null), // Cannot support due to lack of Java API which corresponds to CK_AES_CCM_PARAMS
-    CRYPTO_AES_GCM(6, new ServiceDesc[]
+//  CRYPTO_AES_CCM(null), // Need Java API for CK_AES_CCM_PARAMS
+    CRYPTO_AES_GCM(new ServiceDesc[]
         { sd("Cipher", "AES/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$AesGcmNoPadding"),
-          sd("Cipher", "AES_128/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$Aes128GcmNoPadding",
+          sd("Cipher", "AES_128/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$AesGcmNoPadding",
              "2.16.840.1.101.3.4.1.6", "OID.2.16.840.1.101.3.4.1.6"),
-          sd("Cipher", "AES_192/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$Aes192GcmNoPadding",
+          sd("Cipher", "AES_192/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$AesGcmNoPadding",
              "2.16.840.1.101.3.4.1.26", "OID.2.16.840.1.101.3.4.1.26"),
-          sd("Cipher", "AES_256/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$Aes256GcmNoPadding",
+          sd("Cipher", "AES_256/GCM/NoPadding", "com.oracle.security.ucrypto.NativeGCMCipher$AesGcmNoPadding",
              "2.16.840.1.101.3.4.1.46", "OID.2.16.840.1.101.3.4.1.46")
         }),
-    CRYPTO_AES_GMAC(7, null), // No support from Solaris yet
-    CRYPTO_AES_CFB128(8, new ServiceDesc[]
+//  CRYPTO_AES_GMAC(null), // No support from Solaris
+    CRYPTO_AES_CFB128(new ServiceDesc[]
         { sd("Cipher", "AES/CFB128/NoPadding", "com.oracle.security.ucrypto.NativeCipher$AesCfb128NoPadding"),
-          sd("Cipher", "AES/CFB128/PKCS5Padding", "com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesCfb128PKCS5") }),
-    CRYPTO_RSA_PKCS(31, new ServiceDesc[]
+          sd("Cipher", "AES/CFB128/PKCS5Padding", "com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesCfb128PKCS5")
+        }),
+
+    CRYPTO_RSA_PKCS(new ServiceDesc[]
         { sd("Cipher", "RSA/ECB/PKCS1Padding", "com.oracle.security.ucrypto.NativeRSACipher$PKCS1Padding",
-             "RSA") }),
-    CRYPTO_RSA_X_509(32, new ServiceDesc[]
+             "RSA")
+        }),
+    CRYPTO_RSA_X_509(new ServiceDesc[]
         { sd("Cipher", "RSA/ECB/NoPadding", "com.oracle.security.ucrypto.NativeRSACipher$NoPadding") }),
-    CRYPTO_MD5_RSA_PKCS(33, new ServiceDesc[]
+    CRYPTO_MD5_RSA_PKCS(new ServiceDesc[]
         { sd("Signature", "MD5withRSA", "com.oracle.security.ucrypto.NativeRSASignature$MD5",
-             "1.2.840.113549.1.1.4", "OID.1.2.840.113549.1.1.4") }),
-    CRYPTO_SHA1_RSA_PKCS(34, new ServiceDesc[]
+             "1.2.840.113549.1.1.4", "OID.1.2.840.113549.1.1.4")
+        }),
+    CRYPTO_SHA1_RSA_PKCS(new ServiceDesc[]
         { sd("Signature", "SHA1withRSA", "com.oracle.security.ucrypto.NativeRSASignature$SHA1",
              "1.2.840.113549.1.1.5", "OID.1.2.840.113549.1.1.5",
-             "1.3.14.3.2.29") }),
-    CRYPTO_SHA256_RSA_PKCS(35, new ServiceDesc[]
+             "1.3.14.3.2.29")
+        }),
+    CRYPTO_SHA256_RSA_PKCS(new ServiceDesc[]
         { sd("Signature", "SHA256withRSA", "com.oracle.security.ucrypto.NativeRSASignature$SHA256",
-             "1.2.840.113549.1.1.11", "OID.1.2.840.113549.1.1.11") }),
-    CRYPTO_SHA384_RSA_PKCS(36, new ServiceDesc[]
+             "1.2.840.113549.1.1.11", "OID.1.2.840.113549.1.1.11")
+        }),
+    CRYPTO_SHA384_RSA_PKCS(new ServiceDesc[]
         { sd("Signature", "SHA384withRSA", "com.oracle.security.ucrypto.NativeRSASignature$SHA384",
-             "1.2.840.113549.1.1.12", "OID.1.2.840.113549.1.1.12") }),
-    CRYPTO_SHA512_RSA_PKCS(37, new ServiceDesc[]
+             "1.2.840.113549.1.1.12", "OID.1.2.840.113549.1.1.12")
+        }),
+    CRYPTO_SHA512_RSA_PKCS(new ServiceDesc[]
         { sd("Signature", "SHA512withRSA", "com.oracle.security.ucrypto.NativeRSASignature$SHA512",
-             "1.2.840.113549.1.1.13", "OID.1.2.840.113549.1.1.13") });
+             "1.2.840.113549.1.1.13", "OID.1.2.840.113549.1.1.13")
+        }),
 
-    private final int mech;
+    CRYPTO_MD5(new ServiceDesc[]
+        { sd("MessageDigest", "MD5", "com.oracle.security.ucrypto.NativeDigest$MD5") }),
+    CRYPTO_SHA1(new ServiceDesc[]
+        { sd("MessageDigest", "SHA", "com.oracle.security.ucrypto.NativeDigest$SHA1", "SHA-1", "SHA1") }),
+    CRYPTO_SHA224(new ServiceDesc[]
+        { sd("MessageDigest", "SHA-224", "com.oracle.security.ucrypto.NativeDigest$SHA224",
+             "2.16.840.1.101.3.4.2.4", "OID.2.16.840.1.101.3.4.2.4")
+    }),
+    CRYPTO_SHA256(new ServiceDesc[]
+        { sd("MessageDigest", "SHA-256", "com.oracle.security.ucrypto.NativeDigest$SHA256",
+             "2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1")
+    }),
+    CRYPTO_SHA384(new ServiceDesc[]
+        { sd("MessageDigest", "SHA-384", "com.oracle.security.ucrypto.NativeDigest$SHA384",
+             "2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2")
+    }),
+    CRYPTO_SHA512(new ServiceDesc[]
+        { sd("MessageDigest", "SHA-512", "com.oracle.security.ucrypto.NativeDigest$SHA512",
+             "2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3")
+    }),
+    CRYPTO_SHA3_224(new ServiceDesc[]
+        { sd("MessageDigest", "SHA3-224", "com.oracle.security.ucrypto.NativeDigest$SHA3_224",
+             "2.16.840.1.101.3.4.2.7", "OID.2.16.840.1.101.3.4.2.7")
+    }),
+    CRYPTO_SHA3_256(new ServiceDesc[]
+        { sd("MessageDigest", "SHA3-256", "com.oracle.security.ucrypto.NativeDigest$SHA3_256",
+             "2.16.840.1.101.3.4.2.8", "OID.2.16.840.1.101.3.4.2.8")
+    }),
+    CRYPTO_SHA3_384(new ServiceDesc[]
+        { sd("MessageDigest", "SHA3-384", "com.oracle.security.ucrypto.NativeDigest$SHA3_384",
+             "2.16.840.1.101.3.4.2.9", "OID.2.16.840.1.101.3.4.2.9")
+    }),
+    CRYPTO_SHA3_512(new ServiceDesc[]
+        { sd("MessageDigest", "SHA3-512", "com.oracle.security.ucrypto.NativeDigest$SHA3_512",
+             "2.16.840.1.101.3.4.2.10", "OID.2.16.840.1.101.3.4.2.10")
+    });
+
+    private int mech = 0;
     private final ServiceDesc[] serviceDescs;
 
     private static ServiceDesc sd(String type, String algo, String cn, String... aliases) {
         return new ServiceDesc(type, algo, cn, aliases);
     }
 
-    UcryptoMech(int mech, ServiceDesc[] serviceDescs) {
-        this.mech = mech;
+    UcryptoMech(ServiceDesc[] serviceDescs) {
         this.serviceDescs = serviceDescs;
     }
 
+    public void setValue(int nativeMechValue) {
+        this.mech = nativeMechValue;
+    }
+
     public int value() { return mech; }
     public ServiceDesc[] getServiceDescriptions() { return serviceDescs; }
 }
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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,6 +27,7 @@
 
 import java.io.IOException;
 import java.io.File;
+import java.lang.reflect.Constructor;
 import java.util.*;
 import java.security.*;
 
@@ -74,48 +75,52 @@
             if (provProp != null) {
                 boolean[] result = loadLibraries();
                 if (result.length == 2) {
-                    if (result[0]) { // successfully loaded libmd
-                        provProp.put("MessageDigest.MD5",
-                            sd("MessageDigest", "MD5",
-                               "com.oracle.security.ucrypto.NativeDigest$MD5"));
-                        provProp.put("MessageDigest.SHA",
-                            sd("MessageDigest", "SHA",
-                               "com.oracle.security.ucrypto.NativeDigest$SHA1",
-                               "SHA-1", "SHA1"));
-                        provProp.put("MessageDigest.SHA-256",
-                            sd("MessageDigest", "SHA-256",
-                               "com.oracle.security.ucrypto.NativeDigest$SHA256",
-                               "2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1"));
-
-                        provProp.put("MessageDigest.SHA-384",
-                            sd("MessageDigest", "SHA-384",
-                               "com.oracle.security.ucrypto.NativeDigest$SHA384",
-                               "2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2"));
-
-                        provProp.put("MessageDigest.SHA-512",
-                            sd("MessageDigest", "SHA-512",
-                               "com.oracle.security.ucrypto.NativeDigest$SHA512",
-                               "2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3"));
-                    };
-                    if (result[1]) { // successfully loaded libsoftcrypto
+                    // true when libsoftcrypto or libucrypto(S12) has been successfully loaded
+                    if (result[1]) {
                         String supportedMechs = getMechList();
                         debug("Prov: supported mechs = " + supportedMechs);
-                        for (UcryptoMech m : UcryptoMech.values()) {
-                            if (supportedMechs.indexOf(m.name() + ",") != -1) {
+                        StringTokenizer st = new StringTokenizer(supportedMechs, ":,;");
+                        // format: numOfSupportedMechs:[mechName,mechValue;]+
+                        // skip the first one which is numberOfSupportedMechs
+                        st.nextToken();
+                        while (st.hasMoreTokens()) {
+                            String mechName = st.nextToken();
+                            int nativeMechVal = Integer.parseInt(st.nextToken());
+                            try {
+                                UcryptoMech m = Enum.valueOf(UcryptoMech.class, mechName);
+                                m.setValue(nativeMechVal);
                                 ServiceDesc[] services = m.getServiceDescriptions();
-                                // skip unsupported UcryptoMech
-                                if (services == null || services.length == 0) continue;
+                                // defined in UcryptoMech as unsupported
+                                if (services == null || services.length == 0) {
+                                    debug("Skip Unsupported Algorithm: " + mechName);
+                                    continue;
+                                }
                                 for (int p = 0; p < services.length; p++) {
                                     ServiceDesc entry = services[p];
                                     provProp.put(entry.getType() + "." + entry.getAlgorithm(),
                                                  entry);
                                 }
+                            } catch (IllegalArgumentException iae) {
+                                // not defined in UcryptoMech
+                                debug("Skip Unrecognized Algorithm: " + mechName);
                             }
                         }
                         // NOTE: GCM support is only available since jdk 7
                         provProp.put("AlgorithmParameters.GCM",
-                                     sd("AlgorithmParameters", "GCM", "com.oracle.security.ucrypto.GCMParameters"));
+                                     sd("AlgorithmParameters", "GCM",
+                                        "com.oracle.security.ucrypto.GCMParameters"));
                     }
+                    // true when libmd is needed and has been successfully loaded
+                    if (result[0]) {
+                        for (LibMDMech m : LibMDMech.values()) {
+                            ServiceDesc[] services = m.getServiceDescriptions();
+                            for (ServiceDesc entry : services) {
+                                String sKey = entry.getType() + "." + entry.getAlgorithm();
+                                //  only register if none has been registered
+                                provProp.putIfAbsent(sKey, entry);
+                            }
+                        }
+                    };
                 } else {
                     debug("Prov: unexpected ucrypto library loading error, got " + result.length);
                 }
@@ -138,6 +143,7 @@
                   sd.getAliases(), null);
         }
 
+        @SuppressWarnings("deprecation")
         @Override
         public Object newInstance(Object ctrParamObj)
             throws NoSuchAlgorithmException {
@@ -152,53 +158,19 @@
                     int keySize = -1;
                     if (algo.charAt(3) == '_') {
                         keySize = Integer.parseInt(algo.substring(4, 7))/8;
-                        algo = algo.substring(0, 3) + algo.substring(7);
-                    }
-                    if (algo.equals("AES/ECB/NoPadding")) {
-                        return new NativeCipher.AesEcbNoPadding(keySize);
-                    } else if (algo.equals("AES/ECB/PKCS5Padding")) {
-                        return new NativeCipherWithJavaPadding.AesEcbPKCS5();
-                    } else if (algo.equals("AES/CBC/NoPadding")) {
-                        return new NativeCipher.AesCbcNoPadding(keySize);
-                    } else if (algo.equals("AES/CBC/PKCS5Padding")) {
-                        return new NativeCipherWithJavaPadding.AesCbcPKCS5();
-                    } else if (algo.equals("AES/CTR/NoPadding")) {
-                        return new NativeCipher.AesCtrNoPadding();
-                    } else if (algo.equals("AES/GCM/NoPadding")) {
-                        return new NativeGCMCipher.AesGcmNoPadding(keySize);
-                    } else if (algo.equals("AES/CFB128/NoPadding")) {
-                        return new NativeCipher.AesCfb128NoPadding();
-                    } else if (algo.equals("AES/CFB128/PKCS5Padding")) {
-                        return new NativeCipherWithJavaPadding.AesCfb128PKCS5();
-                    } else if (algo.equals("RSA/ECB/NoPadding")) {
-                        return new NativeRSACipher.NoPadding();
-                    } else if (algo.equals("RSA/ECB/PKCS1Padding")) {
-                        return new NativeRSACipher.PKCS1Padding();
                     }
-                } else if (type.equals("Signature")) {
-                    if (algo.equals("SHA1withRSA")) {
-                        return new NativeRSASignature.SHA1();
-                    } else if (algo.equals("SHA256withRSA")) {
-                        return new NativeRSASignature.SHA256();
-                    } else if (algo.equals("SHA384withRSA")) {
-                        return new NativeRSASignature.SHA384();
-                    } else if (algo.equals("SHA512withRSA")) {
-                        return new NativeRSASignature.SHA512();
-                    } else if (algo.equals("MD5withRSA")) {
-                        return new NativeRSASignature.MD5();
+                    String implClass = getClassName();
+                    Class<?> clz = Class.forName(implClass);
+                    if (keySize != -1) {
+                        Constructor<?> ctr = clz.getConstructor(int.class);
+                        return ctr.newInstance(keySize);
+                    } else {
+                        return clz.newInstance();
                     }
-                } else if (type.equals("MessageDigest")) {
-                    if (algo.equals("SHA")) {
-                        return new NativeDigest.SHA1();
-                    } else if (algo.equals("SHA-256")) {
-                        return new NativeDigest.SHA256();
-                    } else if (algo.equals("SHA-384")) {
-                        return new NativeDigest.SHA384();
-                    } else if (algo.equals("SHA-512")) {
-                        return new NativeDigest.SHA512();
-                    } else if (algo.equals("MD5")) {
-                        return new NativeDigest.MD5();
-                    }
+                } else if (type.equals("Signature") || type.equals("MessageDigest")) {
+                    String implClass = getClassName();
+                    Class<?> clz = Class.forName(implClass);
+                    return clz.newInstance();
                 } else if (type.equals("AlgorithmParameters")) {
                     if (algo.equals("GCM")) {
                         return new GCMParameters();
--- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/libsoftcrypto.h	Fri May 13 18:58:32 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- */
-
-#ifndef _LIBSOFTCRYPTO_H
-#define _LIBSOFTCRYPTO_H
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <strings.h>
-
-typedef enum ucrypto_mech {
-    CRYPTO_AES_ECB = 1,
-    CRYPTO_AES_CBC,
-    CRYPTO_AES_CBC_PAD,
-    CRYPTO_AES_CTR,
-    CRYPTO_AES_CCM,
-    CRYPTO_AES_GCM,
-    CRYPTO_AES_GMAC,
-    CRYPTO_AES_CFB128,
-    CRYPTO_RSA_PKCS = 31,
-    CRYPTO_RSA_X_509,
-    CRYPTO_MD5_RSA_PKCS,
-    CRYPTO_SHA1_RSA_PKCS,
-    CRYPTO_SHA256_RSA_PKCS,
-    CRYPTO_SHA384_RSA_PKCS,
-    CRYPTO_SHA512_RSA_PKCS
-} ucrypto_mech_t;
-
-typedef struct crypto_ctx {
-    void *cc_provider;
-    uint_t    cc_session;
-    void            *cc_provider_private;    /* owned by provider */
-    void            *cc_framework_private;    /* owned by framework */
-    uint32_t        cc_flags;        /* flags */
-    void            *cc_opstate;        /* state */
-} crypto_ctx_t;
-
-extern int ucrypto_encrypt_init(crypto_ctx_t *context,
-    ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len,
-    void *iv, size_t iv_len);
-
-extern int ucrypto_encrypt_update(crypto_ctx_t *context, uchar_t *in,
-    size_t in_len, uchar_t *out, size_t *out_len);
-
-extern int ucrypto_encrypt_final(crypto_ctx_t *context, uchar_t *out,
-    size_t *out_len);
-
-/* Encrypt atomic */
-extern int ucrypto_encrypt(ucrypto_mech_t mech_type, uchar_t *key_str,
-    size_t key_len, void *iv, size_t iv_len, uchar_t *in,
-    size_t in_len, uchar_t *out, size_t *out_len);
-
-/* Decrypt multi-part */
-extern int ucrypto_decrypt_init(crypto_ctx_t *context,
-    ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len,
-    void *iv, size_t iv_len);
-
-extern int ucrypto_decrypt_update(crypto_ctx_t *context, uchar_t *in,
-    size_t in_len, uchar_t *out, size_t *out_len);
-
-extern int ucrypto_decrypt_final(crypto_ctx_t *context, uchar_t *out,
-    size_t *out_len);
-
-/* Decrypt atomic */
-extern int ucrypto_decrypt(ucrypto_mech_t mech_type, uchar_t *key_str,
-    size_t key_len, void *iv, size_t iv_len, uchar_t *in,
-    size_t in_len, uchar_t *out, size_t *out_len);
-
-/* Sign multi-part */
-extern int ucrypto_sign_init(crypto_ctx_t *context, ucrypto_mech_t mech_type,
-    uchar_t *key_str, size_t key_len, void *iv, size_t iv_len);
-
-extern int ucrypto_sign_update(crypto_ctx_t *context,
-    uchar_t *data_str, size_t data_len);
-
-extern int ucrypto_sign_final(crypto_ctx_t *context,
-    uchar_t *sig_str, size_t *sig_len);
-
-/* Sign atomic */
-extern int ucrypto_sign(ucrypto_mech_t mech_type,
-    uchar_t *key_str, size_t key_len, void *iv, size_t iv_len,
-    uchar_t *data_str, size_t data_len, uchar_t *sig_str, size_t *sig_len);
-
-/* Verify multi-part */
-extern int ucrypto_verify_init(crypto_ctx_t *context, ucrypto_mech_t mech_type,
-    uchar_t *key_str, size_t key_len, void *iv, size_t iv_len);
-
-extern int ucrypto_verify_update(crypto_ctx_t *context,
-    uchar_t *data_str, size_t data_len);
-
-extern int ucrypto_verify_final(crypto_ctx_t *context,
-    uchar_t *sig_str, size_t *sig_len);
-
-/* Verify atomic */
-extern int ucrypto_verify(ucrypto_mech_t mech_type,
-    uchar_t *key_str, size_t key_len, void *iv, size_t iv_len,
-    uchar_t *data_str, size_t data_len, uchar_t *sig, size_t *sig_len);
-
-extern int ucrypto_get_mechlist(char *str);
-
-extern const char *ucrypto_id2mech(ucrypto_mech_t mech_type);
-
-extern ucrypto_mech_t ucrypto_mech2id(const char *str);
-
-extern int ucrypto_version();
-
-typedef struct CK_AES_CTR_PARAMS {
-    ulong_t    ulCounterBits;
-    uint8_t cb[16];
-} CK_AES_CTR_PARAMS;
-
-typedef struct CK_AES_GCM_PARAMS {
-    uchar_t *pIv;
-    ulong_t ulIvLen;
-    ulong_t ulIvBits;
-    uchar_t *pAAD;
-    ulong_t ulAADLen;
-    ulong_t ulTagBits;
-} CK_AES_GCM_PARAMS;
-
-typedef struct crypto_object_attribute {
-    uint64_t    oa_type;    /* attribute type */
-    caddr_t            oa_value;    /* attribute value */
-    ssize_t            oa_value_len;    /* length of attribute value */
-} crypto_object_attribute_t;
-
-/* Attribute types to use for passing a RSA public key or a private key. */
-#define    SUN_CKA_MODULUS            0x00000120
-#define    SUN_CKA_MODULUS_BITS        0x00000121
-#define    SUN_CKA_PUBLIC_EXPONENT        0x00000122
-#define    SUN_CKA_PRIVATE_EXPONENT    0x00000123
-#define    SUN_CKA_PRIME_1            0x00000124
-#define    SUN_CKA_PRIME_2            0x00000125
-#define    SUN_CKA_EXPONENT_1        0x00000126
-#define    SUN_CKA_EXPONENT_2        0x00000127
-#define    SUN_CKA_COEFFICIENT        0x00000128
-#define    SUN_CKA_PRIME            0x00000130
-#define    SUN_CKA_SUBPRIME        0x00000131
-#define    SUN_CKA_BASE            0x00000132
-
-#define    CKK_EC            0x00000003
-#define    CKK_GENERIC_SECRET    0x00000010
-#define    CKK_RC4            0x00000012
-#define    CKK_AES            0x0000001F
-#define    CKK_DES            0x00000013
-#define    CKK_DES2        0x00000014
-#define    CKK_DES3        0x00000015
-
-#define    CKO_PUBLIC_KEY        0x00000002
-#define    CKO_PRIVATE_KEY        0x00000003
-#define    CKA_CLASS        0x00000000
-#define    CKA_VALUE        0x00000011
-#define    CKA_KEY_TYPE        0x00000100
-#define    CKA_VALUE_LEN        0x00000161
-#define    CKA_EC_PARAMS        0x00000180
-#define    CKA_EC_POINT        0x00000181
-
-#endif /* _LIBSOFTCRYPTO_H */
--- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -35,6 +35,22 @@
 /*
  * Dumps out byte array in hex with and name and length info
  */
+void printError(char* header, int mech, int rv) {
+  if (mech != -1) {
+    printf("%s, mech = %d, rv = 0x%0x\n", header, mech, rv);
+  } else {
+    printf("%s, rv = 0x%0x\n", header, rv);
+  }
+  if (*ftab->ucryptoStrerror != NULL) {
+    char * reason = (*ftab->ucryptoStrerror)(rv);
+    printf("\tcause = %s\n", reason);
+    free(reason);
+  }
+}
+
+/*
+ * Dumps out byte array in hex with and name and length info
+ */
 void printBytes(char* header, unsigned char* bytes, int len) {
   int i;
 
@@ -60,6 +76,16 @@
   (*env)->DeleteLocalRef(env, jExClass);
 }
 
+/*
+ * De-allocates all memory associated with crypto_ctx_t
+ */
+void freeContext(crypto_ctx_t *context) {
+  if (ftab->ucryptoFreeContext != NULL) {
+    (*ftab->ucryptoFreeContext)(context);
+  }
+  free(context);
+}
+
 JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) {
     return JNI_VERSION_1_4;
 }
@@ -203,10 +229,10 @@
   }
   if (encrypt) {
     rv = (*ftab->ucryptoEncryptInit)(context, mech, jKey, (size_t)jKeyLen, iv, ivLen);
-    if (rv != 0 && DEBUG) printf("ucryptoEncryptInit: ret = 0x%x\n", rv);
+    if (rv != 0 && DEBUG) printError("ucryptoEncryptInit", mech, rv);
   } else {
     rv =(*ftab->ucryptoDecryptInit)(context, mech, jKey, (size_t)jKeyLen, iv, ivLen);
-    if (rv != 0 && DEBUG) printf("ucryptoDecryptInit: ret = 0x%x\n", rv);
+    if (rv != 0 && DEBUG) printError("ucryptoDecryptInit", mech, rv);
   }
 
   if (iv != jIv) {
@@ -234,15 +260,15 @@
   }
   if (encrypt) {
     rv = (*ftab->ucryptoEncryptUpdate)(context, (unsigned char*)(bufIn+inOfs), (size_t)inLen, (unsigned char*)(bufOut+outOfs), &outLength);
-    if (rv != 0) {
-      if (DEBUG) printf("ucryptoEncryptUpdate: ret = 0x%x\n", rv);
+    if (rv) {
+      if (DEBUG) printError("ucryptoEncryptUpdate", -1, rv);
     } else {
       *outLen = (int)outLength;
     }
   } else {
     rv = (*ftab->ucryptoDecryptUpdate)(context, (unsigned char*)(bufIn+inOfs), (size_t)inLen, (unsigned char*)(bufOut+outOfs), &outLength);
-    if (rv != 0) {
-      if (DEBUG) printf("ucryptoDecryptUpdate: ret = 0x%x\n", rv);
+    if (rv) {
+      if (DEBUG) printError("ucryptoDecryptUpdate", -1, rv);
     } else {
       if (DEBUG) printBytes("BufOut=", (unsigned char*)(bufOut+outOfs), outLength);
       *outLen = (int)outLength;
@@ -263,16 +289,16 @@
   if (DEBUG) printf("CipherFinal: OutOfs %i, outLen %i\n", outOfs, *outLen);
   if (encrypt) {
     rv = (*ftab->ucryptoEncryptFinal)(context, (unsigned char*)(bufOut+outOfs), &outLength);
-    if (rv != 0) {
-      if (DEBUG) printf("ucryptoDecryptFinal: ret = 0x%x\n", rv);
+    if (rv) {
+      if (DEBUG) printError("ucryptoDecryptFinal", -1, rv);
     } else {
       if (DEBUG) printBytes("BufOut=", (unsigned char*)(bufOut+outOfs), outLength);
       *outLen = (int)outLength;
     }
   } else {
     rv = (*ftab->ucryptoDecryptFinal)(context, (unsigned char*)(bufOut+outOfs), &outLength);
-    if (rv != 0) {
-      if (DEBUG) printf("ucryptoDecryptFinal: ret = 0x%x\n", rv);
+    if (rv) {
+      if (DEBUG) printError("ucryptoDecryptFinal", -1, rv);
     } else {
       if (DEBUG) printBytes("BufOut=", (unsigned char*)(bufOut+outOfs), outLength);
       *outLen = (int)outLength;
@@ -285,102 +311,61 @@
 // SPECIAL ENTRIES FOR JVM JNI-BYPASSING OPTIMIZATION
 ////////////////////////////////////////////////////////
 jlong JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeInit(jint mech) {
-  void *pContext = NULL;
+  crypto_ctx_t *context = NULL;
+  int rv;
 
-  switch (mech) {
-  case com_oracle_security_ucrypto_NativeDigest_MECH_SHA1:
-    pContext = (SHA1_CTX *) malloc(sizeof(SHA1_CTX));
-    if (pContext != NULL) {
-      (*ftab->sha1Init)((SHA1_CTX *)pContext);
-    }
-    break;
-  case com_oracle_security_ucrypto_NativeDigest_MECH_MD5:
-    pContext = (MD5_CTX *) malloc(sizeof(MD5_CTX));
-    if (pContext != NULL) {
-      (*ftab->md5Init)((MD5_CTX *)pContext);
+  context = malloc(sizeof(crypto_ctx_t));
+  if (context != NULL) {
+    rv = (*ftab->ucryptoDigestInit)(context, (ucrypto_mech_t) mech, NULL, 0);
+    if (rv) {
+      freeContext(context);
+      if (DEBUG) printError("ucryptoDigestInit", mech, rv);
+      return 0L;
     }
-    break;
-  case com_oracle_security_ucrypto_NativeDigest_MECH_SHA256:
-    pContext = (SHA2_CTX *) malloc(sizeof(SHA2_CTX));
-    if (pContext != NULL) {
-      (*ftab->sha2Init)(SHA256, (SHA2_CTX *)pContext);
-    }
-    break;
-  case com_oracle_security_ucrypto_NativeDigest_MECH_SHA384:
-    pContext = (SHA2_CTX *) malloc(sizeof(SHA2_CTX));
-    if (pContext != NULL) {
-      (*ftab->sha2Init)(SHA384, (SHA2_CTX *)pContext);
-    }
-    break;
-  case com_oracle_security_ucrypto_NativeDigest_MECH_SHA512:
-    pContext = (SHA2_CTX *) malloc(sizeof(SHA2_CTX));
-    if (pContext != NULL) {
-      (*ftab->sha2Init)(SHA512, (SHA2_CTX *)pContext);
-    }
-    break;
-  default:
-    if (DEBUG) printf("ERROR: Unsupported mech %i\n", mech);
   }
-  return (jlong) pContext;
+  return (jlong) context;
 }
 
 jint JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeUpdate
   (jint mech, jlong pContext, int notUsed, unsigned char* in, jint ofs, jint len) {
-  if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_SHA1) {
-    (*ftab->sha1Update)((SHA1_CTX*)pContext, (unsigned char*)(in+ofs), len);
-  } else if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_MD5) {
-    (*ftab->md5Update)((MD5_CTX*)pContext, (unsigned char*)(in+ofs), len);
-  } else { // SHA-2 family
-    (*ftab->sha2Update)((SHA2_CTX*)pContext, (unsigned char*)(in+ofs), len);
+  crypto_ctx_t *context;
+  jint rv = 0;
+
+  context = (crypto_ctx_t *) pContext;
+  rv = (*ftab->ucryptoDigestUpdate)(context, (const unsigned char*)(in + ofs),
+                                    (size_t) len);
+
+  if (rv) {
+    freeContext(context);
+    if (DEBUG) printError("ucryptoDigestUpdate", mech, rv);
   }
-  return 0;
+
+  return -rv; // use negative value to indicate error
 }
 
-// Do digest and free the context immediately
 jint JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeDigest
   (jint mech, jlong pContext, int notUsed, unsigned char* out, jint ofs, jint digestLen) {
-
-  if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_SHA1) {
-    (*ftab->sha1Final)((unsigned char*)(out + ofs), (SHA1_CTX *)pContext);
-    free((SHA1_CTX *)pContext);
-  } else if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_MD5) {
-    (*ftab->md5Final)((unsigned char*)(out + ofs), (MD5_CTX *)pContext);
-    free((MD5_CTX *)pContext);
-  } else { // SHA-2 family
-    (*ftab->sha2Final)((unsigned char*)(out + ofs), (SHA2_CTX *)pContext);
-    free((SHA2_CTX *)pContext);
-  }
-  return 0;
-}
+  crypto_ctx_t *context;
+  jint rv = 0;
+  size_t digest_len = digestLen;
 
-jlong JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeClone
-  (jint mech, jlong pContext) {
-  void *copy = NULL;
-  size_t len = 0;
+  context = (crypto_ctx_t *) pContext;
+  rv = (*ftab->ucryptoDigestFinal)(context, (unsigned char*)(out + ofs),
+                                   &digest_len);
+  if (rv) {
+    freeContext(context);
+    if (DEBUG) printError("ucryptoDigestFinal", mech, rv);
+  }
 
-  if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_SHA1) {
-    len = sizeof(SHA1_CTX);
-  } else if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_MD5) {
-    len = sizeof(MD5_CTX);
-  } else { // SHA-2 family
-    len = sizeof(SHA2_CTX);
-  }
-  copy = (void*) malloc(len);
-  if (copy != NULL) {
-    bcopy((void *)pContext, copy, len);
-  }
-  return (jlong) copy;
+  return -rv; // use negative value to indicate error
 }
 
 void JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeFree
   (jint mech, jlong pContext) {
-  if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_SHA1) {
-    free((SHA1_CTX*) pContext);
-  } else if (mech == com_oracle_security_ucrypto_NativeDigest_MECH_MD5) {
-    free((MD5_CTX*) pContext);
-  } else { // SHA-2 family
-    free((SHA2_CTX*) pContext);
-  }
+  crypto_ctx_t *context;
+
+  context = (crypto_ctx_t *) pContext;
+  freeContext(context);
 }
 
 // AES
@@ -395,7 +380,7 @@
     rv = CipherInit(context, encrypt, (ucrypto_mech_t) mech, bufKey, keyLen,
                     bufIv, ivLen, tagLen, bufAad, aadLen);
     if (rv) {
-      free(context);
+      freeContext(context);
       return 0L;
     }
   }
@@ -417,8 +402,7 @@
   context = (crypto_ctx_t *) pContext;
   rv = CipherUpdate(context, encrypt, (unsigned char*)bufIn, inOfs, inLen, (unsigned char*)bufOut, outOfs, &outLen);
   if (rv) {
-    free(context);
-    context = 0;
+    freeContext(context);
     return -rv; // use negative value to indicate error!
   }
 
@@ -443,7 +427,7 @@
     outLen = 0;
   }
   rv = CipherFinal(context, encrypt, bufOut, outOfs, &outLen);
-  free(context);
+  freeContext(context);
   if (rv) {
      return -rv; // use negative value to indicate error!
   }
@@ -451,8 +435,6 @@
   return outLen;
 }
 
-
-
 /*
  * Class:     com_oracle_security_ucrypto_NativeDigest
  * Method:    nativeInit
@@ -475,13 +457,15 @@
 JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeUpdate
   (JNIEnv *env, jclass jcls, jint mech, jlong pContext, jbyteArray jIn, jint jOfs, jint jLen) {
   unsigned char *bufIn;
+  jint rv = 0;
+
 
   bufIn = (unsigned char *) getBytes(env, jIn, jOfs, jLen);
   if (!(*env)->ExceptionCheck(env)) {
-    JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeUpdate(mech, pContext, jLen, bufIn, 0, jLen);
+    rv = JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeUpdate(mech, pContext, jLen, bufIn, 0, jLen);
     free(bufIn);
   }
-  return 0;
+  return rv;
 }
 
 /*
@@ -492,6 +476,7 @@
 JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeDigest
   (JNIEnv *env, jclass jcls, jint mech, jlong pContext, jbyteArray jOut, jint jOutOfs, jint digestLen) {
   unsigned char *bufOut;
+  jint rv = 0;
 
   bufOut = (unsigned char *) malloc(digestLen);
   if (bufOut == NULL) {
@@ -499,21 +484,12 @@
     return 0;
   }
 
-  JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeDigest(mech, pContext, digestLen, bufOut, 0, digestLen);
-
-  (*env)->SetByteArrayRegion(env, jOut, jOutOfs, digestLen, (jbyte *) bufOut);
+  rv = JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeDigest(mech, pContext, digestLen, bufOut, 0, digestLen);
+  if (rv == 0) {
+      (*env)->SetByteArrayRegion(env, jOut, jOutOfs, digestLen, (jbyte *) bufOut);
+  }
   free(bufOut);
-  return 0;
-}
-
-/*
- * Class:     com_oracle_security_ucrypto_NativeDigest
- * Method:    nativeClone
- * Signature: (IJ)J
- */
-JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeClone
-  (JNIEnv *env, jclass jcls, jint mech, jlong pContext) {
-  return JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeClone(mech, pContext);
+  return rv;
 }
 
 /*
@@ -582,7 +558,7 @@
 
 cleanup:
   if ((result == 0L) && (context != NULL)) {
-    free(context);
+    freeContext(context);
   }
   if (bufKey != NULL) {
     (*env)->ReleaseByteArrayElements(env, jKey, (jbyte *)bufKey, 0);
@@ -626,7 +602,7 @@
 
   rv = CipherUpdate(context, encrypt, bufIn, 0, inLen, bufOut, 0, &outLen);
   if (rv) {
-    free(context);
+    freeContext(context);
     free(bufIn);
     free(bufOut);
     return -rv;
@@ -683,6 +659,7 @@
   return rc;
 }
 
+
 /*
  * Class:     com_oracle_security_ucrypto_NativeKey
  * Method:    nativeFree
@@ -984,9 +961,9 @@
   }
 
   if (DEBUG) {
-    printf("RSAPublicKey Init: keyValue=%ld, keyLen=2\n", pKey);
-    printBytes("RSA PublicKey mod: ", (unsigned char*) mod, modLen);
-    printBytes("RSA PublicKey pubExp: ", (unsigned char*) pub, pubLen);
+    printf("RSAPublicKey.nativeInit: keyValue=%ld, keyLen=2\n", pKey);
+    printBytes("\tmod: ", (unsigned char*) mod, modLen);
+    printBytes("\tpubExp: ", (unsigned char*) pub, pubLen);
   }
 
   pKey[0].oa_type = SUN_CKA_MODULUS;
@@ -1062,7 +1039,7 @@
   if (DEBUG) {
     printf("SignatureInit: context=%ld, mech=%d, sign=%d, keyValue=%ld, keyLength=%d\n",
            context, mech, sign, pKey, keyLength);
-    printf("SignatureInit, ret =>  0x%x\n", rv);
+    printError("SignatureInit", mech, rv);
   }
   return rv;
 }
@@ -1083,7 +1060,7 @@
     pKey = (uchar_t *) jKey;
     rv = SignatureInit(context, mech, sign, pKey, (size_t)keyLength);
     if (rv) {
-      free(context);
+      freeContext(context);
       return 0L;
     }
   }
@@ -1105,7 +1082,7 @@
   pKey = (uchar_t *) jKey;
   rv = SignatureInit(context, mech, sign, pKey, (size_t)keyLength);
   if (rv) {
-    free(context);
+    freeContext(context);
     throwUCExceptionUsingRV(env, rv);
     return 0L;
   }
@@ -1125,7 +1102,7 @@
 
   context = (crypto_ctx_t *) pCtxt;
   if (DEBUG) {
-    printf("Signature update: context=%ld, sign=%d, jIn=%ld, jInOfs=%d, jInLen=%d\n",
+    printf("NativeRSASignature.nativeUpdate: context=%ld, sign=%d, jIn=%ld, jInOfs=%d, jInLen=%d\n",
            context, sign, jIn, jInOfs, jInLen);
   }
   if (sign) {
@@ -1133,9 +1110,9 @@
   } else {
     rv = (*ftab->ucryptoVerifyUpdate)(context, (uchar_t *) (jIn + jInOfs), (size_t) jInLen);
   }
-  if (DEBUG) printf("Signature update, ret =>  0x%x\n", rv);
   if (rv) {
-    free(context);
+    freeContext(context);
+    if (DEBUG) printError("NativeRSASignature.nativeUpdate", -1, rv);
     return -rv; // use negative value to indicate error!
   }
 
@@ -1194,9 +1171,9 @@
 
   context = (crypto_ctx_t *) pCtxt;
   if (DEBUG) {
-      printf("Signature final: context=%ld, sign=%d, bufSig=%ld, sigOfs=%d, sigLen=%d\n",
+      printf("NativeRSASignature.nativeFinal: context=%ld, sign=%d, bufSig=%ld, sigOfs=%d, sigLen=%d\n",
              context, sign, bufSig, sigOfs, jSigLen);
-      printBytes("Before Final: SigBytes ", (unsigned char*) (bufSig + sigOfs), jSigLen);
+      printBytes("Before: SigBytes ", (unsigned char*) (bufSig + sigOfs), jSigLen);
   }
   if (sign) {
     rv = (*ftab->ucryptoSignFinal)(context, (uchar_t *) (bufSig + sigOfs), &sigLength);
@@ -1204,18 +1181,17 @@
     rv = (*ftab->ucryptoVerifyFinal)(context, (uchar_t *) (bufSig + sigOfs), &sigLength);
   }
 
-  if (DEBUG) {
-    printf("Signature nativeFinal, ret =>  0x%x\n", rv);
-    if (sigLength != jSigLen) {
-      printf("SIG actual output len=%d\n", sigLength);
+  freeContext(context);
+  if (rv) {
+    if (DEBUG) {
+      printError("NativeRSASignature.nativeFinal", -1, rv);
+      if (sigLength != jSigLen) {
+        printf("NativeRSASignature.nativeFinal out sig len=%d\n", sigLength);
+      }
+      if (sign) {
+        printBytes("After: SigBytes ", (unsigned char*) (bufSig + sigOfs), jSigLen);
+      }
     }
-    if (sign) {
-      printBytes("After nativeFinal: ", (unsigned char*) (bufSig + sigOfs), jSigLen);
-    }
-  }
-
-  free(context);
-  if (rv) {
     return -rv;
   } else return 0;
 }
@@ -1273,10 +1249,10 @@
 
   pKey = (uchar_t *) keyValue;
   if (DEBUG) {
-    printf("Cipher nativeAtomic: mech=%d, encrypt=%d, pKey=%ld, keyLength=%d\n",
+    printf("NativeRSACipher.nativeAtomic: mech=%d, encrypt=%d, pKey=%ld, keyLength=%d\n",
            mech, encrypt, pKey, keyLength);
-    printBytes("Before nativeAtomic: in: ", (unsigned char*) bufIn, jInLen);
-    printBytes("Before nativeAtomic: out: ", (unsigned char*) (bufOut + jOutOfs), jOutLen);
+    printBytes("Before: in  = ", (unsigned char*) bufIn, jInLen);
+    printBytes("Before: out = ", (unsigned char*) (bufOut + jOutOfs), jOutLen);
   }
 
   if (encrypt) {
@@ -1289,11 +1265,11 @@
       (uchar_t *)(bufOut + jOutOfs), &outLength);
   }
   if (DEBUG) {
-    printf("Cipher nativeAtomic, ret =>  0x%x\n", rv);
+    printError("NativeRSACipher.nativeAtomic", mech, rv);
     if (outLength != jOutLen) {
-      printf("CIP actual output len=%d\n", outLength);
+      printf("NativeRSACipher.nativeAtomic out len=%d\n", outLength);
     }
-    printBytes("After nativeAtomic: ", (unsigned char*) (bufOut + jOutOfs), outLength);
+    printBytes("After: ", (unsigned char*) (bufOut + jOutOfs), outLength);
   }
 
   if (rv) {
--- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.h	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.h	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -29,18 +29,18 @@
 extern "C" {
 #endif
 
-#undef com_oracle_security_ucrypto_NativeDigest_MECH_MD5
-#define com_oracle_security_ucrypto_NativeDigest_MECH_MD5 1L
-#undef com_oracle_security_ucrypto_NativeDigest_MECH_SHA1
-#define com_oracle_security_ucrypto_NativeDigest_MECH_SHA1 2L
-#undef com_oracle_security_ucrypto_NativeDigest_MECH_SHA256
-#define com_oracle_security_ucrypto_NativeDigest_MECH_SHA256 3L
-#undef com_oracle_security_ucrypto_NativeDigest_MECH_SHA224
-#define com_oracle_security_ucrypto_NativeDigest_MECH_SHA224 4L
-#undef com_oracle_security_ucrypto_NativeDigest_MECH_SHA384
-#define com_oracle_security_ucrypto_NativeDigest_MECH_SHA384 5L
-#undef com_oracle_security_ucrypto_NativeDigest_MECH_SHA512
-#define com_oracle_security_ucrypto_NativeDigest_MECH_SHA512 6L
+#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5
+#define com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5 1L
+#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1
+#define com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1 2L
+#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA256
+#define com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA256 3L
+#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA224
+#define com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA224 4L
+#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA384
+#define com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA384 5L
+#undef com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA512
+#define com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA512 6L
 
 #define DEBUG 0
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCryptoMD.c	Sat May 14 03:44:30 2016 +0000
@@ -0,0 +1,214 @@
+/*
+ * 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.  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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <jni.h>
+#include "jni_util.h"
+#include <libsoftcrypto.h>
+#include "nativeCrypto.h"
+#include "nativeFunc.h"
+
+
+extern void throwOutOfMemoryError(JNIEnv *env, const char *msg);
+extern jbyte* getBytes(JNIEnv *env, jbyteArray bytes, int offset, int len);
+
+///////////////////////////////////////////////////////
+// SPECIAL ENTRIES FOR JVM JNI-BYPASSING OPTIMIZATION
+////////////////////////////////////////////////////////
+jlong JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeInit(jint mech) {
+  void *pContext = NULL;
+
+  switch (mech) {
+  case com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1:
+    pContext = malloc(sizeof(SHA1_CTX));
+    if (pContext != NULL) {
+      (*ftab->sha1Init)((SHA1_CTX *)pContext);
+    }
+    break;
+  case com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5:
+    pContext = malloc(sizeof(MD5_CTX));
+    if (pContext != NULL) {
+      (*ftab->md5Init)((MD5_CTX *)pContext);
+    }
+    break;
+  case com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA256:
+    pContext = malloc(sizeof(SHA2_CTX));
+    if (pContext != NULL) {
+      (*ftab->sha2Init)(SHA256, (SHA2_CTX *)pContext);
+    }
+    break;
+  case com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA384:
+    pContext = malloc(sizeof(SHA2_CTX));
+    if (pContext != NULL) {
+      (*ftab->sha2Init)(SHA384, (SHA2_CTX *)pContext);
+    }
+    break;
+  case com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA512:
+    pContext = malloc(sizeof(SHA2_CTX));
+    if (pContext != NULL) {
+      (*ftab->sha2Init)(SHA512, (SHA2_CTX *)pContext);
+    }
+    break;
+  default:
+    if (DEBUG) printf("ERROR: Unsupported mech %i\n", mech);
+  }
+  return (jlong) pContext;
+}
+
+jint JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeUpdate
+  (jint mech, jlong pContext, int notUsed, unsigned char* in, jint ofs, jint len) {
+  if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1) {
+    (*ftab->sha1Update)((SHA1_CTX*)pContext, (unsigned char*)(in+ofs), len);
+  } else if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5) {
+    (*ftab->md5Update)((MD5_CTX*)pContext, (unsigned char*)(in+ofs), len);
+  } else { // SHA-2 family
+    (*ftab->sha2Update)((SHA2_CTX*)pContext, (unsigned char*)(in+ofs), len);
+  }
+  return 0;
+}
+
+// Do digest and free the context immediately
+jint JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeDigest
+  (jint mech, jlong pContext, int notUsed, unsigned char* out, jint ofs, jint digestLen) {
+
+  if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1) {
+    (*ftab->sha1Final)((unsigned char*)(out + ofs), (SHA1_CTX *)pContext);
+    free((SHA1_CTX *)pContext);
+  } else if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5) {
+    (*ftab->md5Final)((unsigned char*)(out + ofs), (MD5_CTX *)pContext);
+    free((MD5_CTX *)pContext);
+  } else { // SHA-2 family
+    (*ftab->sha2Final)((unsigned char*)(out + ofs), (SHA2_CTX *)pContext);
+    free((SHA2_CTX *)pContext);
+  }
+  return 0;
+}
+
+jlong JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeClone
+  (jint mech, jlong pContext) {
+  void *copy = NULL;
+  size_t len = 0;
+
+  if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1) {
+    len = sizeof(SHA1_CTX);
+  } else if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5) {
+    len = sizeof(MD5_CTX);
+  } else { // SHA-2 family
+    len = sizeof(SHA2_CTX);
+  }
+  copy = malloc(len);
+  if (copy != NULL) {
+    bcopy((void *)pContext, copy, len);
+  }
+  return (jlong) copy;
+}
+
+void JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeFree
+  (jint mech, jlong pContext) {
+  if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_SHA1) {
+    free((SHA1_CTX*) pContext);
+  } else if (mech == com_oracle_security_ucrypto_NativeDigestMD_MECH_MD5) {
+    free((MD5_CTX*) pContext);
+  } else { // SHA-2 family
+    free((SHA2_CTX*) pContext);
+  }
+}
+
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeDigestMD
+ * Method:    nativeInit
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeDigestMD_nativeInit
+  (JNIEnv *env, jclass jcls, jint mech) {
+  jlong result = JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeInit(mech);
+  if (result == NULL) {
+     throwOutOfMemoryError(env, NULL);
+  }
+  return result;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeDigestMD
+ * Method:    nativeUpdate
+ * Signature: (IJ[BII)I
+ */
+JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeDigestMD_nativeUpdate
+  (JNIEnv *env, jclass jcls, jint mech, jlong pContext, jbyteArray jIn, jint jOfs, jint jLen) {
+  unsigned char *bufIn;
+
+  bufIn = (unsigned char *) getBytes(env, jIn, jOfs, jLen);
+  if (!(*env)->ExceptionCheck(env)) {
+    JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeUpdate(mech, pContext, jLen, bufIn, 0, jLen);
+    free(bufIn);
+  }
+  return 0;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeDigestMD
+ * Method:    nativeDigest
+ * Signature: (IJ[BII)I
+ */
+JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeDigestMD_nativeDigest
+  (JNIEnv *env, jclass jcls, jint mech, jlong pContext, jbyteArray jOut, jint jOutOfs, jint digestLen) {
+  unsigned char *bufOut;
+
+  bufOut = (unsigned char *) malloc(digestLen);
+  if (bufOut == NULL) {
+    throwOutOfMemoryError(env, NULL);
+    return 0;
+  }
+
+  JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeDigest(mech, pContext, digestLen, bufOut, 0, digestLen);
+
+  (*env)->SetByteArrayRegion(env, jOut, jOutOfs, digestLen, (jbyte *) bufOut);
+  free(bufOut);
+  return 0;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeDigestMD
+ * Method:    nativeClone
+ * Signature: (IJ)J
+ */
+JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeDigestMD_nativeClone
+  (JNIEnv *env, jclass jcls, jint mech, jlong pContext) {
+  return JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeClone(mech, pContext);
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeDigestMD
+ * Method:    nativeFree
+ * Signature: (IJ)V
+ */
+JNIEXPORT void JNICALL Java_com_oracle_security_ucrypto_NativeDigestMD_nativeFree
+  (JNIEnv *env, jclass jcls, jint mech, jlong pContext) {
+  JavaCritical_com_oracle_security_ucrypto_NativeDigestMD_nativeFree(mech, pContext);
+}
+
--- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.c	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.c	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -42,21 +42,33 @@
 static const char SHA2_FINAL[]                   = "SHA2Final";
 static const char UCRYPTO_VERSION[]              = "ucrypto_version";
 static const char UCRYPTO_GET_MECHLIST[]         = "ucrypto_get_mechlist";
+
 static const char UCRYPTO_ENCRYPT_INIT[]         = "ucrypto_encrypt_init";
 static const char UCRYPTO_ENCRYPT_UPDATE[]       = "ucrypto_encrypt_update";
 static const char UCRYPTO_ENCRYPT_FINAL[]        = "ucrypto_encrypt_final";
 static const char UCRYPTO_ENCRYPT[]              = "ucrypto_encrypt";
+
 static const char UCRYPTO_DECRYPT_INIT[]         = "ucrypto_decrypt_init";
 static const char UCRYPTO_DECRYPT_UPDATE[]       = "ucrypto_decrypt_update";
 static const char UCRYPTO_DECRYPT_FINAL[]        = "ucrypto_decrypt_final";
 static const char UCRYPTO_DECRYPT[]              = "ucrypto_decrypt";
+
 static const char UCRYPTO_SIGN_INIT[]            = "ucrypto_sign_init";
 static const char UCRYPTO_SIGN_UPDATE[]          = "ucrypto_sign_update";
 static const char UCRYPTO_SIGN_FINAL[]           = "ucrypto_sign_final";
+
 static const char UCRYPTO_VERIFY_INIT[]          = "ucrypto_verify_init";
 static const char UCRYPTO_VERIFY_UPDATE[]        = "ucrypto_verify_update";
 static const char UCRYPTO_VERIFY_FINAL[]         = "ucrypto_verify_final";
 
+static const char UCRYPTO_DIGEST_INIT[]          = "ucrypto_digest_init";
+static const char UCRYPTO_DIGEST_UPDATE[]        = "ucrypto_digest_update";
+static const char UCRYPTO_DIGEST_FINAL[]         = "ucrypto_digest_final";
+
+static const char UCRYPTO_FREE_CONTEXT[]         = "ucrypto_free_context";
+
+static const char UCRYPTO_STRERROR[]             = "ucrypto_strerror";
+
 /**
  * Initialize native T4 crypto function pointers
  */
@@ -73,28 +85,6 @@
     return NULL;
   }
 
-  lib = dlopen("libmd.so", RTLD_NOW);
-  if (lib != NULL) {
-    ftab->md5Init = (MD5INIT_FN_PTR) dlsym(lib, MD5_INIT);
-    ftab->md5Update = (MD5UPDATE_FN_PTR) dlsym(lib, MD5_UPDATE);
-    ftab->md5Final = (MD5FINAL_FN_PTR) dlsym(lib, MD5_FINAL);
-    ftab->sha1Init = (SHA1INIT_FN_PTR) dlsym(lib, SHA1_INIT);
-    ftab->sha1Update = (SHA1UPDATE_FN_PTR) dlsym(lib, SHA1_UPDATE);
-    ftab->sha1Final = (SHA1FINAL_FN_PTR) dlsym(lib, SHA1_FINAL);
-    ftab->sha2Init = (SHA2INIT_FN_PTR) dlsym(lib, SHA2_INIT);
-    ftab->sha2Update = (SHA2UPDATE_FN_PTR) dlsym(lib, SHA2_UPDATE);
-    ftab->sha2Final = (SHA2FINAL_FN_PTR) dlsym(lib, SHA2_FINAL);
-    if (ftab->md5Init != NULL && ftab->md5Update != NULL &&
-        ftab->md5Final != NULL && ftab->sha1Init != NULL &&
-        ftab->sha1Update != NULL && ftab->sha1Final != NULL &&
-        ftab->sha2Init != NULL && ftab->sha2Update != NULL &&
-        ftab->sha2Final != NULL) {
-      buf[0] = JNI_TRUE;
-    } else {
-      dlclose(lib);
-    }
-  }
-
   lib = dlopen("libsoftcrypto.so", RTLD_NOW);
   if (lib != NULL) {
     // These APIs aren't available for v0 lib on Solaris 10
@@ -102,7 +92,6 @@
       dlsym(lib, UCRYPTO_VERSION);
     ftab->ucryptoGetMechList = (UCRYPTO_GET_MECHLIST_FN_PTR)
       dlsym(lib, UCRYPTO_GET_MECHLIST);
-    //??
     ftab->ucryptoSignInit = (UCRYPTO_SIGN_INIT_FN_PTR)
       dlsym(lib, UCRYPTO_SIGN_INIT);
     ftab->ucryptoSignUpdate = (UCRYPTO_SIGN_UPDATE_FN_PTR)
@@ -116,6 +105,21 @@
     ftab->ucryptoVerifyFinal = (UCRYPTO_VERIFY_FINAL_FN_PTR)
       dlsym(lib, UCRYPTO_VERIFY_FINAL);
 
+    // These APS are added starting S12
+    ftab->ucryptoDigestInit = (UCRYPTO_DIGEST_INIT_FN_PTR)
+      dlsym(lib, UCRYPTO_DIGEST_INIT);
+    ftab->ucryptoDigestUpdate = (UCRYPTO_DIGEST_UPDATE_FN_PTR)
+      dlsym(lib, UCRYPTO_DIGEST_UPDATE);
+    ftab->ucryptoDigestFinal = (UCRYPTO_DIGEST_FINAL_FN_PTR)
+      dlsym(lib, UCRYPTO_DIGEST_FINAL);
+
+    ftab->ucryptoFreeContext = (UCRYPTO_FREE_CONTEXT_FN_PTR)
+      dlsym(lib, UCRYPTO_FREE_CONTEXT);
+
+    ftab->ucryptoStrerror = (UCRYPTO_STRERROR_FN_PTR)
+      dlsym(lib, UCRYPTO_STRERROR);
+
+
     // These should be avilable for all libsoftcrypto libs
     ftab->ucryptoEncryptInit = (UCRYPTO_ENCRYPT_INIT_FN_PTR)
       dlsym(lib, UCRYPTO_ENCRYPT_INIT);
@@ -147,6 +151,34 @@
     } else {
       dlclose(lib);
     }
+
+    // proceed with libmd when libucrypto does not support digest operations
+    if (ftab->ucryptoDigestInit == NULL ||
+        ftab->ucryptoDigestUpdate == NULL ||
+        ftab->ucryptoDigestFinal == NULL) {
+
+      lib = dlopen("libmd.so", RTLD_NOW);
+      if (lib != NULL) {
+        ftab->md5Init = (MD5INIT_FN_PTR) dlsym(lib, MD5_INIT);
+        ftab->md5Update = (MD5UPDATE_FN_PTR) dlsym(lib, MD5_UPDATE);
+        ftab->md5Final = (MD5FINAL_FN_PTR) dlsym(lib, MD5_FINAL);
+        ftab->sha1Init = (SHA1INIT_FN_PTR) dlsym(lib, SHA1_INIT);
+        ftab->sha1Update = (SHA1UPDATE_FN_PTR) dlsym(lib, SHA1_UPDATE);
+        ftab->sha1Final = (SHA1FINAL_FN_PTR) dlsym(lib, SHA1_FINAL);
+        ftab->sha2Init = (SHA2INIT_FN_PTR) dlsym(lib, SHA2_INIT);
+        ftab->sha2Update = (SHA2UPDATE_FN_PTR) dlsym(lib, SHA2_UPDATE);
+        ftab->sha2Final = (SHA2FINAL_FN_PTR) dlsym(lib, SHA2_FINAL);
+        if (ftab->md5Init != NULL && ftab->md5Update != NULL &&
+            ftab->md5Final != NULL && ftab->sha1Init != NULL &&
+            ftab->sha1Update != NULL && ftab->sha1Final != NULL &&
+            ftab->sha2Init != NULL && ftab->sha2Update != NULL &&
+            ftab->sha2Final != NULL) {
+          buf[0] = JNI_TRUE;
+        } else {
+          dlclose(lib);
+        }
+      }
+    }
   }
 
   return buf;
--- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.h	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.h	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -69,15 +69,12 @@
      (crypto_ctx_t *context, ucrypto_mech_t mech_type,
       uchar_t *key_str, size_t key_len,
       void *iv, size_t iv_len);
-
 typedef int (*UCRYPTO_ENCRYPT_UPDATE_FN_PTR)
      (crypto_ctx_t *context, uchar_t *in,
       size_t in_len, uchar_t *out, size_t *out_len);
-
 typedef int (*UCRYPTO_ENCRYPT_FINAL_FN_PTR)
      (crypto_ctx_t *context, uchar_t *out,
       size_t *out_len);
-
 typedef int (*UCRYPTO_ENCRYPT_FN_PTR)
      (ucrypto_mech_t mech_type, uchar_t *key_str,
       size_t key_len, void *iv, size_t iv_len, uchar_t *in,
@@ -87,15 +84,12 @@
      (crypto_ctx_t *context,
       ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len,
       void *iv, size_t iv_len);
-
 typedef int (*UCRYPTO_DECRYPT_UPDATE_FN_PTR)
      (crypto_ctx_t *context, uchar_t *in,
       size_t in_len, uchar_t *out, size_t *out_len);
-
 typedef int (*UCRYPTO_DECRYPT_FINAL_FN_PTR)
      (crypto_ctx_t *context, uchar_t *out,
       size_t *out_len);
-
 typedef int (*UCRYPTO_DECRYPT_FN_PTR)
      (ucrypto_mech_t mech_type, uchar_t *key_str,
       size_t key_len, void *iv, size_t iv_len, uchar_t *in,
@@ -105,10 +99,8 @@
      (crypto_ctx_t *context, ucrypto_mech_t mech_type,
       uchar_t *key_str, size_t key_len,
       void *iv, size_t iv_len);
-
 typedef int (*UCRYPTO_SIGN_UPDATE_FN_PTR)
      (crypto_ctx_t *context, uchar_t *data_str, size_t data_len);
-
 typedef int (*UCRYPTO_SIGN_FINAL_FN_PTR)
      (crypto_ctx_t *context, uchar_t *sig_str, size_t *sig_len);
 
@@ -116,13 +108,24 @@
      (crypto_ctx_t *context, ucrypto_mech_t mech_type,
       uchar_t *key_str, size_t key_len,
       void *iv, size_t iv_len);
-
 typedef int (*UCRYPTO_VERIFY_UPDATE_FN_PTR)
      (crypto_ctx_t *context, uchar_t *data_str, size_t data_len);
-
 typedef int (*UCRYPTO_VERIFY_FINAL_FN_PTR)
      (crypto_ctx_t *context, uchar_t *sig_str, size_t *sig_len);
 
+typedef int (*UCRYPTO_DIGEST_INIT_FN_PTR)
+     (crypto_ctx_t *context, ucrypto_mech_t mech_type,
+      void *param, size_t param_len);
+typedef int (*UCRYPTO_DIGEST_UPDATE_FN_PTR)
+     (crypto_ctx_t *context, const uchar_t *data, size_t data_len);
+typedef int (*UCRYPTO_DIGEST_FINAL_FN_PTR)
+     (crypto_ctx_t *context, uchar_t *digest, size_t *digest_len);
+
+typedef void (*UCRYPTO_FREE_CONTEXT_FN_PTR)
+     (crypto_ctx_t *context);
+
+typedef char* (*UCRYPTO_STRERROR_FN_PTR)(int rv);
+
 
 
 /* dynamically resolved functions from libmd, and libsoftcrypto
@@ -153,6 +156,11 @@
   UCRYPTO_VERIFY_INIT_FN_PTR     ucryptoVerifyInit;
   UCRYPTO_VERIFY_UPDATE_FN_PTR   ucryptoVerifyUpdate;
   UCRYPTO_VERIFY_FINAL_FN_PTR    ucryptoVerifyFinal;
+  UCRYPTO_DIGEST_INIT_FN_PTR     ucryptoDigestInit;
+  UCRYPTO_DIGEST_UPDATE_FN_PTR   ucryptoDigestUpdate;
+  UCRYPTO_DIGEST_FINAL_FN_PTR    ucryptoDigestFinal;
+  UCRYPTO_FREE_CONTEXT_FN_PTR    ucryptoFreeContext;
+  UCRYPTO_STRERROR_FN_PTR        ucryptoStrerror;
 } T4CRYPTO_FUNCTION_TABLE;
 
 typedef T4CRYPTO_FUNCTION_TABLE *T4CRYPTO_FUNCTION_TABLE_PTR;
--- a/jdk/test/com/oracle/security/ucrypto/TestDigest.java	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/test/com/oracle/security/ucrypto/TestDigest.java	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug     7088989
+ * @bug     7088989 8000415
  * @summary Ensure the various message digests works correctly
  * @key randomness
  */
@@ -40,84 +40,106 @@
     private static final String[] MD_ALGOS = {
         "MD5",
         "SHA",
+        "SHA-224",
         "SHA-256",
         "SHA-384",
-        "SHA-512"
+        "SHA-512",
+        "SHA3-224",
+        "SHA3-256",
+        "SHA3-384",
+        "SHA3-512"
     };
 
     public static void main(String[] args) throws Exception {
         main(new TestDigest(), null);
     }
 
-    public void doTest(Provider p) {
+    public void doTest(Provider p) throws Exception {
         boolean testPassed = true;
         byte[] msg = new byte[200];
         (new SecureRandom()).nextBytes(msg);
         String interopProvName = "SUN";
 
+        MessageDigest md, md2;
+
         for (String a : MD_ALGOS) {
+            System.out.println("Testing " + a);
             try {
-                MessageDigest md, md2;
-                try {
-                    md = MessageDigest.getInstance(a, p);
-                } catch (NoSuchAlgorithmException nsae) {
-                    System.out.println("Skipping Unsupported MD algo: " + a);
-                    continue;
-                }
+                md = MessageDigest.getInstance(a, p);
+            } catch (NoSuchAlgorithmException nsae) {
+                System.out.println("=> Skip, unsupported");
+                continue;
+            }
+            try {
                 md2 = MessageDigest.getInstance(a, interopProvName);
-                // Test Interoperability for update+digest calls
-                for (int i = 0; i < 3; i++) {
-                    md.update(msg);
-                    byte[] digest = md.digest();
-                    md2.update(msg);
-                    byte[] digest2 = md2.digest();
-                    if (!Arrays.equals(digest, digest2)) {
-                        System.out.println("DIFF1 FAILED for: " + a + " at iter " + i);
-                        testPassed = false;
-                    }
-                }
+            } catch (NoSuchAlgorithmException nsae) {
+                System.out.println("=> Skip, no interop provider found");
+                continue;
+            }
 
-                // Test Interoperability for digest calls
-                md = MessageDigest.getInstance(a, p);
-                md2 = MessageDigest.getInstance(a, interopProvName);
+            // Test Interoperability for update+digest calls
+            for (int i = 0; i < 3; i++) {
+                md.update(msg);
+                byte[] digest = md.digest();
+                md2.update(msg);
+                byte[] digest2 = md2.digest();
+                if (!Arrays.equals(digest, digest2)) {
+                    System.out.println("DIFF1 FAILED at iter " + i);
+                    testPassed = false;
+                } else {
+                    System.out.println("...diff1 test passed");
+                }
+            }
 
-                for (int i = 0; i < 3; i++) {
-                    byte[] digest = md.digest();
-                    byte[] digest2 = md2.digest();
-                    if (!Arrays.equals(digest, digest2)) {
-                        System.out.println("DIFF2 FAILED for: " + a + " at iter " + i);
-                        testPassed = false;
-                    }
-                }
+            // Test Interoperability for digest calls
+            md = MessageDigest.getInstance(a, p);
+            md2 = MessageDigest.getInstance(a, interopProvName);
 
-                // Test Cloning functionality
-                md = MessageDigest.getInstance(a, p);
-                md2 = (MessageDigest) md.clone(); // clone right after construction
+            for (int i = 0; i < 3; i++) {
                 byte[] digest = md.digest();
                 byte[] digest2 = md2.digest();
                 if (!Arrays.equals(digest, digest2)) {
-                    System.out.println("DIFF-3.1 FAILED for: " + a);
+                    System.out.println("DIFF2 FAILED at iter " + i);
                     testPassed = false;
-                }
-                md.update(msg);
-                md2 = (MessageDigest) md.clone(); // clone again after update call
-                digest = md.digest();
-                digest2 = md2.digest();
-                if (!Arrays.equals(digest, digest2)) {
-                    System.out.println("DIFF-3.2 FAILED for: " + a);
-                    testPassed = false;
+                } else {
+                    System.out.println("...diff2 test passed");
                 }
-                md2 = (MessageDigest) md.clone(); // clone after digest
-                digest = md.digest();
-                digest2 = md2.digest();
-                if (!Arrays.equals(digest, digest2)) {
-                    System.out.println("DIFF-3.3 FAILED for: " + a);
-                    testPassed = false;
-                }
-            } catch(Exception ex) {
-                System.out.println("Unexpected Exception: " + a);
-                ex.printStackTrace();
+            }
+
+            // Test Cloning functionality if supported
+            md = MessageDigest.getInstance(a, p);
+            try {
+                md2 = (MessageDigest) md.clone(); // clone right after construction
+            } catch (CloneNotSupportedException cnse) {
+                System.out.println("...no clone support");
+                continue;
+            }
+            byte[] digest = md.digest();
+            byte[] digest2 = md2.digest();
+            if (!Arrays.equals(digest, digest2)) {
+                System.out.println("DIFF-3.1 FAILED");
                 testPassed = false;
+            } else {
+                System.out.println("...diff3.1 tests passed");
+            }
+            md.update(msg);
+            md2 = (MessageDigest) md.clone(); // clone again after update call
+            digest = md.digest();
+            digest2 = md2.digest();
+            if (!Arrays.equals(digest, digest2)) {
+                System.out.println("DIFF-3.2 FAILED");
+                testPassed = false;
+            } else {
+                System.out.println("...diff3.2 tests passed");
+            }
+            md2 = (MessageDigest) md.clone(); // clone after digest
+            digest = md.digest();
+            digest2 = md2.digest();
+            if (!Arrays.equals(digest, digest2)) {
+                System.out.println("DIFF-3.3 FAILED");
+                testPassed = false;
+            } else {
+                System.out.println("...diff3.3 tests passed");
             }
         }
         if (!testPassed) {
--- a/jdk/test/sun/security/provider/MessageDigest/Offsets.java	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/test/sun/security/provider/MessageDigest/Offsets.java	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -84,6 +84,10 @@
         test("SHA-256", 0, 64, 0, 128);
         test("SHA-384", 0, 128, 0, 256);
         test("SHA-512", 0, 128, 0, 256);
+        test("SHA3-224", 0, 64, 0, 128);
+        test("SHA3-256", 0, 64, 0, 128);
+        test("SHA3-384", 0, 128, 0, 256);
+        test("SHA3-512", 0, 128, 0, 256);
     }
 
 }
--- a/jdk/test/sun/security/provider/MessageDigest/TestSHAClone.java	Fri May 13 18:58:32 2016 +0000
+++ b/jdk/test/sun/security/provider/MessageDigest/TestSHAClone.java	Sat May 14 03:44:30 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -32,8 +32,13 @@
 
 public class TestSHAClone {
 
+    // OracleUcrypto provider gets its digest impl from either
+    // libucrypto (starting S12 with SHA-3 support added) and
+    // libmd (pre-S12, no SHA-3 at all).
+    // The impls from libucrypto does not support clone but ones
+    // from libmd do.
     private static final String[] ALGOS = {
-        "SHA", "SHA-224", "SHA-256", "SHA-512", "SHA-384"
+        "SHA", "SHA-224", "SHA-256", "SHA-384", "SHA-512"
     };
 
     private static byte[] input1 = {
@@ -52,7 +57,13 @@
 
     private void run() throws Exception {
         md.update(input1);
-        MessageDigest md2 = (MessageDigest) md.clone();
+        MessageDigest md2;
+        try {
+            md2 = (MessageDigest) md.clone();
+        } catch (CloneNotSupportedException cnse) {
+            System.out.println(md.getAlgorithm() + ": clone unsupported");
+            return;
+        }
         md.update(input2);
         md2.update(input2);
         if (!Arrays.equals(md.digest(), md2.digest())) {