changeset 10877:558e97e47abe

8046002: Move Ucrypto to the open jdk repo Summary: Move Ucrypto related sources, tests to openJDK Reviewed-by: mullan
author valeriep
date Mon, 20 Oct 2014 21:18:48 +0000
parents 57d07aa0a0eb
children 4110a7627857
files make/CreateJars.gmk make/CreateSecurityJars.gmk make/copy/Copy-java.base.gmk make/copy/Copy-jdk.crypto.ucrypto.gmk make/lib/Lib-jdk.crypto.ucrypto.gmk src/java.base/share/conf/security/java.policy src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/CipherContextRef.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/Config.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/GCMParameters.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipher.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipherWithJavaPadding.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigest.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeKey.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSACipher.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSAKeyFactory.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoException.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.java src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java src/jdk.crypto.ucrypto/solaris/conf/security/ucrypto-solaris.cfg src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.h src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.c src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.h src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/sys_old/crypto/common.h src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/sys_old/crypto/spi.h test/TEST.groups test/com/oracle/security/ucrypto/CipherSignNotSupported.java test/com/oracle/security/ucrypto/Test8004873.java test/com/oracle/security/ucrypto/TestAES.java test/com/oracle/security/ucrypto/TestCICOWithGCM.java test/com/oracle/security/ucrypto/TestCICOWithGCMAndAAD.java test/com/oracle/security/ucrypto/TestDigest.java test/com/oracle/security/ucrypto/TestGCMKeyAndIvCheck.java test/com/oracle/security/ucrypto/TestGCMKeyWrap.java test/com/oracle/security/ucrypto/TestGCMWithSBE.java test/com/oracle/security/ucrypto/TestKATForGCM.java test/com/oracle/security/ucrypto/TestMalformedRSA.java test/com/oracle/security/ucrypto/TestRSA.java test/com/oracle/security/ucrypto/UcryptoTest.java
diffstat 41 files changed, 9361 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/make/CreateJars.gmk	Mon Oct 20 12:54:36 2014 -0400
+++ b/make/CreateJars.gmk	Mon Oct 20 21:18:48 2014 +0000
@@ -111,6 +111,7 @@
 # This value should exclude types destined for jars other than rt.jar and resources.jar.
 # When building a Profile this value augments the profile specific exclusions
 RT_JAR_EXCLUDES += \
+    com/oracle/security/ucrypto \
     com/sun/codemodel \
     com/sun/crypto/provider \
     com/sun/istack/internal/tools \
--- a/make/CreateSecurityJars.gmk	Mon Oct 20 12:54:36 2014 -0400
+++ b/make/CreateSecurityJars.gmk	Mon Oct 20 21:18:48 2014 +0000
@@ -169,27 +169,25 @@
 ##########################################################################################
 
 ifeq ($(OPENJDK_TARGET_OS), solaris)
-  ifndef OPENJDK
 
-    UCRYPTO_JAR_DST := $(JDK_OUTPUTDIR)/lib/ext/ucrypto.jar
-    UCRYPTO_JAR_UNSIGNED := $(JDK_OUTPUTDIR)/jce/unsigned/ucrypto.jar
+  UCRYPTO_JAR_DST := $(JDK_OUTPUTDIR)/lib/ext/ucrypto.jar
+  UCRYPTO_JAR_UNSIGNED := $(JDK_OUTPUTDIR)/jce/unsigned/ucrypto.jar
 
-    $(eval $(call SetupArchive,BUILD_UCRYPTO_JAR, , \
-        SRCS := $(JDK_OUTPUTDIR)/modules/jdk.crypto.ucrypto, \
-        SUFFIXES := .class, \
-        INCLUDES := com/oracle/security/ucrypto, \
-        JAR := $(UCRYPTO_JAR_UNSIGNED), \
-        MANIFEST := $(JCE_MANIFEST), \
-        SKIP_METAINF := true))
+  $(eval $(call SetupArchive,BUILD_UCRYPTO_JAR, , \
+      SRCS := $(JDK_OUTPUTDIR)/modules/jdk.crypto.ucrypto, \
+      SUFFIXES := .class, \
+      INCLUDES := com/oracle/security/ucrypto, \
+      JAR := $(UCRYPTO_JAR_UNSIGNED), \
+      MANIFEST := $(JCE_MANIFEST), \
+      SKIP_METAINF := true))
 
-    $(UCRYPTO_JAR_UNSIGNED): $(JCE_MANIFEST)
+  $(UCRYPTO_JAR_UNSIGNED): $(JCE_MANIFEST)
 
-    $(UCRYPTO_JAR_DST): $(UCRYPTO_JAR_UNSIGNED)
+  $(UCRYPTO_JAR_DST): $(UCRYPTO_JAR_UNSIGNED)
 	$(install-file)
 
-    TARGETS += $(UCRYPTO_JAR_UNSIGNED) $(UCRYPTO_JAR_DST)
+  TARGETS += $(UCRYPTO_JAR_UNSIGNED) $(UCRYPTO_JAR_DST)
 
-  endif
 endif
 
 all: $(TARGETS)
--- a/make/copy/Copy-java.base.gmk	Mon Oct 20 12:54:36 2014 -0400
+++ b/make/copy/Copy-java.base.gmk	Mon Oct 20 21:18:48 2014 +0000
@@ -170,10 +170,7 @@
 
 ifeq ($(OPENJDK_TARGET_OS), windows)
   POLICY_SRC_LIST += $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/conf/security/java.policy
-endif
-ifndef OPENJDK
-  # if $(OPENJDK_TARGET_OS) is windows or solaris
-  ifneq ($(findstring $(OPENJDK_TARGET_OS), windows solaris), )
+  ifndef OPENJDK
     POLICY_SRC_LIST += $(JDK_TOPDIR)/src/closed/java.base/$(OPENJDK_TARGET_OS)/conf/security/java.policy
   endif
 endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/copy/Copy-jdk.crypto.ucrypto.gmk	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,49 @@
+#
+# 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.
+#
+
+include CopyCommon.gmk
+
+################################################################################
+
+ifeq ($(OPENJDK_TARGET_OS), solaris)
+
+  UCRYPTO_CFG_SRC := $(JDK_TOPDIR)/src/jdk.crypto.ucrypto/solaris/conf/security/ucrypto-solaris.cfg
+  UCRYPTO_CFG_DST := $(JDK_OUTPUTDIR)/lib/security/ucrypto-solaris.cfg
+
+  $(UCRYPTO_CFG_DST): $(UCRYPTO_CFG_SRC)
+	$(call install-file)
+
+  SECURITY_UCRYPTO_CONF_FILES += $(UCRYPTO_CFG_DST)
+
+endif
+
+################################################################################
+
+jdk.crypto.ucrypto: $(SECURITY_UCRYPTO_CONF_FILES)
+
+all: jdk.crypto.ucrypto
+
+.PHONY: all jdk.crypto.ucrypto
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/lib/Lib-jdk.crypto.ucrypto.gmk	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,62 @@
+#
+# 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.
+#
+
+include $(SPEC)
+include $(JDK_TOPDIR)/make/lib/LibCommon.gmk
+
+################################################################################
+
+ifeq ($(OPENJDK_TARGET_OS), solaris)
+
+  LIBJ2UCRYPTO_SRC := $(JDK_TOPDIR)/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto
+
+  $(eval $(call SetupNativeCompilation,BUILD_LIBJ2UCRYPTO, \
+      LIBRARY := j2ucrypto, \
+      OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+      SRC := $(LIBJ2UCRYPTO_SRC), \
+      LANG := C, \
+      OPTIMIZATION := LOW, \
+      CFLAGS := $(CFLAGS_JDKLIB) \
+          $(addprefix -I, $(LIBJ2UCRYPTO_SRC)), \
+      MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libj2ucrypto/mapfile-vers, \
+      LDFLAGS := $(LDFLAGS_JDKLIB), \
+      LDFLAGS_SUFFIX := $(LIBDL), \
+      LDFLAGS_SUFFIX_solaris := -lc, \
+      OBJECT_DIR := $(JDK_OUTPUTDIR)/objs/libj2ucrypto, \
+      DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
+
+  $(BUILD_LIBJ2UCRYPTO): $(BUILD_LIBJAVA)
+
+  SECURITY_UCRYPTO_LIBRARIES += $(BUILD_LIBJ2UCRYPTO)
+
+endif
+
+################################################################################
+
+jdk.crypto.ucrypto: $(SECURITY_UCRYPTO_LIBRARIES)
+
+all: jdk.crypto.ucrypto
+
+.PHONY: all jdk.crypto.ucrypto
--- a/src/java.base/share/conf/security/java.policy	Mon Oct 20 12:54:36 2014 -0400
+++ b/src/java.base/share/conf/security/java.policy	Mon Oct 20 21:18:48 2014 +0000
@@ -25,6 +25,18 @@
         permission java.security.AllPermission;
 };
 
+grant codeBase "file:${java.home}/lib/ext/ucrypto.jar" {
+        permission java.lang.RuntimePermission "accessClassInPackage.sun.security.*";
+        permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
+        permission java.lang.RuntimePermission "loadLibrary.j2ucrypto";
+        // need "com.oracle.security.ucrypto.debug" for debugging
+        permission java.util.PropertyPermission "*", "read";
+        permission java.security.SecurityPermission "putProviderProperty.OracleUcrypto";
+        permission java.security.SecurityPermission "clearProviderProperties.OracleUcrypto";
+        permission java.security.SecurityPermission "removeProviderProperty.OracleUcrypto";
+        permission java.io.FilePermission "${java.home}/lib/security/ucrypto-solaris.cfg", "read";
+};
+
 grant codeBase "file:${java.home}/lib/ext/sunec.jar" {
         permission java.lang.RuntimePermission "accessClassInPackage.sun.security.*";
         permission java.lang.RuntimePermission "loadLibrary.sunec";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/CipherContextRef.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.nio.ByteBuffer;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.lang.ref.*;
+
+import java.security.*;
+import java.security.spec.*;
+import javax.crypto.*;
+
+import javax.crypto.spec.SecretKeySpec;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Internal class for context resource clean up.
+ *
+ * @since 1.9
+ */
+final class CipherContextRef extends PhantomReference<NativeCipher>
+    implements Comparable<CipherContextRef> {
+
+    private static ReferenceQueue<NativeCipher> refQueue =
+        new ReferenceQueue<NativeCipher>();
+
+    // 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<CipherContextRef> refList =
+        new ConcurrentSkipListSet<CipherContextRef>();
+
+    final long id;
+    final boolean encrypt;
+
+    private static void drainRefQueueBounded() {
+        while (true) {
+            CipherContextRef next = (CipherContextRef) refQueue.poll();
+            if (next == null) break;
+            next.dispose(true);
+        }
+    }
+
+    CipherContextRef(NativeCipher nc, long id, boolean encrypt) {
+        super(nc, refQueue);
+        this.id = id;
+        this.encrypt = encrypt;
+        refList.add(this);
+        UcryptoProvider.debug("Resource: trace CipherCtxt " + this.id);
+        drainRefQueueBounded();
+    }
+
+    public int compareTo(CipherContextRef other) {
+        if (this.id == other.id) {
+            return 0;
+        } else {
+            return (this.id < other.id) ? -1 : 1;
+        }
+    }
+
+    void dispose(boolean doCancel) {
+        refList.remove(this);
+        try {
+            if (doCancel) {
+                UcryptoProvider.debug("Resource: cancel CipherCtxt " + id);
+                int k = NativeCipher.nativeFinal(id, encrypt, null, 0);
+                if (k < 0) {
+                    UcryptoProvider.debug
+                        ("Resource: error cancelling CipherCtxt " + id +
+                        " " + new UcryptoException(-k).getMessage());
+                }
+            } else {
+                UcryptoProvider.debug("Resource: untrace CipherCtxt " + id);
+            }
+        } finally {
+            this.clear();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/Config.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.io.*;
+import static java.io.StreamTokenizer.*;
+import java.math.BigInteger;
+import java.util.*;
+
+import java.security.*;
+
+import sun.security.action.GetPropertyAction;
+import sun.security.util.PropertyExpander;
+
+import sun.security.pkcs11.wrapper.*;
+
+/**
+ * Configuration container and file parsing.
+ *
+ * Currently, there is only one supported entry "disabledServices"
+ * for disabling crypto services. Its syntax is as follows:
+ *
+ * disabledServices = {
+ * <ServiceType>.<Algorithm>
+ * ...
+ * }
+ *
+ * where <Service> can be "MessageDigest", "Cipher", etc. and <Algorithm>
+ * reprepresents the value that's passed into the various getInstance() calls.
+ *
+ * @since   1.9
+ */
+final class Config {
+
+    // Reader and StringTokenizer used during parsing
+    private Reader reader;
+
+    private StreamTokenizer st;
+
+    private Set<String> parsedKeywords;
+
+    // set of disabled crypto services, e.g. MessageDigest.SHA1, or
+    // Cipher.AES/ECB/PKCS5Padding
+    private Set<String> disabledServices;
+
+    Config(String filename) throws IOException {
+        FileInputStream in = new FileInputStream(expand(filename));
+        reader = new BufferedReader(new InputStreamReader(in));
+        parsedKeywords = new HashSet<String>();
+        st = new StreamTokenizer(reader);
+        setupTokenizer();
+        parse();
+    }
+
+    String[] getDisabledServices() {
+        if (disabledServices != null) {
+            return disabledServices.toArray(new String[disabledServices.size()]);
+        } else {
+            return new String[0];
+        }
+    }
+
+    private static String expand(final String s) throws IOException {
+        try {
+            return PropertyExpander.expand(s);
+        } catch (Exception e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    private void setupTokenizer() {
+        st.resetSyntax();
+        st.wordChars('a', 'z');
+        st.wordChars('A', 'Z');
+        st.wordChars('0', '9');
+        st.wordChars(':', ':');
+        st.wordChars('.', '.');
+        st.wordChars('_', '_');
+        st.wordChars('-', '-');
+        st.wordChars('/', '/');
+        st.wordChars('\\', '\\');
+        st.wordChars('$', '$');
+        st.wordChars('{', '{'); // need {} for property subst
+        st.wordChars('}', '}');
+        st.wordChars('*', '*');
+        st.wordChars('+', '+');
+        st.wordChars('~', '~');
+        // XXX check ASCII table and add all other characters except special
+
+        // special: #="(),
+        st.whitespaceChars(0, ' ');
+        st.commentChar('#');
+        st.eolIsSignificant(true);
+        st.quoteChar('\"');
+    }
+
+    private ConfigException excToken(String msg) {
+        return new ConfigException(msg + " " + st);
+    }
+
+    private ConfigException excLine(String msg) {
+        return new ConfigException(msg + ", line " + st.lineno());
+    }
+
+    private void parse() throws IOException {
+        while (true) {
+            int token = nextToken();
+            if (token == TT_EOF) {
+                break;
+            }
+            if (token == TT_EOL) {
+                continue;
+            }
+            if (token != TT_WORD) {
+                throw excToken("Unexpected token:");
+            }
+            String word = st.sval;
+            if (word.equals("disabledServices")) {
+                parseDisabledServices(word);
+            } else {
+                throw new ConfigException
+                        ("Unknown keyword '" + word + "', line " + st.lineno());
+            }
+            parsedKeywords.add(word);
+        }
+        reader.close();
+        reader = null;
+        st = null;
+        parsedKeywords = null;
+    }
+
+    //
+    // Parsing helper methods
+    //
+    private int nextToken() throws IOException {
+        int token = st.nextToken();
+        return token;
+    }
+
+    private void parseEquals() throws IOException {
+        int token = nextToken();
+        if (token != '=') {
+            throw excToken("Expected '=', read");
+        }
+    }
+
+    private void parseOpenBraces() throws IOException {
+        while (true) {
+            int token = nextToken();
+            if (token == TT_EOL) {
+                continue;
+            }
+            if ((token == TT_WORD) && st.sval.equals("{")) {
+                return;
+            }
+            throw excToken("Expected '{', read");
+        }
+    }
+
+    private boolean isCloseBraces(int token) {
+        return (token == TT_WORD) && st.sval.equals("}");
+    }
+
+    private void checkDup(String keyword) throws IOException {
+        if (parsedKeywords.contains(keyword)) {
+            throw excLine(keyword + " must only be specified once");
+        }
+    }
+
+    private void parseDisabledServices(String keyword) throws IOException {
+        checkDup(keyword);
+        disabledServices = new HashSet<String>();
+        parseEquals();
+        parseOpenBraces();
+        while (true) {
+            int token = nextToken();
+            if (isCloseBraces(token)) {
+                break;
+            }
+            if (token == TT_EOL) {
+                continue;
+            }
+            if (token != TT_WORD) {
+                throw excToken("Expected mechanism, read");
+            }
+            disabledServices.add(st.sval);
+        }
+    }
+}
+
+class ConfigException extends IOException {
+    private static final long serialVersionUID = 254492758127673194L;
+    ConfigException(String msg) {
+        super(msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/GCMParameters.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import javax.crypto.spec.GCMParameterSpec;
+import sun.security.util.*;
+
+/**
+ * This class implements the parameter set used with GCM mode
+ * which is defined in RFC5084 as follows:
+ *
+ * <pre>
+ * GCMParameters ::= SEQUENCE {
+ *   aes-nonce        OCTET STRING, -- recommended size is 12 octets
+ *   aes-ICVlen       AES-GCM-ICVlen DEFAULT 12 }
+ *
+ * where
+ * AES-GCM-ICVlen ::= INTEGER (12 | 13 | 14 | 15 | 16)
+ * NOTE: however, NIST 800-38D also lists 4 (32bit) and 8 (64bit)
+ * as possible AES-GCM-ICVlen values, so we allow all 6 values.
+ * </pre>
+ *
+ * @since 1.9
+ */
+public final class GCMParameters extends AlgorithmParametersSpi {
+
+    private byte[] iv; // i.e. aes-nonce
+    private int tLen; // i.e. aes-ICVlen, in bytes
+
+    public GCMParameters() {}
+
+    private void setValues(byte[] iv, int tLen) throws IOException {
+        if (iv == null) {
+            throw new IOException("IV cannot be null");
+        }
+        if (tLen != 4 && tLen != 8 && (tLen < 12 || tLen > 16)) {
+            throw new IOException("Unsupported tag length: " + tLen);
+        }
+        this.iv = iv;
+        this.tLen = tLen;
+    }
+
+    protected byte[] engineGetEncoded() throws IOException {
+        DerOutputStream out = new DerOutputStream();
+        DerOutputStream bytes = new DerOutputStream();
+
+        bytes.putOctetString(iv);
+        bytes.putInteger(tLen);
+        out.write(DerValue.tag_Sequence, bytes);
+        return out.toByteArray();
+    }
+
+    protected byte[] engineGetEncoded(String format) throws IOException {
+        // ignore format for now
+        return engineGetEncoded();
+    }
+
+    protected <T extends AlgorithmParameterSpec>
+            T engineGetParameterSpec(Class<T> paramSpec)
+        throws InvalidParameterSpecException {
+        if (GCMParameterSpec.class.isAssignableFrom(paramSpec)) {
+            return paramSpec.cast(new GCMParameterSpec(tLen*8, iv.clone()));
+        } else {
+            throw new InvalidParameterSpecException
+                ("Inappropriate parameter specification");
+        }
+    }
+
+    protected void engineInit(AlgorithmParameterSpec paramSpec)
+        throws InvalidParameterSpecException {
+        if (!(paramSpec instanceof GCMParameterSpec)) {
+            throw new InvalidParameterSpecException
+                ("Inappropriate parameter specification");
+        }
+        GCMParameterSpec gcmSpec = (GCMParameterSpec) paramSpec;
+        try {
+            setValues(gcmSpec.getIV(), gcmSpec.getTLen()/8);
+        } catch (IOException ioe) {
+            throw new InvalidParameterSpecException(ioe.getMessage());
+        }
+    }
+
+    protected void engineInit(byte[] encoded) throws IOException {
+        DerValue val = new DerValue(encoded);
+        if (val.tag == DerValue.tag_Sequence) {
+            val.data.reset();
+            setValues(val.data.getOctetString(), val.data.getInteger());
+        } else {
+            throw new IOException("GCM parameter parsing error: SEQ tag expected");
+        }
+    }
+
+    protected void engineInit(byte[] encoded, String format)
+        throws IOException {
+        // ignore format for now
+        engineInit(encoded);
+    }
+
+    protected String engineToString() {
+        return ("IV=" + Arrays.toString(iv) + ", tLen=" + tLen * 8);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipher.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,588 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.nio.ByteBuffer;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.lang.ref.*;
+
+import java.security.*;
+import java.security.spec.*;
+import javax.crypto.*;
+
+import javax.crypto.spec.SecretKeySpec;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Cipher wrapper class utilizing ucrypto APIs. This class currently supports
+ * - AES/ECB/NOPADDING
+ * - AES/CBC/NOPADDING
+ * - AES/CTR/NOPADDING
+ * - AES/CFB128/NOPADDING
+ * (Support for GCM mode is inside the child class NativeGCMCipher)
+ *
+ * @since 1.9
+ */
+class NativeCipher extends CipherSpi {
+
+    // public implementation classes
+    public static final class AesEcbNoPadding extends NativeCipher {
+        public AesEcbNoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_AES_ECB);
+        }
+    }
+    public static final class AesCbcNoPadding extends NativeCipher {
+        public AesCbcNoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_AES_CBC);
+        }
+    }
+    public static final class AesCtrNoPadding extends NativeCipher {
+        public AesCtrNoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_AES_CTR);
+        }
+    }
+    public static final class AesCfb128NoPadding extends NativeCipher {
+        public AesCfb128NoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_AES_CFB128);
+        }
+    }
+
+    // public implementation classes with fixed key sizes
+    public static final class Aes128EcbNoPadding extends NativeCipher {
+        public Aes128EcbNoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_AES_ECB, 16);
+        }
+    }
+    public static final class Aes128CbcNoPadding extends NativeCipher {
+        public Aes128CbcNoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_AES_CBC, 16);
+        }
+    }
+    public static final class Aes192EcbNoPadding extends NativeCipher {
+        public Aes192EcbNoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_AES_ECB, 24);
+        }
+    }
+    public static final class Aes192CbcNoPadding extends NativeCipher {
+        public Aes192CbcNoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_AES_CBC, 24);
+        }
+    }
+    public static final class Aes256EcbNoPadding extends NativeCipher {
+        public Aes256EcbNoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_AES_ECB, 32);
+        }
+    }
+    public static final class Aes256CbcNoPadding extends NativeCipher {
+        public Aes256CbcNoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_AES_CBC, 32);
+        }
+    }
+
+    // ok as constants since AES is all we support
+    public static final int AES_BLOCK_SIZE = 16;
+    public static final String AES_KEY_ALGO = "AES";
+
+    // fields set in constructor
+    protected final UcryptoMech mech;
+    protected String keyAlgo;
+    protected int blockSize;
+    protected int fixedKeySize;
+
+    //
+    // fields (re)set in every init()
+    //
+    protected CipherContextRef pCtxt = null;
+    protected byte[] keyValue = null;
+    protected byte[] iv = null;
+    protected boolean initialized = false;
+    protected boolean encrypt = true;
+    protected int bytesBuffered = 0;
+
+    // private utility methods for key re-construction
+    private static final PublicKey constructPublicKey(byte[] encodedKey,
+                                              String encodedKeyAlgorithm)
+        throws InvalidKeyException, NoSuchAlgorithmException {
+
+        PublicKey key = null;
+        try {
+            KeyFactory keyFactory =
+                KeyFactory.getInstance(encodedKeyAlgorithm);
+            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
+            key = keyFactory.generatePublic(keySpec);
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new NoSuchAlgorithmException("No provider found for " +
+                                               encodedKeyAlgorithm +
+                                               " KeyFactory");
+        } catch (InvalidKeySpecException ikse) {
+            // Should never happen
+            throw new InvalidKeyException("Cannot construct public key", ikse);
+        }
+        return key;
+    }
+
+    private static final PrivateKey constructPrivateKey(byte[] encodedKey,
+                                                String encodedKeyAlgorithm)
+        throws InvalidKeyException, NoSuchAlgorithmException {
+
+        PrivateKey key = null;
+        try {
+            KeyFactory keyFactory =
+                KeyFactory.getInstance(encodedKeyAlgorithm);
+            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
+            key = keyFactory.generatePrivate(keySpec);
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new NoSuchAlgorithmException("No provider found for " +
+                                               encodedKeyAlgorithm +
+                                               " KeyFactory");
+        } catch (InvalidKeySpecException ikse) {
+            // Should never happen
+            throw new InvalidKeyException("Cannot construct private key", ikse);
+        }
+        return key;
+    }
+
+    private static final SecretKey constructSecretKey(byte[] encodedKey,
+                                              String encodedKeyAlgorithm) {
+        return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);
+    }
+
+    // package-private utility method for general key re-construction
+    static final Key constructKey(int keyType, byte[] encodedKey,
+                                  String encodedKeyAlgorithm)
+        throws InvalidKeyException, NoSuchAlgorithmException {
+        Key result = null;
+        switch (keyType) {
+        case Cipher.SECRET_KEY:
+            result = constructSecretKey(encodedKey,
+                                        encodedKeyAlgorithm);
+            break;
+        case Cipher.PRIVATE_KEY:
+            result = constructPrivateKey(encodedKey,
+                                         encodedKeyAlgorithm);
+            break;
+        case Cipher.PUBLIC_KEY:
+            result = constructPublicKey(encodedKey,
+                                        encodedKeyAlgorithm);
+            break;
+        }
+        return result;
+    }
+
+    NativeCipher(UcryptoMech mech, int fixedKeySize) throws NoSuchAlgorithmException {
+        this.mech = mech;
+        // defaults to AES - the only supported symmetric cipher algo
+        this.blockSize = AES_BLOCK_SIZE;
+        this.keyAlgo = AES_KEY_ALGO;
+        this.fixedKeySize = fixedKeySize;
+    }
+
+    NativeCipher(UcryptoMech mech) throws NoSuchAlgorithmException {
+        this(mech, -1);
+    }
+
+    @Override
+    protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+        // Disallow change of mode for now since currently it's explicitly
+        // defined in transformation strings
+        throw new NoSuchAlgorithmException("Unsupported mode " + mode);
+    }
+
+    // see JCE spec
+    @Override
+    protected void engineSetPadding(String padding)
+            throws NoSuchPaddingException {
+        // Disallow change of padding for now since currently it's explicitly
+        // defined in transformation strings
+        throw new NoSuchPaddingException("Unsupported padding " + padding);
+    }
+
+    // see JCE spec
+    @Override
+    protected int engineGetBlockSize() {
+        return blockSize;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineGetOutputSize(int inputLen) {
+        return getOutputSizeByOperation(inputLen, true);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineGetIV() {
+        return (iv != null? iv.clone() : null);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized AlgorithmParameters engineGetParameters() {
+        AlgorithmParameters params = null;
+        try {
+            if (iv != null) {
+                IvParameterSpec ivSpec = new IvParameterSpec(iv.clone());
+                params = AlgorithmParameters.getInstance(keyAlgo);
+                params.init(ivSpec);
+            }
+        } catch (GeneralSecurityException e) {
+            // NoSuchAlgorithmException, NoSuchProviderException
+            // InvalidParameterSpecException
+            throw new UcryptoException("Could not encode parameters", e);
+        }
+        return params;
+    }
+
+    @Override
+    protected int engineGetKeySize(Key key) throws InvalidKeyException {
+        return checkKey(key) * 8;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key key,
+            SecureRandom random) throws InvalidKeyException {
+        try {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        } catch (InvalidAlgorithmParameterException e) {
+            throw new InvalidKeyException("init() failed", e);
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key key,
+            AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        checkKey(key);
+        if (opmode != Cipher.ENCRYPT_MODE &&
+            opmode != Cipher.DECRYPT_MODE &&
+            opmode != Cipher.WRAP_MODE &&
+            opmode != Cipher.UNWRAP_MODE) {
+            throw new InvalidAlgorithmParameterException
+                ("Unsupported mode: " + opmode);
+        }
+        boolean doEncrypt =
+                (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE);
+
+        byte[] ivBytes = null;
+        if (mech == UcryptoMech.CRYPTO_AES_ECB) {
+            if (params != null) {
+                throw new InvalidAlgorithmParameterException
+                        ("No Parameters for ECB mode");
+            }
+        } else {
+            if (params != null) {
+                if (!(params instanceof IvParameterSpec)) {
+                    throw new InvalidAlgorithmParameterException
+                            ("IvParameterSpec required");
+                } else {
+                    ivBytes = ((IvParameterSpec) params).getIV();
+                    if (ivBytes.length != blockSize) {
+                        throw new InvalidAlgorithmParameterException
+                             ("Wrong IV length: must be " + blockSize +
+                              " bytes long");
+                    }
+                }
+            } else {
+                if (encrypt) {
+                    // generate IV if none supplied for encryption
+                    ivBytes = new byte[blockSize];
+                    new SecureRandom().nextBytes(ivBytes);
+                } else {
+                    throw new InvalidAlgorithmParameterException
+                            ("Parameters required for decryption");
+                }
+            }
+        }
+        init(doEncrypt, key.getEncoded().clone(), ivBytes);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key key,
+            AlgorithmParameters params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        AlgorithmParameterSpec spec = null;
+        if (params != null) {
+            try {
+                spec = params.getParameterSpec(IvParameterSpec.class);
+            } catch (InvalidParameterSpecException iaps) {
+                throw new InvalidAlgorithmParameterException(iaps);
+            }
+        }
+        engineInit(opmode, key, spec, random);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineUpdate(byte[] in, int ofs, int len) {
+        byte[] out = new byte[getOutputSizeByOperation(len, false)];
+        int n = update(in, ofs, len, out, 0);
+        if (n == 0) {
+            return null;
+        } else if (out.length != n) {
+            out = Arrays.copyOf(out, n);
+        }
+        return out;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineUpdate(byte[] in, int inOfs, int inLen,
+        byte[] out, int outOfs) throws ShortBufferException {
+        int min = getOutputSizeByOperation(inLen, false);
+        if (out.length - outOfs < min) {
+            throw new ShortBufferException("min " + min + "-byte buffer needed");
+        }
+        return update(in, inOfs, inLen, out, outOfs);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineUpdateAAD(byte[] src, int ofs, int len)
+            throws IllegalStateException {
+        throw new IllegalStateException("No AAD can be supplied");
+    }
+
+    // see JCE spec
+    @Override
+    protected void engineUpdateAAD(ByteBuffer src)
+            throws IllegalStateException {
+        throw new IllegalStateException("No AAD can be supplied");
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineDoFinal(byte[] in, int ofs, int len)
+            throws IllegalBlockSizeException, BadPaddingException {
+        byte[] out = new byte[getOutputSizeByOperation(len, true)];
+        try {
+            // delegate to the other engineDoFinal(...) method
+            int k = engineDoFinal(in, ofs, len, out, 0);
+            if (out.length != k) {
+                out = Arrays.copyOf(out, k);
+            }
+            return out;
+        } catch (ShortBufferException e) {
+            throw new UcryptoException("Internal Error", e);
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineDoFinal(byte[] in, int inOfs, int inLen,
+                                             byte[] out, int outOfs)
+            throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        int k = 0;
+        int min = getOutputSizeByOperation(inLen, true);
+        if (out.length - outOfs < min) {
+            throw new ShortBufferException("min " + min + "-byte buffer needed");
+        }
+        if (inLen > 0) {
+            k = update(in, inOfs, inLen, out, outOfs);
+            outOfs += k;
+        }
+        k += doFinal(out, outOfs);
+        return k;
+    }
+
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineWrap(Key key)
+            throws IllegalBlockSizeException, InvalidKeyException {
+        byte[] result = null;
+        try {
+            byte[] encodedKey = key.getEncoded();
+            if ((encodedKey == null) || (encodedKey.length == 0)) {
+                throw new InvalidKeyException("Cannot get an encoding of " +
+                                              "the key to be wrapped");
+            }
+            result = engineDoFinal(encodedKey, 0, encodedKey.length);
+        } catch (BadPaddingException e) {
+            // Should never happen for key wrapping
+            throw new UcryptoException("Internal Error" , e);
+        }
+        return result;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized Key engineUnwrap(byte[] wrappedKey,
+            String wrappedKeyAlgorithm, int wrappedKeyType)
+            throws InvalidKeyException, NoSuchAlgorithmException {
+
+        byte[] encodedKey;
+        Key result = null;
+        try {
+            encodedKey = engineDoFinal(wrappedKey, 0,
+                                       wrappedKey.length);
+        } catch (Exception e) {
+            throw (InvalidKeyException)
+                (new InvalidKeyException()).initCause(e);
+        }
+
+        return constructKey(wrappedKeyType, encodedKey, wrappedKeyAlgorithm);
+    }
+
+    final int checkKey(Key key) throws InvalidKeyException {
+        if (key == null || key.getEncoded() == null) {
+            throw new InvalidKeyException("Key cannot be null");
+        } else {
+            // check key algorithm and format
+            if (!keyAlgo.equalsIgnoreCase(key.getAlgorithm())) {
+                throw new InvalidKeyException("Key algorithm must be " +
+                    keyAlgo);
+            }
+            if (!"RAW".equalsIgnoreCase(key.getFormat())) {
+                throw new InvalidKeyException("Key format must be RAW");
+            }
+            int keyLen = key.getEncoded().length;
+            if (fixedKeySize == -1) {
+                // all 3 AES key lengths are allowed
+                if (keyLen != 16 && keyLen != 24 && keyLen != 32) {
+                    throw new InvalidKeyException("Key size is not valid");
+                }
+            } else {
+                if (keyLen != fixedKeySize) {
+                    throw new InvalidKeyException("Only " + fixedKeySize +
+                        "-byte keys are accepted");
+                }
+            }
+            // return the validated key length in bytes
+            return keyLen;
+        }
+    }
+
+    protected void reset(boolean doCancel) {
+        initialized = false;
+        bytesBuffered = 0;
+        if (pCtxt != null) {
+            pCtxt.dispose(doCancel);
+            pCtxt = null;
+        }
+    }
+
+    /**
+     * calls ucrypto_encrypt_init(...) or ucrypto_decrypt_init(...)
+     * @return pointer to the context
+     */
+    protected native static long nativeInit(int mech, boolean encrypt,
+                                            byte[] key, byte[] iv,
+                                            int tagLen, byte[] aad);
+
+    /**
+     * calls ucrypto_encrypt_update(...) or ucrypto_decrypt_update(...)
+     * @returns the length of output or if negative, an error status code
+     */
+    private native static int nativeUpdate(long pContext, boolean encrypt,
+                                           byte[] in, int inOfs, int inLen,
+                                           byte[] out, int outOfs);
+
+    /**
+     * calls ucrypto_encrypt_final(...) or ucrypto_decrypt_final(...)
+     * @returns the length of output or if negative, an error status code
+     */
+    native static int nativeFinal(long pContext, boolean encrypt,
+                                          byte[] out, int outOfs);
+
+    protected void ensureInitialized() {
+        if (!initialized) {
+            init(encrypt, keyValue, iv);
+            if (!initialized) {
+                throw new UcryptoException("Cannot initialize Cipher");
+            }
+        }
+    }
+
+    protected int getOutputSizeByOperation(int inLen, boolean isDoFinal) {
+        if (inLen <= 0) {
+            inLen = 0;
+        }
+        if (!isDoFinal && (inLen == 0)) {
+            return 0;
+        }
+        return inLen + bytesBuffered;
+    }
+
+    // actual init() implementation - caller should clone key and iv if needed
+    protected void init(boolean encrypt, byte[] keyVal, byte[] ivVal) {
+        reset(true);
+        this.encrypt = encrypt;
+        this.keyValue = keyVal;
+        this.iv = ivVal;
+        long pCtxtVal = nativeInit(mech.value(), encrypt, keyValue, iv, 0, null);
+        initialized = (pCtxtVal != 0L);
+        if (initialized) {
+            pCtxt = new CipherContextRef(this, pCtxtVal, encrypt);
+        } else {
+            throw new UcryptoException("Cannot initialize Cipher");
+        }
+    }
+
+    // Caller MUST check and ensure output buffer has enough capacity
+    private int update(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) {
+        ensureInitialized();
+        if (inLen <= 0) { return 0; }
+
+        int k = nativeUpdate(pCtxt.id, encrypt, in, inOfs, inLen, out, outOfs);
+        if (k < 0) {
+            reset(false);
+            // cannot throw ShortBufferException here since it's too late
+            // native context is invalid upon any failure
+            throw new UcryptoException(-k);
+        }
+        bytesBuffered += (inLen - k);
+        return k;
+    }
+
+    // Caller MUST check and ensure output buffer has enough capacity
+    private int doFinal(byte[] out, int outOfs) throws IllegalBlockSizeException,
+            BadPaddingException {
+        try {
+            ensureInitialized();
+
+            int k = nativeFinal(pCtxt.id, encrypt, out, outOfs);
+            if (k < 0) {
+                String cause = UcryptoException.getErrorMessage(-k);
+                if (cause.endsWith("_LEN_RANGE")) {
+                    throw new IllegalBlockSizeException(cause);
+                } else if (cause.endsWith("_DATA_INVALID")) {
+                    throw new BadPaddingException(cause);
+                } else {
+                    throw new UcryptoException(-k);
+                }
+            }
+            return k;
+        } finally {
+            reset(false);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipherWithJavaPadding.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,464 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.nio.ByteBuffer;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.lang.ref.*;
+
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Wrapper class which uses NativeCipher class and Java impls of padding scheme.
+ * This class currently supports
+ * - AES/ECB/PKCS5PADDING
+ * - AES/CBC/PKCS5PADDING
+ * - AES/CFB128/PKCS5PADDING
+ *
+ * @since 1.9
+ */
+public class NativeCipherWithJavaPadding extends CipherSpi {
+
+    private static interface Padding {
+        // ENC: generate and return the necessary padding bytes
+        int getPadLen(int dataLen);
+
+        // ENC: generate and return the necessary padding bytes
+        byte[] getPaddingBytes(int dataLen);
+
+        // DEC: process the decrypted data and buffer up the potential padding
+        // bytes
+        byte[] bufferBytes(byte[] intermediateData);
+
+        // DEC: return the length of internally buffered pad bytes
+        int getBufferedLength();
+
+        // DEC: unpad and place the output in 'out', starting from outOfs
+        // and return the number of bytes unpadded into 'out'.
+        int unpad(byte[] paddedData, byte[] out, int outOfs)
+                throws BadPaddingException, IllegalBlockSizeException,
+                ShortBufferException;
+
+        // DEC: Clears the padding object to the initial state
+        void clear();
+    }
+
+    private static class PKCS5Padding implements Padding {
+        private final int blockSize;
+        // buffer for storing the the potential padding bytes
+        private ByteBuffer trailingBytes = null;
+
+        PKCS5Padding(int blockSize)
+            throws NoSuchPaddingException {
+            if (blockSize == 0) {
+                throw new NoSuchPaddingException
+                        ("PKCS#5 padding not supported with stream ciphers");
+            }
+            this.blockSize = blockSize;
+        }
+
+        public int getPadLen(int dataLen) {
+            return (blockSize - (dataLen & (blockSize - 1)));
+        }
+
+        public byte[] getPaddingBytes(int dataLen) {
+            byte padValue = (byte) getPadLen(dataLen);
+            byte[] paddingBytes = new byte[padValue];
+            Arrays.fill(paddingBytes, padValue);
+            return paddingBytes;
+        }
+
+        public byte[] bufferBytes(byte[] dataFromUpdate) {
+            if (dataFromUpdate == null || dataFromUpdate.length == 0) {
+                return null;
+            }
+            byte[] result = null;
+            if (trailingBytes == null) {
+                trailingBytes = ByteBuffer.wrap(new byte[blockSize]);
+            }
+            int tbSize = trailingBytes.position();
+            if (dataFromUpdate.length > trailingBytes.remaining()) {
+                int totalLen = dataFromUpdate.length + tbSize;
+                int newTBSize = totalLen % blockSize;
+                if (newTBSize == 0) {
+                    newTBSize = blockSize;
+                }
+                if (tbSize == 0) {
+                    result = Arrays.copyOf(dataFromUpdate, totalLen - newTBSize);
+                } else {
+                    // combine 'trailingBytes' and 'dataFromUpdate'
+                    result = Arrays.copyOf(trailingBytes.array(),
+                                           totalLen - newTBSize);
+                    if (result.length != tbSize) {
+                        System.arraycopy(dataFromUpdate, 0, result, tbSize,
+                                         result.length - tbSize);
+                    }
+                }
+                // update 'trailingBytes' w/ remaining bytes in 'dataFromUpdate'
+                trailingBytes.clear();
+                trailingBytes.put(dataFromUpdate,
+                                  dataFromUpdate.length - newTBSize, newTBSize);
+            } else {
+                trailingBytes.put(dataFromUpdate);
+            }
+            return result;
+        }
+
+        public int getBufferedLength() {
+            if (trailingBytes != null) {
+                return trailingBytes.position();
+            }
+            return 0;
+        }
+
+        public int unpad(byte[] lastData, byte[] out, int outOfs)
+                throws BadPaddingException, IllegalBlockSizeException,
+                ShortBufferException {
+            int tbSize = (trailingBytes == null? 0:trailingBytes.position());
+            int dataLen = tbSize + lastData.length;
+            // check total length
+            if ((dataLen < 1) || (dataLen % blockSize != 0)) {
+                UcryptoProvider.debug("PKCS5Padding: unpad, buffered " + tbSize +
+                                 " bytes, last block " + lastData.length + " bytes");
+
+                throw new IllegalBlockSizeException
+                    ("Input length must be multiples of " + blockSize);
+            }
+
+            // check padding bytes
+            if (lastData.length == 0) {
+                if (tbSize != 0) {
+                    // work on 'trailingBytes' directly
+                    lastData = Arrays.copyOf(trailingBytes.array(), tbSize);
+                    trailingBytes.clear();
+                    tbSize = 0;
+                } else {
+                    throw new BadPaddingException("No pad bytes found!");
+                }
+            }
+            byte padValue = lastData[lastData.length - 1];
+            if (padValue < 1 || padValue > blockSize) {
+                UcryptoProvider.debug("PKCS5Padding: unpad, lastData: " + Arrays.toString(lastData));
+                UcryptoProvider.debug("PKCS5Padding: unpad, padValue=" + padValue);
+                throw new BadPaddingException("Invalid pad value!");
+            }
+
+            // sanity check padding bytes
+            int padStartIndex = lastData.length - padValue;
+            for (int i = padStartIndex; i < lastData.length; i++) {
+                if (lastData[i] != padValue) {
+                    UcryptoProvider.debug("PKCS5Padding: unpad, lastData: " + Arrays.toString(lastData));
+                    UcryptoProvider.debug("PKCS5Padding: unpad, padValue=" + padValue);
+                    throw new BadPaddingException("Invalid padding bytes!");
+                }
+            }
+
+            int actualOutLen = dataLen - padValue;
+            // check output buffer capacity
+            if (out.length - outOfs < actualOutLen) {
+                throw new ShortBufferException("Output buffer too small, need " + actualOutLen +
+                    ", got " + (out.length - outOfs));
+            }
+            try {
+                if (tbSize != 0) {
+                    trailingBytes.rewind();
+                    if (tbSize < actualOutLen) {
+                        trailingBytes.get(out, outOfs, tbSize);
+                        outOfs += tbSize;
+                    } else {
+                        // copy from trailingBytes and we are done
+                        trailingBytes.get(out, outOfs, actualOutLen);
+                        return actualOutLen;
+                    }
+                }
+                if (lastData.length > padValue) {
+                    System.arraycopy(lastData, 0, out, outOfs,
+                                     lastData.length - padValue);
+                }
+                return actualOutLen;
+            } finally {
+                clear();
+            }
+        }
+
+        public void clear() {
+            if (trailingBytes != null) trailingBytes.clear();
+        }
+    }
+
+    public static final class AesEcbPKCS5 extends NativeCipherWithJavaPadding {
+        public AesEcbPKCS5() throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super(new NativeCipher.AesEcbNoPadding(), "PKCS5Padding");
+        }
+    }
+
+    public static final class AesCbcPKCS5 extends NativeCipherWithJavaPadding {
+        public AesCbcPKCS5() throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super(new NativeCipher.AesCbcNoPadding(), "PKCS5Padding");
+        }
+    }
+
+    public static final class AesCfb128PKCS5 extends NativeCipherWithJavaPadding {
+        public AesCfb128PKCS5() throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super(new NativeCipher.AesCfb128NoPadding(), "PKCS5Padding");
+        }
+    }
+
+    // fields (re)set in every init()
+    private final NativeCipher nc;
+    private final Padding padding;
+    private final int blockSize;
+    private int lastBlockLen = 0;
+
+    // Only ECB, CBC, CTR, and CFB128 modes w/ NOPADDING for now
+    NativeCipherWithJavaPadding(NativeCipher nc, String paddingScheme)
+        throws NoSuchAlgorithmException, NoSuchPaddingException {
+        this.nc = nc;
+        this.blockSize = nc.engineGetBlockSize();
+        if (paddingScheme.toUpperCase().equals("PKCS5PADDING")) {
+            padding = new PKCS5Padding(blockSize);
+        } else {
+            throw new NoSuchAlgorithmException("Unsupported padding scheme: " + paddingScheme);
+        }
+    }
+
+    void reset() {
+        padding.clear();
+        lastBlockLen = 0;
+    }
+
+    @Override
+    protected synchronized void engineSetMode(String mode) throws NoSuchAlgorithmException {
+        nc.engineSetMode(mode);
+    }
+
+    // see JCE spec
+    @Override
+    protected void engineSetPadding(String padding)
+            throws NoSuchPaddingException {
+        // Disallow change of padding for now since currently it's explicitly
+        // defined in transformation strings
+        throw new NoSuchPaddingException("Unsupported padding " + padding);
+    }
+
+    // see JCE spec
+    @Override
+    protected int engineGetBlockSize() {
+        return blockSize;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineGetOutputSize(int inputLen) {
+        int result = nc.engineGetOutputSize(inputLen);
+        if (nc.encrypt) {
+            result += padding.getPadLen(result);
+        } else {
+            result += padding.getBufferedLength();
+        }
+        return result;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineGetIV() {
+        return nc.engineGetIV();
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized AlgorithmParameters engineGetParameters() {
+        return nc.engineGetParameters();
+    }
+
+    @Override
+    protected int engineGetKeySize(Key key) throws InvalidKeyException {
+        return nc.engineGetKeySize(key);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key key, SecureRandom random)
+            throws InvalidKeyException {
+        reset();
+        nc.engineInit(opmode, key, random);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key key,
+            AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        reset();
+        nc.engineInit(opmode, key, params, random);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key key, AlgorithmParameters params,
+            SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        reset();
+        nc.engineInit(opmode, key, params, random);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
+        if (nc.encrypt) {
+            lastBlockLen += inLen;
+            lastBlockLen &= (blockSize - 1);
+            return nc.engineUpdate(in, inOfs, inLen);
+        } else {
+            return padding.bufferBytes(nc.engineUpdate(in, inOfs, inLen));
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
+            int outOfs) throws ShortBufferException {
+        if (nc.encrypt) {
+            lastBlockLen += inLen;
+            lastBlockLen &= (blockSize - 1);
+            return nc.engineUpdate(in, inOfs, inLen, out, outOfs);
+        } else {
+            byte[] result = padding.bufferBytes(nc.engineUpdate(in, inOfs, inLen));
+            if (result != null) {
+                System.arraycopy(result, 0, out, outOfs, result.length);
+                return result.length;
+            } else return 0;
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+        int estimatedOutLen = engineGetOutputSize(inLen);
+        byte[] out = new byte[estimatedOutLen];
+        try {
+            int actualOut = this.engineDoFinal(in, inOfs, inLen, out, 0);
+            // truncate off extra bytes
+            if (actualOut != out.length) {
+                out = Arrays.copyOf(out, actualOut);
+            }
+        } catch (ShortBufferException sbe) {
+            throw new UcryptoException("Internal Error");
+        } finally {
+            reset();
+        }
+        return out;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
+                                             int outOfs)
+        throws ShortBufferException, IllegalBlockSizeException,
+               BadPaddingException {
+        int estimatedOutLen = engineGetOutputSize(inLen);
+
+        if (out.length - outOfs < estimatedOutLen) {
+            throw new ShortBufferException();
+        }
+        try {
+            if (nc.encrypt) {
+                int k = nc.engineUpdate(in, inOfs, inLen, out, outOfs);
+                lastBlockLen += inLen;
+                lastBlockLen &= (blockSize - 1);
+                byte[] padBytes = padding.getPaddingBytes(lastBlockLen);
+                k += nc.engineDoFinal(padBytes, 0, padBytes.length, out, (outOfs + k));
+                return k;
+            } else {
+                byte[] tempOut = nc.engineDoFinal(in, inOfs, inLen);
+                int len = padding.unpad(tempOut, out, outOfs);
+                return len;
+            }
+        } finally {
+            reset();
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineWrap(Key key) throws IllegalBlockSizeException,
+                                                InvalidKeyException {
+        byte[] result = null;
+        try {
+            byte[] encodedKey = key.getEncoded();
+            if ((encodedKey == null) || (encodedKey.length == 0)) {
+                throw new InvalidKeyException("Cannot get an encoding of " +
+                                              "the key to be wrapped");
+            }
+            result = engineDoFinal(encodedKey, 0, encodedKey.length);
+        } catch (BadPaddingException e) {
+            // Should never happen for key wrapping
+            throw new UcryptoException("Internal Error", e);
+        }
+        return result;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
+                               int wrappedKeyType)
+        throws InvalidKeyException, NoSuchAlgorithmException {
+
+        byte[] encodedKey;
+        try {
+            encodedKey = engineDoFinal(wrappedKey, 0,
+                                       wrappedKey.length);
+        } catch (Exception e) {
+            throw (InvalidKeyException)
+                (new InvalidKeyException()).initCause(e);
+        }
+
+        return NativeCipher.constructKey(wrappedKeyType, encodedKey,
+                                         wrappedKeyAlgorithm);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeDigest.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,243 @@
+/*
+ * 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.
+ */
+
+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. This class currently supports
+ * MD5, SHA1, SHA256, SHA384, and SHA512
+ *
+ * @since 1.9
+ */
+public abstract class NativeDigest 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<NativeDigest>
+        implements Comparable<DigestContextRef> {
+
+        private static ReferenceQueue<NativeDigest> refQueue =
+            new ReferenceQueue<NativeDigest>();
+
+        // 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(NativeDigest 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);
+                    NativeDigest.nativeFree(mech, id);
+                } else UcryptoProvider.debug("Resource: stop tracking Digest Ctxt " + this.id);
+            } finally {
+                this.clear();
+            }
+        }
+    }
+
+    NativeDigest(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");
+            }
+            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");
+        }
+        if ((ofs < 0) || (len < 0) || (ofs > out.length - len)) {
+            throw new DigestException("Buffer too short to store digest");
+        }
+
+        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();
+        }
+        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 {
+        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;
+    }
+
+    // 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);
+    // 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);
+    // 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,422 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+
+import java.util.Set;
+import java.util.Arrays;
+import java.security.*;
+import java.security.spec.*;
+import javax.crypto.*;
+import javax.crypto.spec.SecretKeySpec;
+import javax.crypto.spec.GCMParameterSpec;
+
+/**
+ * Cipher wrapper class utilizing ucrypto APIs. This class currently supports
+ * - AES/GCM/NoPADDING
+ *
+ * @since 1.9
+ */
+class NativeGCMCipher extends NativeCipher {
+
+    public static final class AesGcmNoPadding extends NativeGCMCipher {
+        public AesGcmNoPadding() throws NoSuchAlgorithmException {
+            super(-1);
+        }
+    }
+    public static final class Aes128GcmNoPadding extends NativeGCMCipher {
+        public Aes128GcmNoPadding() throws NoSuchAlgorithmException {
+            super(16);
+        }
+    }
+    public static final class Aes192GcmNoPadding extends NativeGCMCipher {
+        public Aes192GcmNoPadding() throws NoSuchAlgorithmException {
+            super(24);
+        }
+    }
+    public static final class Aes256GcmNoPadding extends NativeGCMCipher {
+        public Aes256GcmNoPadding() throws NoSuchAlgorithmException {
+            super(32);
+        }
+    }
+
+    private static final int DEFAULT_TAG_LEN = 128; // same as SunJCE provider
+
+    // buffer for storing AAD data; if null, meaning buffer content has been
+    // supplied to native context
+    private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream();
+
+    // buffer for storing input in decryption, not used for encryption
+    private ByteArrayOutputStream ibuffer = null;
+
+    private int tagLen = DEFAULT_TAG_LEN;
+
+    /*
+     * variables used for performing the GCM (key+iv) uniqueness check.
+     * To use GCM mode safely, the cipher object must be re-initialized
+     * with a different combination of key + iv values for each
+     * ENCRYPTION operation. However, checking all past key + iv values
+     * isn't feasible. Thus, we only do a per-instance check of the
+     * key + iv values used in previous encryption.
+     * For decryption operations, no checking is necessary.
+     */
+    private boolean requireReinit = false;
+    private byte[] lastEncKey = null;
+    private byte[] lastEncIv = null;
+
+    NativeGCMCipher(int fixedKeySize) throws NoSuchAlgorithmException {
+        super(UcryptoMech.CRYPTO_AES_GCM, fixedKeySize);
+    }
+
+    @Override
+    protected void ensureInitialized() {
+        if (!initialized) {
+            if (aadBuffer != null && aadBuffer.size() > 0) {
+                init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+                aadBuffer = null;
+            } else {
+                init(encrypt, keyValue, iv, tagLen, null);
+            }
+            if (!initialized) {
+                throw new UcryptoException("Cannot initialize Cipher");
+            }
+        }
+    }
+
+    @Override
+    protected int getOutputSizeByOperation(int inLen, boolean isDoFinal) {
+        if (inLen < 0) return 0;
+
+        if (!isDoFinal && (inLen == 0)) {
+            return 0;
+        }
+
+        int result = inLen + bytesBuffered;
+        if (encrypt) {
+            if (isDoFinal) {
+                result += tagLen/8;
+            }
+        } else {
+            if (ibuffer != null) {
+                result += ibuffer.size();
+            }
+            if (isDoFinal) {
+                result -= tagLen/8;
+            }
+        }
+        if (result < 0) {
+            result = 0;
+        }
+        return result;
+    }
+
+    @Override
+    protected void reset(boolean doCancel) {
+        super.reset(doCancel);
+        if (aadBuffer == null) {
+            aadBuffer = new ByteArrayOutputStream();
+        } else {
+            aadBuffer.reset();
+        }
+
+        if (ibuffer != null) {
+            ibuffer.reset();
+        }
+        if (!encrypt) requireReinit = false;
+    }
+
+    // actual init() implementation - caller should clone key and iv if needed
+    protected void init(boolean encrypt, byte[] keyVal, byte[] ivVal, int tLen, byte[] aad) {
+        reset(true);
+        this.encrypt = encrypt;
+        this.keyValue = keyVal;
+        this.iv = ivVal;
+        long pCtxtVal = NativeCipher.nativeInit(mech.value(), encrypt, keyValue, iv,
+            tLen, aad);
+        initialized = (pCtxtVal != 0L);
+        if (initialized) {
+            pCtxt = new CipherContextRef(this, pCtxtVal, encrypt);
+        } else {
+            throw new UcryptoException("Cannot initialize Cipher");
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized AlgorithmParameters engineGetParameters() {
+        AlgorithmParameters params = null;
+        try {
+            if (iv != null) {
+                GCMParameterSpec gcmSpec = new GCMParameterSpec(tagLen, iv.clone());
+                params = AlgorithmParameters.getInstance("GCM");
+                params.init(gcmSpec);
+            }
+        } catch (GeneralSecurityException e) {
+            // NoSuchAlgorithmException, NoSuchProviderException
+            // InvalidParameterSpecException
+            throw new UcryptoException("Could not encode parameters", e);
+        }
+        return params;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key key,
+            AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        checkKey(key);
+        if (opmode != Cipher.ENCRYPT_MODE &&
+            opmode != Cipher.DECRYPT_MODE &&
+            opmode != Cipher.WRAP_MODE &&
+            opmode != Cipher.UNWRAP_MODE) {
+            throw new InvalidAlgorithmParameterException
+                ("Unsupported mode: " + opmode);
+        }
+        boolean doEncrypt = (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE);
+        byte[] keyBytes = key.getEncoded().clone();
+        byte[] ivBytes = null;
+        if (params != null) {
+            if (!(params instanceof GCMParameterSpec)) {
+                throw new InvalidAlgorithmParameterException("GCMParameterSpec required");
+            } else {
+                tagLen = ((GCMParameterSpec) params).getTLen();
+                ivBytes = ((GCMParameterSpec) params).getIV();
+            }
+        } else {
+            if (doEncrypt) {
+                tagLen = DEFAULT_TAG_LEN;
+
+                // generate IV if none supplied for encryption
+                ivBytes = new byte[blockSize];
+                new SecureRandom().nextBytes(ivBytes);
+            } else {
+                throw new InvalidAlgorithmParameterException("Parameters required for decryption");
+            }
+        }
+        if (doEncrypt) {
+            requireReinit = Arrays.equals(ivBytes, lastEncIv) &&
+                Arrays.equals(keyBytes, lastEncKey);
+            if (requireReinit) {
+                throw new InvalidAlgorithmParameterException
+                    ("Cannot reuse iv for GCM encryption");
+            }
+            lastEncIv = ivBytes;
+            lastEncKey = keyBytes;
+        } else {
+            requireReinit = false;
+            ibuffer = new ByteArrayOutputStream();
+        }
+        init(doEncrypt, keyBytes, ivBytes, tagLen, null);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key key, AlgorithmParameters params,
+            SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        AlgorithmParameterSpec spec = null;
+        if (params != null) {
+            try {
+                // mech must be UcryptoMech.CRYPTO_AES_GCM
+                spec = params.getParameterSpec(GCMParameterSpec.class);
+            } catch (InvalidParameterSpecException iaps) {
+                throw new InvalidAlgorithmParameterException(iaps);
+            }
+        }
+        engineInit(opmode, key, spec, random);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
+        if (aadBuffer != null && aadBuffer.size() > 0) {
+            // init again with AAD data
+            init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+            aadBuffer = null;
+        }
+        if (requireReinit) {
+            throw new IllegalStateException
+                ("Must use either different key or iv for GCM encryption");
+        }
+        if (inLen > 0) {
+            if (!encrypt) {
+                ibuffer.write(in, inOfs, inLen);
+                return null;
+            }
+            return super.engineUpdate(in, inOfs, inLen);
+        } else return null;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
+            int outOfs) throws ShortBufferException {
+        int len = getOutputSizeByOperation(inLen, false);
+        if (out.length - outOfs < len) {
+            throw new ShortBufferException("Output buffer must be "
+                                           + "(at least) " + len
+                                           + " bytes long");
+        }
+        if (aadBuffer != null && aadBuffer.size() > 0) {
+            // init again with AAD data
+            init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+            aadBuffer = null;
+        }
+        if (requireReinit) {
+            throw new IllegalStateException
+                ("Must use either different key or iv for GCM encryption");
+        }
+        if (inLen > 0) {
+            if (!encrypt) {
+                ibuffer.write(in, inOfs, inLen);
+                return 0;
+            } else {
+                return super.engineUpdate(in, inOfs, inLen, out, outOfs);
+            }
+        }
+        return 0;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineUpdateAAD(byte[] src, int srcOfs, int srcLen)
+            throws IllegalStateException {
+
+        if ((src == null) || (srcOfs < 0) || (srcOfs + srcLen > src.length)) {
+            throw new IllegalArgumentException("Invalid AAD");
+        }
+        if (keyValue == null) {
+            throw new IllegalStateException("Need to initialize Cipher first");
+        }
+        if (requireReinit) {
+            throw new IllegalStateException
+                ("Must use either different key or iv for GCM encryption");
+        }
+        if (aadBuffer != null) {
+            aadBuffer.write(src, srcOfs, srcLen);
+        } else {
+            // update has already been called
+            throw new IllegalStateException
+                ("Update has been called; no more AAD data");
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected void engineUpdateAAD(ByteBuffer src)
+            throws IllegalStateException {
+        if (src == null) {
+            throw new IllegalArgumentException("Invalid AAD");
+        }
+        if (keyValue == null) {
+            throw new IllegalStateException("Need to initialize Cipher first");
+        }
+        if (requireReinit) {
+            throw new IllegalStateException
+                ("Must use either different key or iv for GCM encryption");
+        }
+        if (aadBuffer != null) {
+            if (src.hasRemaining()) {
+                byte[] srcBytes = new byte[src.remaining()];
+                src.get(srcBytes);
+                aadBuffer.write(srcBytes, 0, srcBytes.length);
+            }
+        } else {
+            // update has already been called
+            throw new IllegalStateException
+                ("Update has been called; no more AAD data");
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+        byte[] out = new byte[getOutputSizeByOperation(inLen, true)];
+        try {
+            // delegate to the other engineDoFinal(...) method
+            int k = engineDoFinal(in, inOfs, inLen, out, 0);
+            if (out.length != k) {
+                out = Arrays.copyOf(out, k);
+            }
+            return out;
+        } catch (ShortBufferException e) {
+            throw new UcryptoException("Internal Error", e);
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineDoFinal(byte[] in, int inOfs, int inLen,
+                                             byte[] out, int outOfs)
+        throws ShortBufferException, IllegalBlockSizeException,
+               BadPaddingException {
+        int len = getOutputSizeByOperation(inLen, true);
+        if (out.length - outOfs < len) {
+            throw new ShortBufferException("Output buffer must be "
+                                           + "(at least) " + len
+                                           + " bytes long");
+        }
+        if (aadBuffer != null && aadBuffer.size() > 0) {
+            // init again with AAD data
+            init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray());
+            aadBuffer = null;
+        }
+        if (requireReinit) {
+            throw new IllegalStateException
+                ("Must use either different key or iv for GCM encryption");
+        }
+        if (!encrypt) {
+            if (inLen > 0) {
+                ibuffer.write(in, inOfs, inLen);
+            }
+            inLen = ibuffer.size();
+            if (inLen < tagLen/8) {
+                // Otherwise, Solaris lib will error out w/ CRYPTO_BUFFER_TOO_SMALL
+                // when ucrypto_decrypt_final() is called
+                throw new AEADBadTagException("Input too short - need tag");
+            }
+            // refresh 'in' to all buffered-up bytes
+            in = ibuffer.toByteArray();
+            inOfs = 0;
+            ibuffer.reset();
+        }
+        try {
+            return super.engineDoFinal(in, inOfs, inLen, out, outOfs);
+        } catch (UcryptoException ue) {
+            if (ue.getMessage().equals("CRYPTO_INVALID_MAC")) {
+                throw new AEADBadTagException("Tag does not match");
+            } else {
+                // pass it up
+                throw ue;
+            }
+        } finally {
+            requireReinit = encrypt;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeKey.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.util.Set;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.lang.ref.*;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Key;
+import java.security.PublicKey;
+import java.security.PrivateKey;
+import java.security.KeyFactorySpi;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+/**
+ * Wrapper class for native keys needed for using ucrypto APIs.
+ * This class currently supports native RSA private/public keys.
+ *
+ * @since 1.9
+ */
+abstract class NativeKey implements Key {
+
+    private static final long serialVersionUID = 6812507588904302830L;
+
+    private final int numComponents;
+
+    NativeKey(int numComponents) {
+        this.numComponents = numComponents;
+    }
+
+    abstract long value();
+
+    int length() {
+        return numComponents;
+    }
+
+    public String getAlgorithm() { return "RSA"; }
+    public String getFormat() { return "RAW"; }
+    public byte[] getEncoded() {
+        // not used; so not generated
+        return null;
+    }
+
+    private native static void nativeFree(long id, int numComponents);
+
+    static byte[] getMagnitude(BigInteger bi) {
+        byte[] b = bi.toByteArray();
+        if ((b.length > 1) && (b[0] == 0)) {
+            int n = b.length - 1;
+            byte[] newarray = new byte[n];
+            System.arraycopy(b, 1, newarray, 0, n);
+            b = newarray;
+        }
+        return b;
+    }
+
+    static final class RSAPrivateCrt extends NativeKey implements RSAPrivateCrtKey {
+
+        private static final long serialVersionUID = 6812507588904302831L;
+
+        private final RSAPrivateCrtKeySpec keySpec;
+        private final long keyId;
+
+        RSAPrivateCrt(KeySpec keySpec) throws InvalidKeySpecException {
+            super(8);
+            long pKey = 0L;
+            if (keySpec instanceof RSAPrivateCrtKeySpec) {
+                RSAPrivateCrtKeySpec ks = (RSAPrivateCrtKeySpec) keySpec;
+                BigInteger mod = ks.getModulus();
+                BigInteger publicExp =  ks.getPublicExponent();
+                BigInteger privateExp =  ks.getPrivateExponent();
+                BigInteger primeP = ks.getPrimeP();
+                BigInteger primeQ = ks.getPrimeQ();
+                BigInteger primeExpP = ks.getPrimeExponentP();
+                BigInteger primeExpQ = ks.getPrimeExponentQ();
+                BigInteger crtCoeff = ks.getCrtCoefficient();
+                pKey = nativeInit(NativeKey.getMagnitude(mod),
+                                  NativeKey.getMagnitude(publicExp),
+                                  NativeKey.getMagnitude(privateExp),
+                                  NativeKey.getMagnitude(primeP),
+                                  NativeKey.getMagnitude(primeQ),
+                                  NativeKey.getMagnitude(primeExpP),
+                                  NativeKey.getMagnitude(primeExpQ),
+                                  NativeKey.getMagnitude(crtCoeff));
+            } else {
+                throw new InvalidKeySpecException("Only supports RSAPrivateCrtKeySpec");
+            }
+            if (pKey == 0L) {
+                throw new UcryptoException("Error constructing RSA PrivateKey");
+            }
+            // track native resource clean up
+            new KeyRef(this, pKey);
+            this.keySpec = (RSAPrivateCrtKeySpec) keySpec;
+            this.keyId = pKey;
+        }
+
+        long value() { return keyId; }
+        public BigInteger getModulus() { return keySpec.getModulus(); };
+        public BigInteger getPublicExponent() { return keySpec.getPublicExponent(); };
+        public BigInteger getPrivateExponent() { return keySpec.getPrivateExponent(); };
+        public BigInteger getPrimeP() { return keySpec.getPrimeP(); };
+        public BigInteger getPrimeQ() { return keySpec.getPrimeQ(); };
+        public BigInteger getPrimeExponentP() { return keySpec.getPrimeExponentP(); };
+        public BigInteger getPrimeExponentQ() { return keySpec.getPrimeExponentQ(); };
+        public BigInteger getCrtCoefficient() { return keySpec.getCrtCoefficient(); };
+
+        private native static long nativeInit(byte[] mod, byte[] pubExp, byte[] privExp,
+                                      byte[] p, byte[] q,
+                                      byte[] expP, byte[] expQ, byte[] crtCoeff);
+    }
+
+    static final class RSAPublic extends NativeKey implements RSAPublicKey {
+
+        private static final long serialVersionUID = 6812507588904302832L;
+
+        private final RSAPublicKeySpec keySpec;
+        private final long keyId;
+
+        RSAPublic(KeySpec keySpec) throws InvalidKeySpecException {
+            super(2);
+            long pKey = 0L;
+            if (keySpec instanceof RSAPublicKeySpec) {
+                RSAPublicKeySpec ks = (RSAPublicKeySpec) keySpec;
+                BigInteger mod = ks.getModulus();
+                BigInteger publicExp = ks.getPublicExponent();
+                pKey = nativeInit(NativeKey.getMagnitude(mod),
+                                  NativeKey.getMagnitude(publicExp));
+            } else {
+                throw new InvalidKeySpecException("Only supports RSAPublicKeySpec");
+            }
+            if (pKey == 0L) {
+                throw new UcryptoException("Error constructing RSA PublicKey");
+            }
+            // track native resource clean up
+            new KeyRef(this, pKey);
+            this.keySpec = (RSAPublicKeySpec) keySpec;
+            this.keyId = pKey;
+        }
+
+        long value() { return keyId; }
+        public BigInteger getModulus() { return keySpec.getModulus(); };
+        public BigInteger getPublicExponent() { return keySpec.getPublicExponent(); };
+
+        private native static long nativeInit(byte[] mod, byte[] pubExp);
+    }
+
+    // internal class for native resource cleanup
+    private static class KeyRef extends PhantomReference<NativeKey>
+        implements Comparable<KeyRef> {
+
+        private static ReferenceQueue<NativeKey> refQueue =
+            new ReferenceQueue<NativeKey>();
+
+        // 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<KeyRef> refList =
+            new ConcurrentSkipListSet<KeyRef>();
+
+        private final long id;
+        private final int length;
+
+        private static void drainRefQueueBounded() {
+            while (true) {
+                KeyRef next = (KeyRef) refQueue.poll();
+                if (next == null) break;
+                next.dispose();
+            }
+        }
+
+        KeyRef(NativeKey nk, long id) {
+            super(nk, refQueue);
+            this.id = id;
+            this.length = nk.length();
+            refList.add(this);
+            UcryptoProvider.debug("Resource: track NativeKey " + this.id);
+            drainRefQueueBounded();
+        }
+
+        public int compareTo(KeyRef other) {
+            if (this.id == other.id) {
+                return 0;
+            } else {
+                return (this.id < other.id) ? -1 : 1;
+            }
+        }
+
+        void dispose() {
+            refList.remove(this);
+            UcryptoProvider.debug("Resource: free NativeKey " + this.id);
+            try {
+                NativeKey.nativeFree(id, length);
+            } finally {
+                this.clear();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSACipher.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,448 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.util.Arrays;
+import java.util.WeakHashMap;
+import java.util.Collections;
+import java.util.Map;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PublicKey;
+import java.security.PrivateKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.InvalidKeySpecException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
+import sun.security.util.KeyUtil;
+
+/**
+ * Asymmetric Cipher wrapper class utilizing ucrypto APIs. This class
+ * currently supports
+ * - RSA/ECB/NOPADDING
+ * - RSA/ECB/PKCS1PADDING
+ *
+ * @since 1.9
+ */
+public class NativeRSACipher extends CipherSpi {
+    // fields set in constructor
+    private final UcryptoMech mech;
+    private final int padLen;
+    private final NativeRSAKeyFactory keyFactory;
+    private AlgorithmParameterSpec spec;
+    private SecureRandom random;
+
+    // Keep a cache of RSA keys and their RSA NativeKey for reuse.
+    // When the RSA key is gc'ed, we let NativeKey phatom references cleanup
+    // the native allocation
+    private static final Map<Key, NativeKey> keyList =
+            Collections.synchronizedMap(new WeakHashMap<Key, NativeKey>());
+
+    //
+    // fields (re)set in every init()
+    //
+    private NativeKey key = null;
+    private int outputSize = 0; // e.g. modulus size in bytes
+    private boolean encrypt = true;
+    private byte[] buffer;
+    private int bufOfs = 0;
+
+    // public implementation classes
+    public static final class NoPadding extends NativeRSACipher {
+        public NoPadding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_RSA_X_509, 0);
+        }
+    }
+
+    public static final class PKCS1Padding extends NativeRSACipher {
+        public PKCS1Padding() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_RSA_PKCS, 11);
+        }
+    }
+
+    NativeRSACipher(UcryptoMech mech, int padLen)
+        throws NoSuchAlgorithmException {
+        this.mech = mech;
+        this.padLen = padLen;
+        this.keyFactory = new NativeRSAKeyFactory();
+    }
+
+    @Override
+    protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+        // Disallow change of mode for now since currently it's explicitly
+        // defined in transformation strings
+        throw new NoSuchAlgorithmException("Unsupported mode " + mode);
+    }
+
+    // see JCE spec
+    @Override
+    protected void engineSetPadding(String padding)
+            throws NoSuchPaddingException {
+        // Disallow change of padding for now since currently it's explicitly
+        // defined in transformation strings
+        throw new NoSuchPaddingException("Unsupported padding " + padding);
+    }
+
+    // see JCE spec
+    @Override
+    protected int engineGetBlockSize() {
+        return 0;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineGetOutputSize(int inputLen) {
+        return outputSize;
+    }
+
+    // see JCE spec
+    @Override
+    protected byte[] engineGetIV() {
+        return null;
+    }
+
+    // see JCE spec
+    @Override
+    protected AlgorithmParameters engineGetParameters() {
+        return null;
+    }
+
+    @Override
+    protected int engineGetKeySize(Key key) throws InvalidKeyException {
+        if (!(key instanceof RSAKey)) {
+            throw new InvalidKeyException("RSAKey required");
+        }
+        int n = ((RSAKey)key).getModulus().bitLength();
+        // strip off the leading extra 0x00 byte prefix
+        int realByteSize = (n + 7) >> 3;
+        return realByteSize * 8;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key key, SecureRandom random)
+            throws InvalidKeyException {
+        try {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        } catch (InvalidAlgorithmParameterException e) {
+            throw new InvalidKeyException("init() failed", e);
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key newKey,
+            AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (newKey == null) {
+            throw new InvalidKeyException("Key cannot be null");
+        }
+        if (opmode != Cipher.ENCRYPT_MODE &&
+            opmode != Cipher.DECRYPT_MODE &&
+            opmode != Cipher.WRAP_MODE &&
+            opmode != Cipher.UNWRAP_MODE) {
+            throw new InvalidAlgorithmParameterException
+                ("Unsupported mode: " + opmode);
+        }
+        if (params != null) {
+            if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
+                throw new InvalidAlgorithmParameterException(
+                        "No Parameters can be specified");
+            }
+            spec = params;
+            this.random = random;   // for TLS RSA premaster secret
+        }
+        boolean doEncrypt = (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE);
+
+        // Make sure the proper opmode uses the proper key
+        if (doEncrypt && (!(newKey instanceof RSAPublicKey))) {
+            throw new InvalidKeyException("RSAPublicKey required for encryption");
+        } else if (!doEncrypt && (!(newKey instanceof RSAPrivateCrtKey))) {
+            throw new InvalidKeyException("RSAPrivateCrtKey required for decryption");
+        }
+
+        NativeKey nativeKey = null;
+        // Check keyList cache for a nativeKey
+        nativeKey = keyList.get(newKey);
+        if (nativeKey == null) {
+            // With no existing nativeKey for this newKey, create one
+            if (doEncrypt) {
+                RSAPublicKey publicKey = (RSAPublicKey) newKey;
+                try {
+                    nativeKey = (NativeKey) keyFactory.engineGeneratePublic
+                        (new RSAPublicKeySpec(publicKey.getModulus(), publicKey.getPublicExponent()));
+                } catch (InvalidKeySpecException ikse) {
+                    throw new InvalidKeyException(ikse);
+                }
+            } else {
+                RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) newKey;
+                try {
+                    nativeKey = (NativeKey) keyFactory.engineGeneratePrivate
+                        (new RSAPrivateCrtKeySpec(privateKey.getModulus(),
+                                                  privateKey.getPublicExponent(),
+                                                  privateKey.getPrivateExponent(),
+                                                  privateKey.getPrimeP(),
+                                                  privateKey.getPrimeQ(),
+                                                  privateKey.getPrimeExponentP(),
+                                                  privateKey.getPrimeExponentQ(),
+                                                  privateKey.getCrtCoefficient()));
+                } catch (InvalidKeySpecException ikse) {
+                    throw new InvalidKeyException(ikse);
+                }
+            }
+
+            // Add nativeKey to keyList cache and associate it with newKey
+            keyList.put(newKey, nativeKey);
+        }
+
+        init(doEncrypt, nativeKey);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized void engineInit(int opmode, Key key, AlgorithmParameters params,
+            SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (params != null) {
+            throw new InvalidAlgorithmParameterException("No Parameters can be specified");
+        }
+        engineInit(opmode, key, (AlgorithmParameterSpec) null, random);
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
+        if (inLen > 0) {
+            update(in, inOfs, inLen);
+        }
+        return null;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
+            int outOfs) throws ShortBufferException {
+        if (out.length - outOfs < outputSize) {
+            throw new ShortBufferException("Output buffer too small");
+        }
+        if (inLen > 0) {
+            update(in, inOfs, inLen);
+        }
+        return 0;
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+        byte[] out = new byte[outputSize];
+        try {
+            // delegate to the other engineDoFinal(...) method
+            int actualLen = engineDoFinal(in, inOfs, inLen, out, 0);
+            if (actualLen != outputSize) {
+                return Arrays.copyOf(out, actualLen);
+            } else {
+                return out;
+            }
+        } catch (ShortBufferException e) {
+            throw new UcryptoException("Internal Error", e);
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
+                                             int outOfs)
+        throws ShortBufferException, IllegalBlockSizeException,
+               BadPaddingException {
+        if (inLen != 0) {
+            update(in, inOfs, inLen);
+        }
+        return doFinal(out, outOfs, out.length - outOfs);
+    }
+
+
+    // see JCE spec
+    @Override
+    protected synchronized byte[] engineWrap(Key key) throws IllegalBlockSizeException,
+                                                             InvalidKeyException {
+        try {
+            byte[] encodedKey = key.getEncoded();
+            if ((encodedKey == null) || (encodedKey.length == 0)) {
+                throw new InvalidKeyException("Cannot get an encoding of " +
+                                              "the key to be wrapped");
+            }
+            if (encodedKey.length > buffer.length) {
+                throw new InvalidKeyException("Key is too long for wrapping");
+            }
+            return engineDoFinal(encodedKey, 0, encodedKey.length);
+        } catch (BadPaddingException e) {
+            // Should never happen for key wrapping
+            throw new UcryptoException("Internal Error", e);
+        }
+    }
+
+    // see JCE spec
+    @Override
+    protected synchronized Key engineUnwrap(byte[] wrappedKey,
+            String wrappedKeyAlgorithm, int wrappedKeyType)
+            throws InvalidKeyException, NoSuchAlgorithmException {
+
+        if (wrappedKey.length > buffer.length) {
+            throw new InvalidKeyException("Key is too long for unwrapping");
+        }
+
+        boolean isTlsRsaPremasterSecret =
+                wrappedKeyAlgorithm.equals("TlsRsaPremasterSecret");
+        Exception failover = null;
+
+        byte[] encodedKey = null;
+        try {
+            encodedKey = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+        } catch (BadPaddingException bpe) {
+            if (isTlsRsaPremasterSecret) {
+                failover = bpe;
+            } else {
+                throw new InvalidKeyException("Unwrapping failed", bpe);
+            }
+        } catch (Exception e) {
+            throw new InvalidKeyException("Unwrapping failed", e);
+        }
+
+        if (isTlsRsaPremasterSecret) {
+            if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
+                throw new IllegalStateException(
+                        "No TlsRsaPremasterSecretParameterSpec specified");
+            }
+
+            // polish the TLS premaster secret
+            encodedKey = KeyUtil.checkTlsPreMasterSecretKey(
+                ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(),
+                ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(),
+                random, encodedKey, (failover != null));
+        }
+
+        return NativeCipher.constructKey(wrappedKeyType,
+                encodedKey, wrappedKeyAlgorithm);
+    }
+
+    /**
+     * calls ucrypto_encrypt(...) or ucrypto_decrypt(...)
+     * @returns the length of output or an negative error status code
+     */
+    private native static int nativeAtomic(int mech, boolean encrypt,
+                                           long keyValue, int keyLength,
+                                           byte[] in, int inLen,
+                                           byte[] out, int ouOfs, int outLen);
+
+    // do actual initialization
+    private void init(boolean encrypt, NativeKey key) {
+        this.encrypt = encrypt;
+        this.key = key;
+        try {
+            this.outputSize = engineGetKeySize(key)/8;
+        } catch (InvalidKeyException ike) {
+            throw new UcryptoException("Internal Error", ike);
+        }
+        this.buffer = new byte[outputSize];
+        this.bufOfs = 0;
+    }
+
+    // store the specified input into the internal buffer
+    private void update(byte[] in, int inOfs, int inLen) {
+        if ((inLen <= 0) || (in == null)) {
+            return;
+        }
+        // buffer bytes internally until doFinal is called
+        if ((bufOfs + inLen + (encrypt? padLen:0)) > buffer.length) {
+            // lead to IllegalBlockSizeException when doFinal() is called
+            bufOfs = buffer.length + 1;
+            return;
+        }
+        System.arraycopy(in, inOfs, buffer, bufOfs, inLen);
+        bufOfs += inLen;
+    }
+
+    // return the actual non-negative output length
+    private int doFinal(byte[] out, int outOfs, int outLen)
+            throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        if (bufOfs > buffer.length) {
+            throw new IllegalBlockSizeException(
+                "Data must not be longer than " +
+                (buffer.length - (encrypt ? padLen : 0)) + " bytes");
+        }
+        if (outLen < outputSize) {
+            throw new ShortBufferException();
+        }
+        try {
+            long keyValue = key.value();
+            int k = nativeAtomic(mech.value(), encrypt, keyValue,
+                                 key.length(), buffer, bufOfs,
+                                 out, outOfs, outLen);
+            if (k < 0) {
+                if ( k == -16 || k == -64) {
+                    // -16: CRYPTO_ENCRYPTED_DATA_INVALID
+                    // -64: CKR_ENCRYPTED_DATA_INVALID, see bug 17459266
+                    UcryptoException ue = new UcryptoException(16);
+                    BadPaddingException bpe =
+                        new BadPaddingException("Invalid encryption data");
+                    bpe.initCause(ue);
+                    throw bpe;
+                }
+                throw new UcryptoException(-k);
+            }
+
+            return k;
+        } finally {
+            bufOfs = 0;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSAKeyFactory.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.util.Set;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.lang.ref.*;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Key;
+import java.security.PublicKey;
+import java.security.PrivateKey;
+import java.security.KeyFactorySpi;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+/**
+ * Ucrypto-private KeyFactory class for generating native keys
+ * needed for using ucrypto APIs. Given that it's not used
+ * externally, it only needs to support RSAPrivateCrtKeySpec
+ * and RSAPublicKeySpec objects.
+ *
+ * @since 1.9
+ */
+public final class NativeRSAKeyFactory extends KeyFactorySpi {
+
+    @Override
+    protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+        throws InvalidKeySpecException {
+        return new NativeKey.RSAPrivateCrt(keySpec);
+    }
+
+    @Override
+    protected PublicKey engineGeneratePublic(KeySpec keySpec)
+        throws InvalidKeySpecException {
+        return new NativeKey.RSAPublic(keySpec);
+    }
+
+    @Override
+    protected <T extends KeySpec> T
+        engineGetKeySpec(Key key, Class<T> keySpec)
+            throws InvalidKeySpecException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+        // no need to support this
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,445 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.util.Set;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.lang.ref.*;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+import java.security.SignatureSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.InvalidParameterException;
+import java.security.InvalidKeyException;
+import java.security.SignatureException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import sun.nio.ch.DirectBuffer;
+import java.nio.ByteBuffer;
+import sun.security.rsa.RSAPadding;
+
+/**
+ * Signature implementation class. This class currently supports the
+ * following algorithms:
+ *
+ * . RSA:
+ *   . MD5withRSA
+ *   . SHA1withRSA
+ *   . SHA256withRSA
+ *   . SHA384withRSA
+ *   . SHA512withRSA
+ *
+ * @since 1.9
+ */
+class NativeRSASignature extends SignatureSpi {
+
+    private static final int PKCS1PADDING_LEN = 11;
+
+    // fields set in constructor
+    private final UcryptoMech mech;
+    private final int encodedLen;
+
+    // field for ensuring native memory is freed
+    private SignatureContextRef pCtxt = null;
+
+    //
+    // fields (re)set in every init()
+    //
+    private boolean initialized = false;
+    private boolean sign = true;
+    private int sigLength;
+    private NativeKey key;
+    private NativeRSAKeyFactory keyFactory; // may need a more generic type later
+
+    // public implementation classes
+    public static final class MD5 extends NativeRSASignature {
+        public MD5() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_MD5_RSA_PKCS, 34);
+        }
+    }
+
+    public static final class SHA1 extends NativeRSASignature {
+        public SHA1() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_SHA1_RSA_PKCS, 35);
+        }
+    }
+
+    public static final class SHA256 extends NativeRSASignature {
+        public SHA256() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_SHA256_RSA_PKCS, 51);
+        }
+    }
+
+    public static final class SHA384 extends NativeRSASignature {
+        public SHA384() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_SHA384_RSA_PKCS, 67);
+        }
+    }
+
+    public static final class SHA512 extends NativeRSASignature {
+        public SHA512() throws NoSuchAlgorithmException {
+            super(UcryptoMech.CRYPTO_SHA512_RSA_PKCS, 83);
+        }
+    }
+
+    // internal class for native resource cleanup
+    private static class SignatureContextRef extends PhantomReference<NativeRSASignature>
+        implements Comparable<SignatureContextRef> {
+
+        private static ReferenceQueue<NativeRSASignature> refQueue =
+            new ReferenceQueue<NativeRSASignature>();
+
+        // 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<SignatureContextRef> refList =
+            new ConcurrentSkipListSet<SignatureContextRef>();
+        //           Collections.synchronizedSortedSet(new TreeSet<SignatureContextRef>());
+
+        private final long id;
+        private final boolean sign;
+
+        private static void drainRefQueueBounded() {
+            while (true) {
+                SignatureContextRef next = (SignatureContextRef) refQueue.poll();
+                if (next == null) break;
+                next.dispose(true);
+            }
+        }
+
+        SignatureContextRef(NativeRSASignature ns, long id, boolean sign) {
+            super(ns, refQueue);
+            this.id = id;
+            this.sign = sign;
+            refList.add(this);
+            UcryptoProvider.debug("Resource: track Signature Ctxt " + this.id);
+            drainRefQueueBounded();
+        }
+
+        public int compareTo(SignatureContextRef other) {
+            if (this.id == other.id) {
+                return 0;
+            } else {
+                return (this.id < other.id) ? -1 : 1;
+            }
+        }
+
+        void dispose(boolean doCancel) {
+            refList.remove(this);
+            try {
+                if (doCancel) {
+                    UcryptoProvider.debug("Resource: free Signature Ctxt " + this.id);
+                    NativeRSASignature.nativeFinal(id, sign, null, 0, 0);
+                } else {
+                    UcryptoProvider.debug("Resource: stop tracking Signature Ctxt " + this.id);
+                }
+            } finally {
+                this.clear();
+            }
+        }
+    }
+
+    NativeRSASignature(UcryptoMech mech, int encodedLen)
+        throws NoSuchAlgorithmException {
+        this.mech = mech;
+        this.encodedLen = encodedLen;
+        this.keyFactory = new NativeRSAKeyFactory();
+    }
+
+    // deprecated but abstract
+    @SuppressWarnings("deprecation")
+    protected Object engineGetParameter(String param) throws InvalidParameterException {
+        throw new UnsupportedOperationException("getParameter() not supported");
+    }
+
+    @Override
+    protected synchronized void engineInitSign(PrivateKey privateKey)
+            throws InvalidKeyException {
+        if (privateKey == null) {
+            throw new InvalidKeyException("Key must not be null");
+        }
+        NativeKey newKey = key;
+        int newSigLength = sigLength;
+        // Need to check RSA key length whenever a new private key is set
+        if (privateKey != key) {
+            if (privateKey instanceof RSAPrivateCrtKey) {
+                RSAPrivateCrtKey rsaPrivKey = (RSAPrivateCrtKey) privateKey;
+                BigInteger mod = rsaPrivKey.getModulus();
+                newSigLength = checkRSAKeyLength(mod);
+                try {
+                    newKey = (NativeKey) keyFactory.engineGeneratePrivate
+                        (new RSAPrivateCrtKeySpec(mod,
+                                                  rsaPrivKey.getPublicExponent(),
+                                                  rsaPrivKey.getPrivateExponent(),
+                                                  rsaPrivKey.getPrimeP(),
+                                                  rsaPrivKey.getPrimeQ(),
+                                                  rsaPrivKey.getPrimeExponentP(),
+                                                  rsaPrivKey.getPrimeExponentQ(),
+                                                  rsaPrivKey.getCrtCoefficient()));
+                } catch (InvalidKeySpecException ikse) {
+                    throw new InvalidKeyException(ikse);
+                }
+            } else {
+                throw new InvalidKeyException("RSAPrivateCrtKey required");
+            }
+        }
+        init(true, newKey, newSigLength);
+    }
+
+
+    @Override
+    protected synchronized void engineInitVerify(PublicKey publicKey)
+            throws InvalidKeyException {
+        if (publicKey == null) {
+            throw new InvalidKeyException("Key must not be null");
+        }
+        NativeKey newKey = key;
+        int newSigLength = sigLength;
+        // Need to check RSA key length whenever a new public key is set
+        if (publicKey != key) {
+            if (publicKey instanceof RSAPublicKey) {
+                BigInteger mod = ((RSAPublicKey) publicKey).getModulus();
+                newSigLength = checkRSAKeyLength(mod);
+                try {
+                    newKey = (NativeKey) keyFactory.engineGeneratePublic
+                        (new RSAPublicKeySpec(mod, ((RSAPublicKey) publicKey).getPublicExponent()));
+                } catch (InvalidKeySpecException ikse) {
+                    throw new InvalidKeyException(ikse);
+                }
+            } else {
+                throw new InvalidKeyException("RSAPublicKey required");
+            }
+        }
+        init(false, newKey, newSigLength);
+    }
+
+    // deprecated but abstract
+    @SuppressWarnings("deprecation")
+    protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
+        throw new UnsupportedOperationException("setParameter() not supported");
+    }
+
+    @Override
+    protected synchronized byte[] engineSign() throws SignatureException {
+        byte[] sig = new byte[sigLength];
+        int rv = doFinal(sig, 0, sigLength);
+        if (rv < 0) {
+            throw new SignatureException(new UcryptoException(-rv));
+        }
+        return sig;
+    }
+
+    @Override
+    protected synchronized int engineSign(byte[] outbuf, int offset, int len)
+        throws SignatureException {
+        if (outbuf == null || (offset < 0) || (outbuf.length < (offset + sigLength))
+            || (len < sigLength)) {
+            throw new SignatureException("Invalid output buffer");
+        }
+        int rv = doFinal(outbuf, offset, sigLength);
+        if (rv < 0) {
+            throw new SignatureException(new UcryptoException(-rv));
+        }
+        return sigLength;
+    }
+
+    @Override
+    protected synchronized void engineUpdate(byte b) throws SignatureException {
+        byte[] in = { b };
+        int rv = update(in, 0, 1);
+        if (rv < 0) {
+            throw new SignatureException(new UcryptoException(-rv));
+        }
+    }
+
+    @Override
+    protected synchronized void engineUpdate(byte[] in, int inOfs, int inLen)
+            throws SignatureException {
+        if (in == null || inOfs < 0 || inLen == 0) return;
+
+        int rv = update(in, inOfs, inLen);
+        if (rv < 0) {
+            throw new SignatureException(new UcryptoException(-rv));
+        }
+    }
+
+    @Override
+    protected synchronized void engineUpdate(ByteBuffer in) {
+        if (in == null || in.remaining() == 0) return;
+
+        if (in instanceof DirectBuffer == false) {
+            // cannot do better than default impl
+            super.engineUpdate(in);
+            return;
+        }
+        long inAddr = ((DirectBuffer)in).address();
+        int inOfs = in.position();
+        int inLen = in.remaining();
+
+        int rv = update((inAddr + inOfs), inLen);
+        if (rv < 0) {
+            throw new UcryptoException(-rv);
+        }
+        in.position(inOfs + inLen);
+    }
+
+    @Override
+    protected synchronized boolean engineVerify(byte[] sigBytes) throws SignatureException {
+        return engineVerify(sigBytes, 0, sigBytes.length);
+    }
+
+    @Override
+    protected synchronized boolean engineVerify(byte[] sigBytes, int sigOfs, int sigLen)
+        throws SignatureException {
+        if (sigBytes == null || (sigOfs < 0) || (sigBytes.length < (sigOfs + this.sigLength))
+            || (sigLen < this.sigLength)) {
+            throw new SignatureException("Invalid signature buffer");
+        }
+
+        int rv = doFinal(sigBytes, sigOfs, sigLen);
+        if (rv == 0) {
+            return true;
+        } else {
+            UcryptoProvider.debug("Signature: " + mech + " verification error " +
+                             new UcryptoException(-rv).getMessage());
+            return false;
+        }
+    }
+
+    void reset(boolean doCancel) {
+        initialized = false;
+        if (pCtxt != null) {
+            pCtxt.dispose(doCancel);
+            pCtxt = null;
+        }
+    }
+
+    /**
+     * calls ucrypto_sign_init(...) or ucrypto_verify_init(...)
+     * @return pointer to the context
+     */
+    private native static long nativeInit(int mech, boolean sign,
+                                          long keyValue, int keyLength);
+
+    /**
+     * calls ucrypto_sign_update(...) or ucrypto_verify_update(...)
+     * @returns an error status code (0 means SUCCESS)
+     */
+    private native static int nativeUpdate(long pContext, boolean sign,
+                                           byte[] in, int inOfs, int inLen);
+    /**
+     * calls ucrypto_sign_update(...) or ucrypto_verify_update(...)
+     * @returns an error status code (0 means SUCCESS)
+     */
+    private native static int nativeUpdate(long pContext, boolean sign,
+                                           long pIn, int inLen);
+
+    /**
+     * calls ucrypto_sign_final(...) or ucrypto_verify_final(...)
+     * @returns the length of signature bytes or verification status.
+     * If negative, it indicates an error status code
+     */
+    private native static int nativeFinal(long pContext, boolean sign,
+                                          byte[] sig, int sigOfs, int sigLen);
+
+    // actual init() implementation - caller should clone key if needed
+    private void init(boolean sign, NativeKey key, int sigLength) {
+        reset(true);
+        this.sign = sign;
+        this.sigLength = sigLength;
+        this.key = key;
+        long pCtxtVal = nativeInit(mech.value(), sign, key.value(),
+                                   key.length());
+        initialized = (pCtxtVal != 0L);
+        if (initialized) {
+            pCtxt = new SignatureContextRef(this, pCtxtVal, sign);
+        } else {
+            throw new UcryptoException("Cannot initialize Signature");
+        }
+    }
+
+    private void ensureInitialized() {
+        if (!initialized) {
+            init(sign, key, sigLength);
+            if (!initialized) {
+                throw new UcryptoException("Cannot initialize Signature");
+            }
+        }
+    }
+
+    // returns 0 (success) or negative (ucrypto error occurred)
+    private int update(byte[] in, int inOfs, int inLen) {
+        if (inOfs < 0 || inOfs + inLen > in.length) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        ensureInitialized();
+        int k = nativeUpdate(pCtxt.id, sign, in, inOfs, inLen);
+        if (k < 0) {
+            reset(false);
+        }
+        return k;
+    }
+
+    // returns 0 (success) or negative (ucrypto error occurred)
+    private int update(long pIn, int inLen) {
+        ensureInitialized();
+        int k = nativeUpdate(pCtxt.id, sign, pIn, inLen);
+        if (k < 0) {
+            reset(false);
+        }
+        return k;
+    }
+
+    // returns 0 (success) or negative (ucrypto error occurred)
+    private int doFinal(byte[] sigBytes, int sigOfs, int sigLen) {
+        try {
+            ensureInitialized();
+            int k = nativeFinal(pCtxt.id, sign, sigBytes, sigOfs, sigLen);
+            return k;
+        } finally {
+            reset(false);
+        }
+    }
+
+    // check and return RSA key size in number of bytes
+    private int checkRSAKeyLength(BigInteger mod) throws InvalidKeyException {
+        int keySize = (mod.bitLength() + 7) >> 3;
+        int maxDataSize = keySize - PKCS1PADDING_LEN;
+        if (maxDataSize < encodedLen) {
+            throw new InvalidKeyException
+                ("Key is too short for this signature algorithm");
+        }
+        return keySize;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoException.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.util.*;
+import java.security.ProviderException;
+
+/**
+ * The exception class used by SunUcrypto provider. An exception
+ * object of this class indicates that a function call to the underlying
+ * native calls returned a value not equal to CRYPTO_SUCCESS.
+ *
+ * @since 1.9
+ */
+public final class UcryptoException extends ProviderException {
+
+    private static final long serialVersionUID = -933864511110035746L;
+
+    // NOTE: check /usr/include/sys/crypto/common.h for updates
+    private static final String ERROR_MSG[] = {
+        "CRYPTO_SUCCESS",
+        "CRYPTO_CANCEL",
+        "CRYPTO_HOST_MEMORY",
+        "CRYPTO_GENERAL_ERROR",
+        "CRYPTO_FAILED",
+        "CRYPTO_ARGUMENTS_BAD",
+        "CRYPTO_ATTRIBUTE_READ_ONLY",
+        "CRYPTO_ATTRIBUTE_SENSITIVE",
+        "CRYPTO_ATTRIBUTE_TYPE_INVALID",
+        "CRYPTO_ATTRIBUTE_VALUE_INVALID",
+        "CRYPTO_CANCELED",
+        "CRYPTO_DATA_INVALID",
+        "CRYPTO_DATA_LEN_RANGE",
+        "CRYPTO_DEVICE_ERROR",
+        "CRYPTO_DEVICE_MEMORY",
+        "CRYPTO_DEVICE_REMOVED",
+        "CRYPTO_ENCRYPTED_DATA_INVALID",
+        "CRYPTO_ENCRYPTED_DATA_LEN_RANGE",
+        "CRYPTO_KEY_HANDLE_INVALID",
+        "CRYPTO_KEY_SIZE_RANGE",
+        "CRYPTO_KEY_TYPE_INCONSISTENT",
+        "CRYPTO_KEY_NOT_NEEDED",
+        "CRYPTO_KEY_CHANGED",
+        "CRYPTO_KEY_NEEDED",
+        "CRYPTO_KEY_INDIGESTIBLE",
+        "CRYPTO_KEY_FUNCTION_NOT_PERMITTED",
+        "CRYPTO_KEY_NOT_WRAPPABLE",
+        "CRYPTO_KEY_UNEXTRACTABLE",
+        "CRYPTO_MECHANISM_INVALID",
+        "CRYPTO_MECHANISM_PARAM_INVALID",
+        "CRYPTO_OBJECT_HANDLE_INVALID",
+        "CRYPTO_OPERATION_IS_ACTIVE",
+        "CRYPTO_OPERATION_NOT_INITIALIZED",
+        "CRYPTO_PIN_INCORRECT",
+        "CRYPTO_PIN_INVALID",
+        "CRYPTO_PIN_LEN_RANGE",
+        "CRYPTO_PIN_EXPIRED",
+        "CRYPTO_PIN_LOCKED",
+        "CRYPTO_SESSION_CLOSED",
+        "CRYPTO_SESSION_COUNT",
+        "CRYPTO_SESSION_HANDLE_INVALID",
+        "CRYPTO_SESSION_READ_ONLY",
+        "CRYPTO_SESSION_EXISTS",
+        "CRYPTO_SESSION_READ_ONLY_EXISTS",
+        "CRYPTO_SESSION_READ_WRITE_SO_EXISTS",
+        "CRYPTO_SIGNATURE_INVALID",
+        "CRYPTO_SIGNATURE_LEN_RANGE",
+        "CRYPTO_TEMPLATE_INCOMPLETE",
+        "CRYPTO_TEMPLATE_INCONSISTENT",
+        "CRYPTO_UNWRAPPING_KEY_HANDLE_INVALID",
+        "CRYPTO_UNWRAPPING_KEY_SIZE_RANGE",
+        "CRYPTO_UNWRAPPING_KEY_TYPE_INCONSISTENT",
+        "CRYPTO_USER_ALREADY_LOGGED_IN",
+        "CRYPTO_USER_NOT_LOGGED_IN",
+        "CRYPTO_USER_PIN_NOT_INITIALIZED",
+        "CRYPTO_USER_TYPE_INVALID",
+        "CRYPTO_USER_ANOTHER_ALREADY_LOGGED_IN",
+        "CRYPTO_USER_TOO_MANY_TYPES",
+        "CRYPTO_WRAPPED_KEY_INVALID",
+        "CRYPTO_WRAPPED_KEY_LEN_RANGE",
+        "CRYPTO_WRAPPING_KEY_HANDLE_INVALID",
+        "CRYPTO_WRAPPING_KEY_SIZE_RANGE",
+        "CRYPTO_WRAPPING_KEY_TYPE_INCONSISTENT",
+        "CRYPTO_RANDOM_SEED_NOT_SUPPORTED",
+        "CRYPTO_RANDOM_NO_RNG",
+        "CRYPTO_DOMAIN_PARAMS_INVALID",
+        "CRYPTO_BUFFER_TOO_SMALL",
+        "CRYPTO_INFORMATION_SENSITIVE",
+        "CRYPTO_NOT_SUPPORTED",
+        "CRYPTO_QUEUED",
+        "CRYPTO_BUFFER_TOO_BIG",
+        "CRYPTO_INVALID_CONTEXT",
+        "CRYPTO_INVALID_MAC",
+        "CRYPTO_MECH_NOT_SUPPORTED",
+        "CRYPTO_INCONSISTENT_ATTRIBUTE",
+        "CRYPTO_NO_PERMISSION",
+        "CRYPTO_INVALID_PROVIDER_ID",
+        "CRYPTO_VERSION_MISMATCH",
+        "CRYPTO_BUSY",
+        "CRYPTO_UNKNOWN_PROVIDER",
+        "CRYPTO_MODVERIFICATION_FAILED",
+        "CRYPTO_OLD_CTX_TEMPLATE",
+        "CRYPTO_WEAK_KEY",
+        "CRYPTO_FIPS140_ERROR"
+    };
+
+    /**
+     * The error code if this exception is triggered by a Ucrypto error.
+     */
+    private final int errorCode;
+
+    /**
+     * This method gets the corresponding text error message from a
+     * predefined mapping. If mapping is not found, then it returns the error
+     * code as a hex-string.
+     *
+     * @return The message or the error code; e.g. "CRYPTO_DATA_INVALID" or
+     *         "0x88".
+     */
+    static String getErrorMessage(int errorCode) {
+        String message;
+        if (errorCode < ERROR_MSG.length) {
+            message = ERROR_MSG[errorCode];
+        } else {
+            message = "0x" + Integer.toHexString(errorCode);
+        }
+        return message;
+    }
+
+    /**
+     * Constructor taking the error code as defined for the CRYPTO_* constants
+     */
+    public UcryptoException(int rv) {
+        super(getErrorMessage(rv));
+        this.errorCode = rv;
+    }
+
+    public UcryptoException(String message) {
+        super(message);
+        errorCode = -1;
+    }
+
+    public UcryptoException(String message, Throwable cause) {
+        super(message, cause);
+        errorCode = -1;
+    }
+
+    /**
+     * Returns the Ucrypto error code.
+     *
+     * @return The error code.
+     */
+    public int getErrorCode() {
+        return errorCode;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoMech.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.util.HashMap;
+
+/**
+ * Enum for representing the ucrypto mechanisms.
+ *
+ * @since 1.9
+ */
+// Check /usr/include/libsoftcrypto.h for updates
+public enum UcryptoMech {
+    CRYPTO_AES_ECB(1, new String[]
+        { "Cipher.AES/ECB/NoPadding;com.oracle.security.ucrypto.NativeCipher$AesEcbNoPadding",
+          "Cipher.AES/ECB/PKCS5Padding;com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesEcbPKCS5",
+          "Cipher.AES_128/ECB/NoPadding;com.oracle.security.ucrypto.NativeCipher$Aes128EcbNoPadding",
+          "Alg.Alias.Cipher.2.16.840.1.101.3.4.1.1;AES_128/ECB/NoPadding",
+          "Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.1;AES_128/ECB/NoPadding",
+          "Cipher.AES_192/ECB/NoPadding;com.oracle.security.ucrypto.NativeCipher$Aes192EcbNoPadding",
+          "Alg.Alias.Cipher.2.16.840.1.101.3.4.1.21;AES_192/ECB/NoPadding",
+          "Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.21;AES_192/ECB/NoPadding",
+          "Cipher.AES_256/ECB/NoPadding;com.oracle.security.ucrypto.NativeCipher$Aes256EcbNoPadding",
+          "Alg.Alias.Cipher.2.16.840.1.101.3.4.1.41;AES_256/ECB/NoPadding",
+          "Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.41;AES_256/ECB/NoPadding"
+        }),
+    CRYPTO_AES_CBC(2, new String[]
+        { "Cipher.AES/CBC/NoPadding;com.oracle.security.ucrypto.NativeCipher$AesCbcNoPadding",
+          "Cipher.AES/CBC/PKCS5Padding;com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesCbcPKCS5",
+          "Cipher.AES_128/CBC/NoPadding;com.oracle.security.ucrypto.NativeCipher$Aes128CbcNoPadding",
+          "Alg.Alias.Cipher.2.16.840.1.101.3.4.1.2;AES_128/CBC/NoPadding",
+          "Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.2;AES_128/CBC/NoPadding",
+          "Cipher.AES_192/CBC/NoPadding;com.oracle.security.ucrypto.NativeCipher$Aes192CbcNoPadding",
+          "Alg.Alias.Cipher.2.16.840.1.101.3.4.1.22;AES_192/CBC/NoPadding",
+          "Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.22;AES_192/CBC/NoPadding",
+          "Cipher.AES_256/CBC/NoPadding;com.oracle.security.ucrypto.NativeCipher$Aes256CbcNoPadding",
+          "Alg.Alias.Cipher.2.16.840.1.101.3.4.1.42;AES_256/CBC/NoPadding",
+          "Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.42;AES_256/CBC/NoPadding"
+        }),
+    CRYPTO_AES_CBC_PAD(3, null), // No support from Solaris yet
+    CRYPTO_AES_CTR(4, new String[]
+        { "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 String[]
+        { "Cipher.AES/GCM/NoPadding;com.oracle.security.ucrypto.NativeGCMCipher$AesGcmNoPadding",
+          "Cipher.AES_128/GCM/NoPadding;com.oracle.security.ucrypto.NativeGCMCipher$Aes128GcmNoPadding",
+          "Alg.Alias.Cipher.2.16.840.1.101.3.4.1.6;AES_128/GCM/NoPadding",
+          "Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.6;AES_128/GCM/NoPadding",
+          "Cipher.AES_192/GCM/NoPadding;com.oracle.security.ucrypto.NativeGCMCipher$Aes192GcmNoPadding",
+          "Alg.Alias.Cipher.2.16.840.1.101.3.4.1.26;AES_192/GCM/NoPadding",
+          "Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.26;AES_192/GCM/NoPadding",
+          "Cipher.AES_256/GCM/NoPadding;com.oracle.security.ucrypto.NativeGCMCipher$Aes256GcmNoPadding",
+          "Alg.Alias.Cipher.2.16.840.1.101.3.4.1.46;AES_256/GCM/NoPadding",
+          "Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.46;AES_256/GCM/NoPadding",
+        }),
+    CRYPTO_AES_GMAC(7, null), // No support from Solaris yet
+    CRYPTO_AES_CFB128(8, new String[]
+        { "Cipher.AES/CFB128/NoPadding;com.oracle.security.ucrypto.NativeCipher$AesCfb128NoPadding",
+          "Cipher.AES/CFB128/PKCS5Padding;com.oracle.security.ucrypto.NativeCipherWithJavaPadding$AesCfb128PKCS5" }),
+    CRYPTO_RSA_PKCS(31, new String[]
+        { "Cipher.RSA/ECB/PKCS1Padding;com.oracle.security.ucrypto.NativeRSACipher$PKCS1Padding" }),
+    CRYPTO_RSA_X_509(32, new String[]
+        { "Cipher.RSA/ECB/NoPadding;com.oracle.security.ucrypto.NativeRSACipher$NoPadding" }),
+    CRYPTO_MD5_RSA_PKCS(33, new String[]
+        { "Signature.MD5withRSA;com.oracle.security.ucrypto.NativeRSASignature$MD5",
+          "Alg.Alias.Signature.1.2.840.113549.1.1.4;MD5withRSA",
+          "Alg.Alias.Signature.OID.1.2.840.113549.1.1.4;MD5withRSA" }),
+    CRYPTO_SHA1_RSA_PKCS(34, new String[]
+        { "Signature.SHA1withRSA;com.oracle.security.ucrypto.NativeRSASignature$SHA1",
+          "Alg.Alias.Signature.1.2.840.113549.1.1.5;SHA1withRSA",
+          "Alg.Alias.Signature.OID.1.2.840.113549.1.1.5;SHA1withRSA",
+          "Alg.Alias.Signature.1.3.14.3.2.29;SHA1withRSA" }),
+    CRYPTO_SHA256_RSA_PKCS(35, new String[]
+        { "Signature.SHA256withRSA;com.oracle.security.ucrypto.NativeRSASignature$SHA256",
+          "Alg.Alias.Signature.1.2.840.113549.1.1.11;SHA256withRSA",
+          "Alg.Alias.Signature.OID.1.2.840.113549.1.1.11;SHA256withRSA" }),
+    CRYPTO_SHA384_RSA_PKCS(36, new String[]
+        { "Signature.SHA384withRSA;com.oracle.security.ucrypto.NativeRSASignature$SHA384",
+          "Alg.Alias.Signature.1.2.840.113549.1.1.12;SHA384withRSA",
+          "Alg.Alias.Signature.OID.1.2.840.113549.1.1.12;SHA384withRSA" }),
+    CRYPTO_SHA512_RSA_PKCS(37, new String[]
+        { "Signature.SHA512withRSA;com.oracle.security.ucrypto.NativeRSASignature$SHA512",
+          "Alg.Alias.Signature.1.2.840.113549.1.1.13;SHA512withRSA",
+          "Alg.Alias.Signature.OID.1.2.840.113549.1.1.13;SHA512withRSA" });
+
+    private int mech;
+    private String[] jceProps;
+
+    UcryptoMech(int mech, String[] jceProps) {
+        this.mech = mech;
+        this.jceProps = jceProps;
+    }
+
+    public int value() { return mech; }
+    public String[] jceProperties() { return jceProps; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+package com.oracle.security.ucrypto;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+import java.security.*;
+import sun.security.action.PutAllAction;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * OracleUcrypto provider main class.
+ *
+ * @since 1.9
+ */
+public final class UcryptoProvider extends Provider {
+
+    private static final long serialVersionUID = 351251234302833L;
+
+    private static boolean DEBUG;
+    private static HashMap<String, String> provProp;
+
+    static {
+        try {
+            DEBUG = Boolean.parseBoolean(AccessController.doPrivileged
+                (new GetPropertyAction("com.oracle.security.ucrypto.debug")));
+
+            // cannot use LoadLibraryAction because that would make the native
+            // library available to the bootclassloader, but we run in the
+            // extension classloader.
+            provProp = AccessController.doPrivileged
+                (new PrivilegedAction<HashMap<String, String>>() {
+                    public HashMap<String, String> run() {
+                        try {
+                            System.loadLibrary("j2ucrypto");
+                            String osname = System.getProperty("os.name");
+                            if (osname.startsWith("SunOS")) {
+                                return new HashMap<String, String>();
+                            } else return null;
+                        } catch (Error err) {
+                            return null;
+                        } catch (SecurityException se) {
+                            return null;
+                        }
+                    }
+                });
+            if (provProp != null) {
+                boolean[] result = loadLibraries();
+                if (result.length == 2) {
+                    if (result[0]) { // successfully loaded libmd
+                        provProp.put("MessageDigest.MD5",
+                                     "com.oracle.security.ucrypto.NativeDigest$MD5");
+                        provProp.put("MessageDigest.SHA",
+                                     "com.oracle.security.ucrypto.NativeDigest$SHA1");
+                        provProp.put("Alg.Alias.MessageDigest.SHA-1", "SHA");
+                        provProp.put("Alg.Alias.MessageDigest.SHA1", "SHA");
+                        provProp.put("MessageDigest.SHA-256",
+                                     "com.oracle.security.ucrypto.NativeDigest$SHA256");
+                        provProp.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256");
+                        provProp.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.1", "SHA-256");
+
+                        provProp.put("MessageDigest.SHA-384",
+                                     "com.oracle.security.ucrypto.NativeDigest$SHA384");
+                        provProp.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384");
+                        provProp.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.2", "SHA-384");
+
+                        provProp.put("MessageDigest.SHA-512",
+                                     "com.oracle.security.ucrypto.NativeDigest$SHA512");
+                        provProp.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
+                        provProp.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3", "SHA-512");
+
+                    }
+                    if (result[1]) { // successfully loaded libsoftcrypto
+                        String supportedMechs = getMechList();
+                        debug("Prov: supported mechs = " + supportedMechs);
+                        for (UcryptoMech m : UcryptoMech.values()) {
+                            if (supportedMechs.indexOf(m.name() + ",") != -1) {
+                                String[] jceProps = m.jceProperties();
+                                // skip unsupported UcryptoMech
+                                if (jceProps == null) continue;
+                                for (int p = 0; p < jceProps.length; p++) {
+                                    StringTokenizer st =
+                                        new StringTokenizer(jceProps[p], ";");
+                                    if (st.countTokens() != 2) {
+                                        throw new RuntimeException("Wrong format: " + jceProps[p]);
+                                    }
+                                    provProp.put(st.nextToken(), st.nextToken());
+                                }
+                            }
+                        }
+                        // NOTE: GCM support is only available since jdk 7
+                        provProp.put("AlgorithmParameters.GCM",
+                                     "com.oracle.security.ucrypto.GCMParameters");
+                    }
+                } else {
+                    debug("Prov: unexpected ucrypto library loading error, got " + result.length);
+                }
+            }
+        } catch (AccessControlException ace) {
+            // disable Ucrypto provider
+            DEBUG = false;
+            provProp = null;
+        }
+    }
+
+    static Provider provider = null;
+    private static native boolean[] loadLibraries();
+    private static native String getMechList();
+
+    static void debug(String msg) {
+        if (DEBUG) {
+            System.out.println("UCrypto/" + msg);
+        }
+    }
+
+    public UcryptoProvider() {
+        super("OracleUcrypto", 1.9d, "Provider using Oracle Ucrypto API");
+        if (provProp != null) {
+            AccessController.doPrivileged(new PutAllAction(this, provProp));
+        }
+        if (provider == null) provider = this;
+    }
+
+    public UcryptoProvider(String configName) {
+        super("OracleUcrypto", 1.9d, "Provider using Oracle Ucrypto API");
+        try {
+            if (provProp != null) {
+                HashMap<String, String> customProvProp =
+                    new HashMap<String, String>(provProp);
+                Config c = new Config(configName);
+                String[] disabledServices = c.getDisabledServices();
+                for (int i = 0; i < disabledServices.length; i++) {
+                    if (customProvProp.remove(disabledServices[i]) != null) {
+                        debug("Prov: remove config-disabled service " + disabledServices[i]);
+                    } else {
+                        debug("Prov: ignore unsupported config-disabled service " +
+                              disabledServices[i]);
+                    }
+                }
+                AccessController.doPrivileged(new PutAllAction(this, customProvProp));
+            }
+        } catch (IOException ioe) { // thrown by Config
+            throw new UcryptoException("Error parsing Config", ioe);
+        }
+        if (provider == null) provider = this;
+    }
+
+    public boolean equals(Object obj) {
+        return this == obj;
+    }
+
+    public int hashCode() {
+        return System.identityHashCode(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/conf/security/ucrypto-solaris.cfg	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,9 @@
+#
+# Configuration file for the OracleUcrypto provider
+#
+disabledServices = {
+  # disabled due to Solaris bug 7121679
+  Cipher.AES/CFB128/PKCS5Padding
+  Cipher.AES/CFB128/NoPadding
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,1250 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <jni.h>
+#include <libsoftcrypto.h>
+#include "nativeCrypto.h"
+#include "nativeFunc.h"
+
+/*
+ * Dumps out byte array in hex with and name and length info
+ */
+void printBytes(char* header, unsigned char* bytes, int len) {
+  int i;
+
+  printf("%s", header);
+  printf("len=%d {", len);
+  for (i = 0; i < len; i++) {
+    if (i > 0) printf(":");
+    printf("%02X", bytes[i]);
+  }
+  printf("}\n");
+}
+
+/*
+ * Throws java.lang.OutOfMemoryError
+ */
+void throwOutOfMemoryError(JNIEnv *env, const char *msg)
+{
+  jclass jExClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
+  if (jExClass != 0) /* Otherwise an exception has already been thrown */ {
+    (*env)->ThrowNew(env, jExClass, msg);
+  }
+  /* free the local ref */
+  (*env)->DeleteLocalRef(env, jExClass);
+}
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
+    return JNI_VERSION_1_4;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_UcryptoProvider
+ * Method:    loadLibraries
+ * Signature: ()[Z
+ */
+JNIEXPORT jbooleanArray JNICALL Java_com_oracle_security_ucrypto_UcryptoProvider_loadLibraries
+(JNIEnv *env, jclass jcls) {
+  jbooleanArray jResult;
+  jboolean *result;
+  jResult = (*env)->NewBooleanArray(env, 2);
+
+  if (jResult != NULL) {
+    result = loadNative();
+    (*env)->SetBooleanArrayRegion(env, jResult, 0, 2, result);
+    free(result);
+  }
+  return jResult;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_UcryptoProvider
+ * Method:    getMechList
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_oracle_security_ucrypto_UcryptoProvider_getMechList
+(JNIEnv *env, jclass jcls) {
+  jstring jResult;
+  char* result;
+  int length;
+
+  jResult = NULL;
+  if (ftab->ucryptoVersion != NULL && ftab->ucryptoGetMechList != NULL) {
+      length = (*ftab->ucryptoGetMechList)(NULL);
+      if (DEBUG) printf("mech list length: %d\n", length);
+      result = malloc(length);
+      if (result == NULL) {
+        throwOutOfMemoryError(env, NULL);
+        return NULL;
+      }
+      length = (*ftab->ucryptoGetMechList)(result);
+      if (DEBUG) printf("mech list: %s\n", result);
+      jResult = (*env)->NewStringUTF(env, result);
+      free(result);
+  } else {
+      // version 0 on Solaris 10
+      result = "CRYPTO_AES_ECB,CRYPTO_AES_CBC,CRYPTO_AES_CFB128,";
+      jResult = (*env)->NewStringUTF(env, result);
+  }
+  return jResult;
+}
+
+/*
+ * Utility function for throwing a UcryptoException when rv is not CRYPTO_OK(0)
+ */
+void throwUCExceptionUsingRV(JNIEnv *env, int rv) {
+  jclass jExClass;
+  jmethodID jConstructor;
+  jthrowable jException;
+
+  if ((*env)->ExceptionCheck(env)) return;
+
+  jExClass = (*env)->FindClass(env, "com/oracle/security/ucrypto/UcryptoException");
+  /* if jExClass is NULL, an exception has already been thrown */
+  if (jExClass != NULL) {
+    jConstructor = (*env)->GetMethodID(env, jExClass, "<init>", "(I)V");
+    if (jConstructor != NULL) {
+      jException = (jthrowable) (*env)->NewObject(env, jExClass, jConstructor, rv);
+      if (jException != NULL) {
+        (*env)->Throw(env, jException);
+      }
+    }
+  }
+  /* free the local ref */
+  (*env)->DeleteLocalRef(env, jExClass);
+}
+
+/*
+ * Utility function for duplicating a byte array from jbyteArray
+ * If anything went wrong, no memory will be allocated.
+ * NOTE: caller is responsible for freeing the allocated memory
+ * once this method returned successfully.
+ */
+jbyte* getBytes(JNIEnv *env, jbyteArray bytes, int offset, int len) {
+  jbyte* result = NULL;
+
+  if (!(*env)->ExceptionCheck(env)) {
+    result = (jbyte*) calloc(len, sizeof(char));
+    if (result == NULL) {
+      throwOutOfMemoryError(env, NULL);
+      return NULL;
+    }
+    (*env)->GetByteArrayRegion(env, bytes, offset, len, result);
+    if ((*env)->ExceptionCheck(env)) {
+        // free allocated memory if error occurred
+        free(result);
+        return NULL;
+    }
+  }
+  return result;
+}
+
+
+int
+CipherInit(crypto_ctx_t *context, int encrypt, ucrypto_mech_t mech,
+           unsigned char *jKey, int jKeyLen, unsigned char *jIv, int jIvLen,
+           int tagLen, unsigned char *jAad, int jAadLen)
+
+{
+  int rv = 0;
+  void *iv;
+  size_t ivLen;
+
+  if (DEBUG) printf("CipherInit: mech %i, key %i(%i), iv %i(%i) tagLen %i, aad %i(%i)\n",
+                    mech, jKey, jKeyLen, jIv, jIvLen, tagLen, jAad, jAadLen);
+  if (mech == CRYPTO_AES_CTR) {
+    ivLen = sizeof(CK_AES_CTR_PARAMS);
+    iv = (CK_AES_CTR_PARAMS*) malloc(ivLen);
+    if (iv == NULL) return -1;
+
+    ((CK_AES_CTR_PARAMS*)iv)->ulCounterBits = 32;
+    memcpy(((CK_AES_CTR_PARAMS*)iv)->cb, jIv, 16);
+  } else if (mech == CRYPTO_AES_GCM) {
+    ivLen = sizeof(CK_AES_GCM_PARAMS);
+    iv = (CK_AES_GCM_PARAMS*) malloc(ivLen);
+    if (iv == NULL) return -1;
+
+    ((CK_AES_GCM_PARAMS*)iv)->pIv = (uchar_t *)jIv;
+    ((CK_AES_GCM_PARAMS*)iv)->ulIvLen = (ulong_t)jIvLen;
+    ((CK_AES_GCM_PARAMS*)iv)->ulIvBits = 96;
+    ((CK_AES_GCM_PARAMS*)iv)->pAAD = (uchar_t *)jAad;
+    ((CK_AES_GCM_PARAMS*)iv)->ulAADLen = (ulong_t)jAadLen;
+    ((CK_AES_GCM_PARAMS*)iv)->ulTagBits = (ulong_t)tagLen;
+  } else {
+    // normal bytes
+    iv = jIv;
+    ivLen = jIvLen;
+  }
+  if (encrypt) {
+    rv = (*ftab->ucryptoEncryptInit)(context, mech, jKey, (size_t)jKeyLen, iv, ivLen);
+    if (rv != 0 && DEBUG) printf("ucryptoEncryptInit: ret = 0x%x\n", 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 (iv != jIv) {
+    if (mech == CRYPTO_AES_CTR) {
+      free((CK_AES_CTR_PARAMS*)iv);
+    } else {
+      free((CK_AES_GCM_PARAMS*)iv);
+    }
+  }
+
+  return rv;
+}
+
+int
+CipherUpdate(crypto_ctx_t *context, int encrypt, unsigned char *bufIn, int inOfs,
+             int inLen, unsigned char *bufOut, int outOfs, int *outLen)
+{
+  int rv = 0;
+  size_t outLength;
+
+  outLength = (size_t) *outLen;
+  if (DEBUG) {
+    printf("CipherUpdate: Inofs %i, InLen %i, OutOfs %i, OutLen %i\n", inOfs, inLen, outOfs, *outLen);
+    printBytes("BufIn=", (unsigned char*)(bufIn+inOfs), inLen);
+  }
+  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);
+    } 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);
+    } else {
+      if (DEBUG) printBytes("BufOut=", (unsigned char*)(bufOut+outOfs), outLength);
+      *outLen = (int)outLength;
+    }
+  }
+
+  return rv;
+}
+
+int
+CipherFinal(crypto_ctx_t *context, int encrypt, unsigned char *bufOut, int outOfs, int *outLen)
+{
+  int rv = 0;
+  size_t outLength;
+
+  outLength = (size_t)*outLen;
+
+  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);
+    } 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);
+    } else {
+      if (DEBUG) printBytes("BufOut=", (unsigned char*)(bufOut+outOfs), outLength);
+      *outLen = (int)outLength;
+    }
+  }
+  return rv;
+}
+
+////////////////////////////////////////////////////////
+// SPECIAL ENTRIES FOR JVM JNI-BYPASSING OPTIMIZATION
+////////////////////////////////////////////////////////
+jlong JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeInit(jint mech) {
+  void *pContext = NULL;
+
+  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);
+    }
+    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;
+}
+
+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);
+  }
+  return 0;
+}
+
+// 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;
+}
+
+jlong JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeClone
+  (jint mech, jlong pContext) {
+  void *copy = NULL;
+  size_t len = 0;
+
+  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;
+}
+
+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);
+  }
+}
+
+// AES
+jlong JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeInit
+  (jint mech, jboolean encrypt, int keyLen, unsigned char* bufKey,
+   int ivLen, unsigned char* bufIv, jint tagLen, int aadLen, unsigned char* bufAad) {
+  crypto_ctx_t *context = NULL;
+  int rv;
+
+  context = malloc(sizeof(crypto_ctx_t));
+  if (context != NULL) {
+    rv = CipherInit(context, encrypt, (ucrypto_mech_t) mech, bufKey, keyLen,
+                    bufIv, ivLen, tagLen, bufAad, aadLen);
+    if (rv) {
+      free(context);
+      return 0L;
+    }
+  }
+  return (jlong)context;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeCipher
+ * Method:    nativeUpdate
+ * Signature: (JZ[BII[BI)I
+ */
+jint JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeUpdate
+  (jlong pContext, jboolean encrypt, int notUsed, jbyte* bufIn, jint inOfs, jint inLen,
+   int outCapacity, jbyte* bufOut, jint outOfs) {
+  crypto_ctx_t *context;
+  int rv = 0;
+  int outLen = outCapacity - outOfs; // recalculate the real out length
+
+  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;
+    return -rv; // use negative value to indicate error!
+  }
+
+  return outLen;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeCipher
+ * Method:    nativeFinal
+ * Signature: (JZ[BI)I
+ */
+jint JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeFinal
+  (jlong pContext, jboolean encrypt, int outLen, jbyte* bufOut, jint outOfs) {
+  crypto_ctx_t *context;
+  int rv = 0;
+
+  context = (crypto_ctx_t *) pContext;
+  rv = CipherFinal(context, encrypt, (unsigned char*)bufOut, outOfs, &outLen);
+  free(context);
+  if (rv) {
+     return -rv; // use negative value to indicate error!
+  }
+
+  return outLen;
+}
+
+
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeDigest
+ * Method:    nativeInit
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeInit
+  (JNIEnv *env, jclass jcls, jint mech) {
+  jlong result = JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeInit(mech);
+  if (result == NULL) {
+     throwOutOfMemoryError(env, NULL);
+  }
+  return result;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeDigest
+ * Method:    nativeUpdate
+ * Signature: (IJ[BII)I
+ */
+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;
+
+  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);
+    free(bufIn);
+  }
+  return 0;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeDigest
+ * Method:    nativeDigest
+ * Signature: (IJ[BII)I
+ */
+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;
+
+  bufOut = (unsigned char *) malloc(digestLen);
+  if (bufOut == NULL) {
+    throwOutOfMemoryError(env, NULL);
+    return 0;
+  }
+
+  JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeDigest(mech, pContext, digestLen, bufOut, 0, digestLen);
+
+  (*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);
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeDigest
+ * Method:    nativeFree
+ * Signature: (IJ)V
+ */
+JNIEXPORT void JNICALL Java_com_oracle_security_ucrypto_NativeDigest_nativeFree
+  (JNIEnv *env, jclass jcls, jint mech, jlong pContext) {
+  JavaCritical_com_oracle_security_ucrypto_NativeDigest_nativeFree(mech, pContext);
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeCipher
+ * Method:    nativeInit
+ * Signature: (IZ[B[BI[B)J
+ */
+JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeCipher_nativeInit
+(JNIEnv *env, jclass jcls, jint mech, jboolean encrypt, jbyteArray jKey,
+ jbyteArray jIv, jint tagLen, jbyteArray jAad) {
+
+  crypto_ctx_t *context;
+  unsigned char *bufKey;
+  unsigned char *bufIv;
+  unsigned char *bufAad;
+  int keyLen, ivLen, aadLen, rv = 0;
+  jlong result = 0L;
+
+  bufKey = bufIv = bufAad = NULL;
+  keyLen = ivLen = aadLen = 0;
+  context = malloc(sizeof(crypto_ctx_t));
+  if (context == NULL) {
+    throwOutOfMemoryError(env, NULL);
+    return 0L;
+  }
+
+  // jKey MUST NOT BE NULL;
+  keyLen = (*env)->GetArrayLength(env, jKey);
+  bufKey = (unsigned char *) (*env)->GetByteArrayElements(env, jKey, NULL);
+  if (bufKey == NULL) {
+    goto cleanup;
+  }
+
+  if (jIv != NULL) {
+    ivLen = (*env)->GetArrayLength(env, jIv);
+    bufIv = (unsigned char *) (*env)->GetByteArrayElements(env, jIv, NULL);
+    if (bufIv == NULL) {
+      goto cleanup;
+    }
+  }
+
+  if (jAad != NULL) {
+    aadLen = (*env)->GetArrayLength(env, jAad);
+    bufAad = (unsigned char *) (*env)->GetByteArrayElements(env, jAad, NULL);
+    if (bufAad == NULL) {
+      goto cleanup;
+    }
+  }
+
+  rv = CipherInit(context, encrypt, mech, bufKey, keyLen, bufIv, ivLen, tagLen, bufAad, aadLen);
+  if (rv != 0) {
+    throwUCExceptionUsingRV(env, rv);
+  } else {
+     result = (jlong) context;
+  }
+
+cleanup:
+  if ((result == 0L) && (context != NULL)) {
+    free(context);
+  }
+  if (bufKey != NULL) {
+    (*env)->ReleaseByteArrayElements(env, jKey, (jbyte *)bufKey, 0);
+  }
+  if (bufIv != NULL) {
+    (*env)->ReleaseByteArrayElements(env, jIv, (jbyte *)bufIv, 0);
+  }
+  if (bufAad != NULL) {
+    (*env)->ReleaseByteArrayElements(env, jAad, (jbyte *)bufAad, 0);
+  }
+
+  return result;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeCipher
+ * Method:    nativeUpdate
+ * Signature: (JZ[BII[BI)I
+ */
+JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeCipher_nativeUpdate
+  (JNIEnv *env, jclass jcls, jlong contextID, jboolean encrypt,
+    jbyteArray jIn, jint inOfs, jint inLen, jbyteArray jOut, jint outOfs) {
+  crypto_ctx_t *context;
+  unsigned char *bufIn;
+  unsigned char *bufOut;
+  int outLen, rv = 0;
+
+  context = (crypto_ctx_t *) contextID;
+  bufIn = (unsigned char *) getBytes(env, jIn, inOfs, inLen);
+  if ((*env)->ExceptionCheck(env)) {
+    return 0;
+  }
+
+  outLen = (*env)->GetArrayLength(env, jOut) - outOfs;
+  bufOut = calloc(outLen, sizeof(char));
+  if (bufOut == NULL) {
+    free(bufIn);
+    throwOutOfMemoryError(env, NULL);
+    return 0;
+  }
+
+  rv = CipherUpdate(context, encrypt, bufIn, 0, inLen, bufOut, 0, &outLen);
+  if (rv) {
+    free(context);
+    free(bufIn);
+    free(bufOut);
+    return -rv;
+  } else {
+    (*env)->SetByteArrayRegion(env, jOut, outOfs, outLen, (jbyte *)bufOut);
+    free(bufIn);
+    free(bufOut);
+    return outLen;
+  }
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeCipher
+ * Method:    nativeFinal
+ * Signature: (JZ[BI)I
+ */
+JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeCipher_nativeFinal
+  (JNIEnv *env, jclass jCls, jlong contextID, jboolean encrypt,
+   jbyteArray out, jint outOfs) {
+  crypto_ctx_t *context;
+  unsigned char *bufIn;
+  unsigned char *bufOut;
+  int outLen, rv = 0;
+
+  context = (crypto_ctx_t *) contextID;
+
+  // out is null when nativeFinal() is called solely for resource clean up
+  if (out == NULL) {
+    bufOut = NULL;
+    outLen = 0;
+  } else {
+    outLen = (*env)->GetArrayLength(env, out) - outOfs;
+    bufOut = calloc(outLen, sizeof(char));
+    if (bufOut == NULL) {
+      throwOutOfMemoryError(env, NULL);
+      return 0;
+    }
+  }
+  rv = CipherFinal(context, encrypt, bufOut, 0, &outLen);
+  if (rv) {
+    free(context);
+    free(bufOut);
+    return -rv;
+  } else {
+    if (bufOut != NULL) {
+      (*env)->SetByteArrayRegion(env, out, outOfs, outLen, (jbyte *)bufOut);
+      free(bufOut);
+    }
+    free(context);
+    return outLen;
+  }
+}
+
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeKey
+ * Method:    nativeFree
+ * Signature: (JI)V
+ */
+void JavaCritical_com_oracle_security_ucrypto_NativeKey_nativeFree
+  (jlong id, jint numOfComponents) {
+  crypto_object_attribute_t* pKey;
+  int i;
+
+  pKey = (crypto_object_attribute_t*) id;
+  for (i = 0; i < numOfComponents; i++) {
+    free(pKey[i].oa_value);
+  }
+  free(pKey);
+}
+
+JNIEXPORT void JNICALL Java_com_oracle_security_ucrypto_NativeKey_nativeFree
+  (JNIEnv *env, jclass jCls, jlong id, jint numOfComponents) {
+  JavaCritical_com_oracle_security_ucrypto_NativeKey_nativeFree(id, numOfComponents);
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeKey_RSAPrivateCrt
+ * Method:    nativeInit
+ * Signature: ([B[B[B[B[B[B[B[B)J
+ */
+jlong JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivateCrt_nativeInit
+(int modLen, jbyte* jMod, int pubLen, jbyte* jPub, int privLen, jbyte* jPriv,
+ int pLen, jbyte* jP, int qLen, jbyte* jQ, int expPLen, jbyte* jExpP,
+ int expQLen, jbyte* jExpQ, int crtCoeffLen, jbyte* jCrtCoeff) {
+
+  unsigned char *mod, *pub, *priv, *p, *q, *expP, *expQ, *crtCoeff;
+  crypto_object_attribute_t* pKey = NULL;
+
+  pKey = calloc(8, sizeof(crypto_object_attribute_t));
+  if (pKey == NULL) {
+    return 0L;
+  }
+  mod = pub = priv = p = q = expP = expQ = crtCoeff = NULL;
+  mod = malloc(modLen);
+  pub = malloc(pubLen);
+  priv = malloc(privLen);
+  p = malloc(pLen);
+  q = malloc(qLen);
+  expP = malloc(expPLen);
+  expQ = malloc(expQLen);
+  crtCoeff = malloc(crtCoeffLen);
+  if (mod == NULL || pub == NULL || priv == NULL || p == NULL ||
+      q == NULL || expP == NULL || expQ == NULL || crtCoeff == NULL) {
+    free(pKey);
+    free(mod);
+    free(pub);
+    free(priv);
+    free(p);
+    free(q);
+    free(expP);
+    free(expQ);
+    free(crtCoeff);
+    return 0L;
+  } else {
+    memcpy(mod, jMod, modLen);
+    memcpy(pub, jPub, pubLen);
+    memcpy(priv, jPriv, privLen);
+    memcpy(p, jP, pLen);
+    memcpy(q, jQ, qLen);
+    memcpy(expP, jExpP, expPLen);
+    memcpy(expQ, jExpQ, expQLen);
+    memcpy(crtCoeff, jCrtCoeff, crtCoeffLen);
+  }
+
+  // NOTE: numOfComponents should be 8
+  pKey[0].oa_type = SUN_CKA_MODULUS;
+  pKey[0].oa_value = (char*) mod;
+  pKey[0].oa_value_len = (size_t) modLen;
+  pKey[1].oa_type = SUN_CKA_PUBLIC_EXPONENT;
+  pKey[1].oa_value = (char*) pub;
+  pKey[1].oa_value_len = (size_t) pubLen;
+  pKey[2].oa_type = SUN_CKA_PRIVATE_EXPONENT;
+  pKey[2].oa_value = (char*) priv;
+  pKey[2].oa_value_len = (size_t) privLen;
+  pKey[3].oa_type = SUN_CKA_PRIME_1;
+  pKey[3].oa_value = (char*) p;
+  pKey[3].oa_value_len = (size_t) pLen;
+  pKey[4].oa_type = SUN_CKA_PRIME_2;
+  pKey[4].oa_value = (char*) q;
+  pKey[4].oa_value_len = (size_t) qLen;
+  pKey[5].oa_type = SUN_CKA_EXPONENT_1;
+  pKey[5].oa_value = (char*) expP;
+  pKey[5].oa_value_len = (size_t) expPLen;
+  pKey[6].oa_type = SUN_CKA_EXPONENT_2;
+  pKey[6].oa_value = (char*) expQ;
+  pKey[6].oa_value_len = (size_t) expQLen;
+  pKey[7].oa_type = SUN_CKA_COEFFICIENT;
+  pKey[7].oa_value = (char*) crtCoeff;
+  pKey[7].oa_value_len = (size_t) crtCoeffLen;
+
+  return (jlong) pKey;
+}
+
+
+JNIEXPORT jlong JNICALL
+Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivateCrt_nativeInit
+  (JNIEnv *env, jclass jCls, jbyteArray jMod, jbyteArray jPub, jbyteArray jPriv,
+   jbyteArray jP, jbyteArray jQ, jbyteArray jExpP, jbyteArray jExpQ,
+   jbyteArray jCrtCoeff) {
+
+  int modLen, pubLen, privLen, pLen, qLen, expPLen, expQLen, crtCoeffLen;
+  jbyte *bufMod, *bufPub, *bufPriv, *bufP, *bufQ, *bufExpP, *bufExpQ, *bufCrtCoeff;
+  crypto_object_attribute_t* pKey = NULL;
+
+  bufMod = bufPub = bufPriv = bufP = bufQ = bufExpP = bufExpQ = bufCrtCoeff = NULL;
+
+  modLen = (*env)->GetArrayLength(env, jMod);
+  bufMod = getBytes(env, jMod, 0, modLen);
+  if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+  pubLen = (*env)->GetArrayLength(env, jPub);
+  bufPub = getBytes(env, jPub, 0, pubLen);
+  if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+  privLen = (*env)->GetArrayLength(env, jPriv);
+  bufPriv = getBytes(env, jPriv, 0, privLen);
+  if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+  pLen = (*env)->GetArrayLength(env, jP);
+  bufP = getBytes(env, jP, 0, pLen);
+  if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+  qLen = (*env)->GetArrayLength(env, jQ);
+  bufQ = getBytes(env, jQ, 0, qLen);
+  if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+  expPLen = (*env)->GetArrayLength(env, jExpP);
+  bufExpP = getBytes(env, jExpP, 0, expPLen);
+  if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+  expQLen = (*env)->GetArrayLength(env, jExpQ);
+  bufExpQ = getBytes(env, jExpQ, 0, expQLen);
+  if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+  crtCoeffLen = (*env)->GetArrayLength(env, jCrtCoeff);
+  bufCrtCoeff = getBytes(env, jCrtCoeff, 0, crtCoeffLen);
+  if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+  // proceed if no error; otherwise free allocated memory
+  pKey = calloc(8, sizeof(crypto_object_attribute_t));
+  if (pKey == NULL) {
+    throwOutOfMemoryError(env, NULL);
+    goto cleanup;
+  }
+
+  // NOTE: numOfComponents should be 8
+  pKey[0].oa_type = SUN_CKA_MODULUS;
+  pKey[0].oa_value = (char*) bufMod;
+  pKey[0].oa_value_len = (size_t) modLen;
+  pKey[1].oa_type = SUN_CKA_PUBLIC_EXPONENT;
+  pKey[1].oa_value = (char*) bufPub;
+  pKey[1].oa_value_len = (size_t) pubLen;
+  pKey[2].oa_type = SUN_CKA_PRIVATE_EXPONENT;
+  pKey[2].oa_value = (char*) bufPriv;
+  pKey[2].oa_value_len = (size_t) privLen;
+  pKey[3].oa_type = SUN_CKA_PRIME_1;
+  pKey[3].oa_value = (char*) bufP;
+  pKey[3].oa_value_len = (size_t) pLen;
+  pKey[4].oa_type = SUN_CKA_PRIME_2;
+  pKey[4].oa_value = (char*) bufQ;
+  pKey[4].oa_value_len = (size_t) qLen;
+  pKey[5].oa_type = SUN_CKA_EXPONENT_1;
+  pKey[5].oa_value = (char*) bufExpP;
+  pKey[5].oa_value_len = (size_t) expPLen;
+  pKey[6].oa_type = SUN_CKA_EXPONENT_2;
+  pKey[6].oa_value = (char*) bufExpQ;
+  pKey[6].oa_value_len = (size_t) expQLen;
+  pKey[7].oa_type = SUN_CKA_COEFFICIENT;
+  pKey[7].oa_value = (char*) bufCrtCoeff;
+  pKey[7].oa_value_len = (size_t) crtCoeffLen;
+  return (jlong) pKey;
+
+cleanup:
+  free(bufMod);
+  free(bufPub);
+  free(bufPriv);
+  free(bufP);
+  free(bufQ);
+  free(bufExpP);
+  free(bufExpQ);
+  free(bufCrtCoeff);
+
+  return 0L;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeKey_RSAPublic
+ * Method:    nativeInit
+ * Signature: ([B[B)J
+ */
+
+jlong JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeInit
+(int modLen, jbyte* jMod, int pubLen, jbyte* jPub) {
+  unsigned char *mod, *pub;
+  crypto_object_attribute_t* pKey = NULL;
+
+  pKey = calloc(2, sizeof(crypto_object_attribute_t));
+  if (pKey == NULL) {
+    return 0L;
+  }
+  mod = pub = NULL;
+  mod = malloc(modLen);
+  pub = malloc(pubLen);
+  if (mod == NULL || pub == NULL) {
+    free(pKey);
+    free(mod);
+    free(pub);
+    return 0L;
+  } else {
+    memcpy(mod, jMod, modLen);
+    memcpy(pub, jPub, pubLen);
+  }
+
+  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);
+  }
+
+  pKey[0].oa_type = SUN_CKA_MODULUS;
+  pKey[0].oa_value = (char*) mod;
+  pKey[0].oa_value_len = (size_t) modLen;
+  pKey[1].oa_type = SUN_CKA_PUBLIC_EXPONENT;
+  pKey[1].oa_value = (char*) pub;
+  pKey[1].oa_value_len = (size_t) pubLen;
+
+  return (jlong) pKey;
+}
+
+JNIEXPORT jlong JNICALL
+Java_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeInit
+(JNIEnv *env, jclass jCls, jbyteArray jMod, jbyteArray jPub) {
+  int modLen, pubLen;
+  jbyte *bufMod, *bufPub;
+  crypto_object_attribute_t* pKey = NULL;
+
+  bufMod = bufPub = NULL;
+
+  modLen = (*env)->GetArrayLength(env, jMod);
+  bufMod = getBytes(env, jMod, 0, modLen);
+  if ((*env)->ExceptionCheck(env)) {
+    return 0L;
+  }
+
+  pubLen = (*env)->GetArrayLength(env, jPub);
+  bufPub = getBytes(env, jPub, 0, pubLen);
+  if ((*env)->ExceptionCheck(env)) {
+    free(bufMod);
+    return 0L;
+  }
+
+  // proceed if no error; otherwise free allocated memory
+  pKey = calloc(2, sizeof(crypto_object_attribute_t));
+  if (pKey != NULL) {
+    // NOTE: numOfComponents should be 2
+    pKey[0].oa_type = SUN_CKA_MODULUS;
+    pKey[0].oa_value = (char*) bufMod;
+    pKey[0].oa_value_len = (size_t) modLen;
+    pKey[1].oa_type = SUN_CKA_PUBLIC_EXPONENT;
+    pKey[1].oa_value = (char*) bufPub;
+    pKey[1].oa_value_len = (size_t) pubLen;
+    return (jlong) pKey;
+  } else {
+    free(bufMod);
+    free(bufPub);
+    throwOutOfMemoryError(env, NULL);
+    return 0L;
+  }
+}
+
+////////////////////////
+// NativeRSASignature
+////////////////////////
+
+int
+SignatureInit(crypto_ctx_t *context, jint mechVal, jboolean sign,
+              uchar_t *pKey, size_t keyLength) {
+  ucrypto_mech_t mech;
+  int rv = 0;
+
+  mech = (ucrypto_mech_t) mechVal;
+
+  if (sign) {
+    rv = (*ftab->ucryptoSignInit)(context, mech, pKey, keyLength,
+                                  NULL, 0);
+  } else {
+    rv = (*ftab->ucryptoVerifyInit)(context, mech, pKey, keyLength,
+                                    NULL, 0);
+  }
+  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);
+  }
+  return rv;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeRSASignature
+ * Method:    nativeInit
+ * Signature: (IZJI[B)J
+ */
+jlong JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeInit
+(jint mech, jboolean sign, jlong jKey, jint keyLength) {
+  crypto_ctx_t *context;
+  int rv;
+  uchar_t *pKey;
+
+  context = malloc(sizeof(crypto_ctx_t));
+  if (context != NULL) {
+    pKey = (uchar_t *) jKey;
+    rv = SignatureInit(context, mech, sign, pKey, (size_t)keyLength);
+    if (rv) {
+      free(context);
+      return 0L;
+    }
+  }
+  return (jlong)context;
+}
+
+JNIEXPORT jlong JNICALL Java_com_oracle_security_ucrypto_NativeRSASignature_nativeInit
+(JNIEnv *env, jclass jCls, jint mech, jboolean sign, jlong jKey, jint keyLength) {
+  crypto_ctx_t *context;
+  int rv = 0;
+  uchar_t *pKey;
+
+  context = malloc(sizeof(crypto_ctx_t));
+  if (context == NULL) {
+    throwOutOfMemoryError(env, NULL);
+    return 0L;
+  }
+
+  pKey = (uchar_t *) jKey;
+  rv = SignatureInit(context, mech, sign, pKey, (size_t)keyLength);
+  if (rv) {
+    free(context);
+    throwUCExceptionUsingRV(env, rv);
+    return 0L;
+  }
+
+  return (jlong)context;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeRSASignature
+ * Method:    nativeUpdate
+ * Signature: (JZ[BII)I
+ */
+jint JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII
+(jlong pCtxt, jboolean sign, int notUsed, jbyte* jIn, jint jInOfs, jint jInLen) {
+  crypto_ctx_t *context;
+  int rv = 0;
+
+  context = (crypto_ctx_t *) pCtxt;
+  if (DEBUG) {
+    printf("Signature update: context=%ld, sign=%d, jIn=%ld, jInOfs=%d, jInLen=%d\n",
+           context, sign, jIn, jInOfs, jInLen);
+  }
+  if (sign) {
+    rv = (*ftab->ucryptoSignUpdate)(context, (uchar_t *) (jIn + jInOfs), (size_t) jInLen);
+  } 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);
+    return -rv; // use negative value to indicate error!
+  }
+
+  return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII
+(JNIEnv *env, jclass jCls, jlong pCtxt, jboolean sign, jbyteArray jIn, jint inOfs, jint inLen) {
+  int rv = 0;
+  jbyte* bufIn;
+
+  bufIn = getBytes(env, jIn, inOfs, inLen);
+  if ((*env)->ExceptionCheck(env)) {
+    return -1; // use negative value to indicate error!
+  }
+
+  if (DEBUG) printBytes("Update w/ data: ", (unsigned char*)bufIn, (size_t) inLen);
+
+  rv = JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII
+    (pCtxt, sign, inLen, bufIn, 0, inLen);
+
+  free(bufIn);
+  return rv;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeRSASignature
+ * Method:    nativeUpdate
+ * Signature: (JZJI)I
+ */
+jint JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZJI
+(jlong pCtxt, jboolean sign, jlong inAddr, jint inLen) {
+
+  return JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII
+    (pCtxt, sign, inLen, (jbyte*)inAddr, 0, inLen);
+}
+
+JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZJI
+(JNIEnv *env, jclass jCls, jlong pCtxt, jboolean sign, jlong inAddr, jint inLen) {
+
+  return JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeUpdate__JZ_3BII
+    (pCtxt, sign, inLen, (jbyte*)inAddr, 0, inLen);
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeRSASignature
+ * Method:    nativeFinal
+ * Signature: (JZ[BII)I
+ */
+jint JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal
+(jlong pCtxt, jboolean sign, int notUsed, jbyte* bufSig, jint sigOfs, jint jSigLen) {
+
+  crypto_ctx_t *context;
+  int rv = 0;
+  size_t sigLength = (size_t) jSigLen;
+
+  context = (crypto_ctx_t *) pCtxt;
+  if (DEBUG) {
+      printf("Signature final: 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);
+  }
+  if (sign) {
+    rv = (*ftab->ucryptoSignFinal)(context, (uchar_t *) (bufSig + sigOfs), &sigLength);
+  } else {
+    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);
+    }
+    if (sign) {
+      printBytes("After nativeFinal: ", (unsigned char*) (bufSig + sigOfs), jSigLen);
+    }
+  }
+
+  free(context);
+  if (rv) {
+    return -rv;
+  } else return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal
+(JNIEnv *env, jclass jCls, jlong pCtxt, jboolean sign, jbyteArray jSig, jint jSigOfs, jint jSigLen) {
+  int rv = 0;
+  jbyte* bufSig = NULL;
+
+  if (jSigLen != 0) {
+    bufSig = calloc(jSigLen, sizeof(char));
+    if (bufSig == NULL) {
+      throwOutOfMemoryError(env, NULL);
+      return 0;
+    }
+    if (!sign) {
+      // need to copy over the to-be-verified signature bytes
+      (*env)->GetByteArrayRegion(env, jSig, jSigOfs, jSigLen, (jbyte *)bufSig);
+    }
+  }
+
+  if (!(*env)->ExceptionCheck(env)) {
+    // Frees context + converts rv to negative if error occurred
+    rv = JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeFinal
+      (pCtxt, sign, jSigLen, bufSig, 0, jSigLen);
+
+    if (rv == 0 && sign) {
+      // need to copy the generated signature bytes to the java bytearray
+      (*env)->SetByteArrayRegion(env, jSig, jSigOfs, jSigLen, (jbyte *)bufSig);
+    }
+  } else {
+    // set rv to negative to indicate error
+    rv = -1;
+  }
+
+  free(bufSig);
+
+  return rv;
+}
+
+/*
+ * Class:     com_oracle_security_ucrypto_NativeRSACipher
+ * Method:    nativeAtomic
+ * Signature: (IZJI[BI[BII)I
+ */
+jint JavaCritical_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic
+  (jint mech, jboolean encrypt, jlong keyValue, jint keyLength,
+   int notUsed1, jbyte* bufIn, jint jInLen,
+   int notUsed2, jbyte* bufOut, jint jOutOfs, jint jOutLen) {
+
+  uchar_t *pKey;
+  crypto_object_attribute_t* pKey2;
+  int rv = 0;
+  size_t outLength = (size_t) jOutLen;
+
+  pKey = (uchar_t *) keyValue;
+  if (DEBUG) {
+    printf("Cipher 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);
+  }
+
+  if (encrypt) {
+    rv = (*ftab->ucryptoEncrypt)((ucrypto_mech_t)mech, pKey, (size_t)keyLength,
+      NULL, 0, (uchar_t *)bufIn, (size_t)jInLen,
+      (uchar_t *)(bufOut + jOutOfs), &outLength);
+  } else {
+    rv = (*ftab->ucryptoDecrypt)((ucrypto_mech_t)mech, pKey, (size_t)keyLength,
+      NULL, 0, (uchar_t *)bufIn, (size_t)jInLen,
+      (uchar_t *)(bufOut + jOutOfs), &outLength);
+  }
+  if (DEBUG) {
+    printf("Cipher nativeAtomic, ret =>  0x%x\n", rv);
+    if (outLength != jOutLen) {
+      printf("CIP actual output len=%d\n", outLength);
+    }
+    printBytes("After nativeAtomic: ", (unsigned char*) (bufOut + jOutOfs), outLength);
+  }
+
+  if (rv) {
+    return -rv;
+  } else return outLength;
+}
+
+JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic
+  (JNIEnv *env, jclass jCls, jint mech, jboolean encrypt,
+   jlong keyValue, jint keyLength, jbyteArray jIn, jint jInLen,
+   jbyteArray jOut, jint jOutOfs, jint jOutLen) {
+  int rv = 0;
+  jbyte *bufIn = NULL;
+  jbyte *bufOut = NULL;
+
+  if (jInLen != 0) {
+    bufIn = (*env)->GetByteArrayElements(env, jIn, NULL);
+    if (bufIn == NULL) {
+      return 0;
+    }
+  }
+  bufOut = calloc(jOutLen, sizeof(jbyte));
+  if (bufOut == NULL) {
+    (*env)->ReleaseByteArrayElements(env, jIn, bufIn, 0);
+    throwOutOfMemoryError(env, NULL);
+    return 0;
+  }
+
+  // rv: output length or error code (if negative)
+  rv = JavaCritical_com_oracle_security_ucrypto_NativeRSACipher_nativeAtomic
+    (mech, encrypt, keyValue, keyLength, jInLen, bufIn, jInLen,
+     jOutLen, bufOut, 0, jOutLen);
+
+  if (rv > 0) {
+    (*env)->SetByteArrayRegion(env, jOut, jOutOfs, rv, (jbyte *)bufOut);
+  }
+
+  if (bufIn != NULL) {
+    (*env)->ReleaseByteArrayElements(env, jIn, bufIn, 0);
+  }
+  free(bufOut);
+  return rv;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.h	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,50 @@
+/*
+ * 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 _Included_com_oracle_security_ucrypto_NativeCrypto
+#define _Included_com_oracle_security_ucrypto_NativeCrypto
+#ifdef __cplusplus
+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
+
+#define DEBUG 0
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.c	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+#include <jni.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <link.h>
+#include "nativeFunc.h"
+
+/* standard md5/md/softcrypto method names (ordering is from mapfile) */
+static const char MD5_INIT[]                     = "MD5Init";
+static const char MD5_UPDATE[]                   = "MD5Update";
+static const char MD5_FINAL[]                    = "MD5Final";
+static const char SHA1_INIT[]                    = "SHA1Init";
+static const char SHA1_UPDATE[]                  = "SHA1Update";
+static const char SHA1_FINAL[]                   = "SHA1Final";
+static const char SHA2_INIT[]                    = "SHA2Init";
+static const char SHA2_UPDATE[]                  = "SHA2Update";
+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";
+
+/**
+ * Initialize native T4 crypto function pointers
+ */
+jboolean* loadNative() {
+
+  jboolean* buf;
+  void *lib;
+
+  buf = malloc(2 * sizeof(jboolean));
+  buf[0] = buf[1] = JNI_FALSE;
+  ftab = (T4CRYPTO_FUNCTION_TABLE_PTR) calloc(1, sizeof(T4CRYPTO_FUNCTION_TABLE));
+  if (ftab == NULL) {
+    free(buf);
+    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
+    ftab->ucryptoVersion = (UCRYPTO_VERSION_FN_PTR)
+      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)
+      dlsym(lib, UCRYPTO_SIGN_UPDATE);
+    ftab->ucryptoSignFinal = (UCRYPTO_SIGN_FINAL_FN_PTR)
+      dlsym(lib, UCRYPTO_SIGN_FINAL);
+    ftab->ucryptoVerifyInit = (UCRYPTO_VERIFY_INIT_FN_PTR)
+      dlsym(lib, UCRYPTO_VERIFY_INIT);
+    ftab->ucryptoVerifyUpdate = (UCRYPTO_VERIFY_UPDATE_FN_PTR)
+      dlsym(lib, UCRYPTO_VERIFY_UPDATE);
+    ftab->ucryptoVerifyFinal = (UCRYPTO_VERIFY_FINAL_FN_PTR)
+      dlsym(lib, UCRYPTO_VERIFY_FINAL);
+
+    // These should be avilable for all libsoftcrypto libs
+    ftab->ucryptoEncryptInit = (UCRYPTO_ENCRYPT_INIT_FN_PTR)
+      dlsym(lib, UCRYPTO_ENCRYPT_INIT);
+    ftab->ucryptoEncryptUpdate = (UCRYPTO_ENCRYPT_UPDATE_FN_PTR)
+      dlsym(lib, UCRYPTO_ENCRYPT_UPDATE);
+    ftab->ucryptoEncryptFinal = (UCRYPTO_ENCRYPT_FINAL_FN_PTR)
+      dlsym(lib, UCRYPTO_ENCRYPT_FINAL);
+    ftab->ucryptoEncrypt = (UCRYPTO_ENCRYPT_FN_PTR)
+      dlsym(lib, UCRYPTO_ENCRYPT);
+
+    ftab->ucryptoDecryptInit = (UCRYPTO_DECRYPT_INIT_FN_PTR)
+      dlsym(lib, UCRYPTO_DECRYPT_INIT);
+    ftab->ucryptoDecryptUpdate = (UCRYPTO_DECRYPT_UPDATE_FN_PTR)
+      dlsym(lib, UCRYPTO_DECRYPT_UPDATE);
+    ftab->ucryptoDecryptFinal = (UCRYPTO_DECRYPT_FINAL_FN_PTR)
+      dlsym(lib, UCRYPTO_DECRYPT_FINAL);
+    ftab->ucryptoDecrypt = (UCRYPTO_DECRYPT_FN_PTR)
+      dlsym(lib, UCRYPTO_DECRYPT);
+
+    if (ftab->ucryptoEncryptInit != NULL &&
+        ftab->ucryptoEncryptUpdate != NULL &&
+        ftab->ucryptoEncryptFinal != NULL &&
+        ftab->ucryptoEncrypt != NULL &&
+        ftab->ucryptoDecryptInit != NULL &&
+        ftab->ucryptoDecryptUpdate != NULL &&
+        ftab->ucryptoDecryptFinal != NULL &&
+        ftab->ucryptoDecrypt != NULL) {
+      buf[1] = JNI_TRUE;
+    } else {
+      dlclose(lib);
+    }
+  }
+
+  return buf;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeFunc.h	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,163 @@
+/*
+ * 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 SPARCT4_NATIVE_FUNC_H
+#define SPARCT4_NATIVE_FUNC_H
+#include <md5.h>
+#include <sha1.h>
+#include <sha2.h>
+#include <libsoftcrypto.h>
+
+jboolean* loadNative();
+
+/* function pointer definitions */
+
+typedef void (*MD5INIT_FN_PTR)(MD5_CTX *context);
+
+typedef void (*MD5UPDATE_FN_PTR)
+     (MD5_CTX *context, unsigned char *input,
+      unsigned int inlen);
+
+typedef void (*MD5FINAL_FN_PTR)
+     (unsigned char *output, MD5_CTX *context);
+
+typedef void (*SHA1INIT_FN_PTR)(SHA1_CTX *context);
+
+typedef void (*SHA1UPDATE_FN_PTR)
+     (SHA1_CTX *context, unsigned char *input,
+      unsigned int inlen);
+
+typedef void (*SHA1FINAL_FN_PTR)
+     (unsigned char *output, SHA1_CTX *context);
+
+typedef void (*SHA2INIT_FN_PTR)(uint64_t mech, SHA2_CTX *context);
+
+typedef void (*SHA2UPDATE_FN_PTR)
+     (SHA2_CTX *context, unsigned char *input,
+      unsigned int inlen);
+
+typedef void (*SHA2FINAL_FN_PTR)
+     (unsigned char *output, SHA2_CTX *context);
+
+typedef int (*UCRYPTO_VERSION_FN_PTR)();
+
+typedef int (*UCRYPTO_GET_MECHLIST_FN_PTR)(char *str);
+
+typedef int (*UCRYPTO_ENCRYPT_INIT_FN_PTR)
+     (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,
+      size_t in_len, uchar_t *out, size_t *out_len);
+
+typedef int (*UCRYPTO_DECRYPT_INIT_FN_PTR)
+     (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,
+      size_t in_len, uchar_t *out, size_t *out_len);
+
+typedef int (*UCRYPTO_SIGN_INIT_FN_PTR)
+     (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);
+
+typedef int (*UCRYPTO_VERIFY_INIT_FN_PTR)
+     (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);
+
+
+
+/* dynamically resolved functions from libmd, and libsoftcrypto
+   libraries */
+typedef struct T4CRYPTO_FUNCTION_TABLE {
+  MD5INIT_FN_PTR                 md5Init;
+  MD5UPDATE_FN_PTR               md5Update;
+  MD5FINAL_FN_PTR                md5Final;
+  SHA1INIT_FN_PTR                sha1Init;
+  SHA1UPDATE_FN_PTR              sha1Update;
+  SHA1FINAL_FN_PTR               sha1Final;
+  SHA2INIT_FN_PTR                sha2Init;
+  SHA2UPDATE_FN_PTR              sha2Update;
+  SHA2FINAL_FN_PTR               sha2Final;
+  UCRYPTO_VERSION_FN_PTR         ucryptoVersion;
+  UCRYPTO_GET_MECHLIST_FN_PTR    ucryptoGetMechList;
+  UCRYPTO_ENCRYPT_INIT_FN_PTR    ucryptoEncryptInit;
+  UCRYPTO_ENCRYPT_UPDATE_FN_PTR  ucryptoEncryptUpdate;
+  UCRYPTO_ENCRYPT_FINAL_FN_PTR   ucryptoEncryptFinal;
+  UCRYPTO_ENCRYPT_FN_PTR         ucryptoEncrypt;
+  UCRYPTO_DECRYPT_INIT_FN_PTR    ucryptoDecryptInit;
+  UCRYPTO_DECRYPT_UPDATE_FN_PTR  ucryptoDecryptUpdate;
+  UCRYPTO_DECRYPT_FINAL_FN_PTR   ucryptoDecryptFinal;
+  UCRYPTO_DECRYPT_FN_PTR         ucryptoDecrypt;
+  UCRYPTO_SIGN_INIT_FN_PTR       ucryptoSignInit;
+  UCRYPTO_SIGN_UPDATE_FN_PTR     ucryptoSignUpdate;
+  UCRYPTO_SIGN_FINAL_FN_PTR      ucryptoSignFinal;
+  UCRYPTO_VERIFY_INIT_FN_PTR     ucryptoVerifyInit;
+  UCRYPTO_VERIFY_UPDATE_FN_PTR   ucryptoVerifyUpdate;
+  UCRYPTO_VERIFY_FINAL_FN_PTR    ucryptoVerifyFinal;
+} T4CRYPTO_FUNCTION_TABLE;
+
+typedef T4CRYPTO_FUNCTION_TABLE *T4CRYPTO_FUNCTION_TABLE_PTR;
+
+/* global function table */
+T4CRYPTO_FUNCTION_TABLE_PTR ftab;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/sys_old/crypto/common.h	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2003, 2011, 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 _SYS_CRYPTO_COMMON_H
+#define _SYS_CRYPTO_COMMON_H
+
+/*
+ * Header file for the common data structures of the cryptographic framework
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stream.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+
+/* Convenience defines/macros */
+
+#define CRYPTO_ARG_INPLACE(input, output)    \
+    if ((output) == NULL)        \
+        (output) = (input);
+
+#ifdef _KERNEL
+
+#include <sys/kmem.h>
+#define CRYPTO_KMFLAG(x)        crypto_kmflag((x))
+#define CRYPTO_ALLOC(sz, kmflag)        kmem_alloc((sz), (kmflag))
+#define CRYPTO_ZALLOC(sz, kmflag)        kmem_zalloc((sz), (kmflag))
+#define CRYPTO_FREE(ptr, sz)        kmem_free((ptr), (sz))
+#define CRYPTO_ZFREE(ptr, sz)        if (ptr != NULL) { \
+                                         bzero((ptr), (sz)), \
+                                         kmem_free((ptr), (sz)); \
+                                     }
+
+#else /* _KERNEL */
+
+#include <malloc.h>
+#define    CRYPTO_KMFLAG(x)        (0)
+#define    CRYPTO_ALLOC(sz, kmflag)        malloc((sz))
+#define    CRYPTO_ZALLOC(sz, kmflag)        calloc(1, (sz))
+#define    CRYPTO_FREE(ptr, sz)        free((ptr))
+#define    CRYPTO_ZFREE(ptr, sz)        if (ptr != NULL) { \
+                                         bzero((ptr), (sz)), \
+                                         free((ptr)); \
+                                     }
+
+#endif /* _KERNEL */
+
+/* Cryptographic Mechanisms */
+
+#define    CRYPTO_MAX_MECH_NAME 32
+typedef char crypto_mech_name_t[CRYPTO_MAX_MECH_NAME];
+
+typedef uint64_t crypto_mech_type_t;
+
+typedef struct crypto_mechanism {
+    crypto_mech_type_t    cm_type;    /* mechanism type */
+    caddr_t            cm_param;    /* mech. parameter */
+    size_t            cm_param_len;    /* mech. parameter len */
+} crypto_mechanism_t;
+
+#ifdef  _SYSCALL32
+
+typedef struct crypto_mechanism32 {
+    crypto_mech_type_t    cm_type;    /* mechanism type */
+    caddr32_t        cm_param;    /* mech. parameter */
+    size32_t        cm_param_len;   /* mech. parameter len */
+} crypto_mechanism32_t;
+
+#endif  /* _SYSCALL32 */
+
+#ifdef _KERNEL
+/* CK_AES_CTR_PARAMS provides parameters to the CKM_AES_CTR mechanism */
+typedef struct CK_AES_CTR_PARAMS {
+    ulong_t    ulCounterBits;
+    uint8_t cb[16];
+} CK_AES_CTR_PARAMS;
+#endif
+
+/* CK_AES_CCM_PARAMS provides parameters to the CKM_AES_CCM mechanism */
+typedef struct CK_AES_CCM_PARAMS {
+    ulong_t ulMACSize;
+    ulong_t ulNonceSize;
+    ulong_t ulAuthDataSize;
+    ulong_t ulDataSize; /* used for plaintext or ciphertext */
+    uchar_t *nonce;
+    uchar_t *authData;
+} CK_AES_CCM_PARAMS;
+
+/* CK_AES_GCM_PARAMS provides parameters to the CKM_AES_GCM mechanism */
+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;
+
+/* CK_AES_GMAC_PARAMS provides parameters to the CKM_AES_GMAC mechanism */
+typedef struct CK_AES_GMAC_PARAMS {
+    uchar_t *pIv;
+    uchar_t *pAAD;
+    ulong_t ulAADLen;
+} CK_AES_GMAC_PARAMS;
+
+#ifdef _KERNEL
+/*
+ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_KEY_DERIVE mechanism
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+    ulong_t        kdf;
+    ulong_t        ulSharedDataLen;
+    uchar_t        *pSharedData;
+    ulong_t        ulPublicDataLen;
+    uchar_t        *pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+#endif
+
+#ifdef _KERNEL
+#ifdef  _SYSCALL32
+
+/* needed for 32-bit applications running on 64-bit kernels */
+typedef struct CK_AES_CTR_PARAMS32 {
+    uint32_t ulCounterBits;
+    uint8_t cb[16];
+} CK_AES_CTR_PARAMS32;
+
+/* needed for 32-bit applications running on 64-bit kernels */
+typedef struct CK_AES_CCM_PARAMS32 {
+    uint32_t ulMACSize;
+    uint32_t ulNonceSize;
+    uint32_t ulAuthDataSize;
+    uint32_t ulDataSize;
+    caddr32_t nonce;
+    caddr32_t authData;
+} CK_AES_CCM_PARAMS32;
+
+/* needed for 32-bit applications running on 64-bit kernels */
+typedef struct CK_AES_GCM_PARAMS32 {
+    caddr32_t pIv;
+    uint32_t ulIvLen;
+    uint32_t ulIvBits;
+    caddr32_t pAAD;
+    uint32_t ulAADLen;
+    uint32_t ulTagBits;
+} CK_AES_GCM_PARAMS32;
+
+/* needed for 32-bit applications running on 64-bit kernels */
+typedef struct CK_AES_GMAC_PARAMS32 {
+    caddr32_t pIv;
+    caddr32_t pAAD;
+    uint32_t ulAADLen;
+} CK_AES_GMAC_PARAMS32;
+
+typedef struct CK_ECDH1_DERIVE_PARAMS32 {
+    uint32_t    kdf;
+    uint32_t    ulSharedDataLen;
+    caddr32_t    pSharedData;
+    uint32_t    ulPublicDataLen;
+    caddr32_t    pPublicData;
+} CK_ECDH1_DERIVE_PARAMS32;
+
+#endif  /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+/*
+ * The measurement unit bit flag for a mechanism's minimum or maximum key size.
+ * The unit are mechanism dependent.  It can be in bits or in bytes.
+ */
+typedef uint32_t crypto_keysize_unit_t;
+
+/*
+ * The following bit flags are valid in cm_mech_flags field in
+ * the crypto_mech_info_t structure of the SPI.
+ *
+ * Only the first two bit flags are valid in mi_keysize_unit
+ * field in the crypto_mechanism_info_t structure of the API.
+ */
+#define    CRYPTO_KEYSIZE_UNIT_IN_BITS    0x00000001
+#define    CRYPTO_KEYSIZE_UNIT_IN_BYTES    0x00000002
+#define    CRYPTO_CAN_SHARE_OPSTATE    0x00000004 /* supports sharing */
+
+
+/* Mechanisms supported out-of-the-box */
+#define    SUN_CKM_MD4            "CKM_MD4"
+#define    SUN_CKM_MD5            "CKM_MD5"
+#define    SUN_CKM_MD5_HMAC        "CKM_MD5_HMAC"
+#define    SUN_CKM_MD5_HMAC_GENERAL    "CKM_MD5_HMAC_GENERAL"
+#define    SUN_CKM_SHA1            "CKM_SHA_1"
+#define    SUN_CKM_SHA1_HMAC        "CKM_SHA_1_HMAC"
+#define    SUN_CKM_SHA1_HMAC_GENERAL    "CKM_SHA_1_HMAC_GENERAL"
+#define    SUN_CKM_SHA256            "CKM_SHA256"
+#define    SUN_CKM_SHA256_HMAC        "CKM_SHA256_HMAC"
+#define    SUN_CKM_SHA256_HMAC_GENERAL    "CKM_SHA256_HMAC_GENERAL"
+#define    SUN_CKM_SHA384            "CKM_SHA384"
+#define    SUN_CKM_SHA384_HMAC        "CKM_SHA384_HMAC"
+#define    SUN_CKM_SHA384_HMAC_GENERAL    "CKM_SHA384_HMAC_GENERAL"
+#define    SUN_CKM_SHA512            "CKM_SHA512"
+#define    SUN_CKM_SHA512_HMAC        "CKM_SHA512_HMAC"
+#define    SUN_CKM_SHA512_HMAC_GENERAL    "CKM_SHA512_HMAC_GENERAL"
+#define    SUN_CKM_DES_CBC            "CKM_DES_CBC"
+#define    SUN_CKM_DES3_CBC        "CKM_DES3_CBC"
+#define    SUN_CKM_DES_ECB            "CKM_DES_ECB"
+#define    SUN_CKM_DES3_ECB        "CKM_DES3_ECB"
+#define    SUN_CKM_BLOWFISH_CBC        "CKM_BLOWFISH_CBC"
+#define    SUN_CKM_BLOWFISH_ECB        "CKM_BLOWFISH_ECB"
+#define    SUN_CKM_AES_CBC            "CKM_AES_CBC"
+#define    SUN_CKM_AES_ECB            "CKM_AES_ECB"
+#define    SUN_CKM_AES_CTR            "CKM_AES_CTR"
+#define    SUN_CKM_AES_CCM            "CKM_AES_CCM"
+#define    SUN_CKM_AES_GCM            "CKM_AES_GCM"
+#define    SUN_CKM_AES_GMAC        "CKM_AES_GMAC"
+#define    SUN_CKM_AES_CFB128        "CKM_AES_CFB128"
+#define    SUN_CKM_RC4            "CKM_RC4"
+#define    SUN_CKM_RSA_PKCS        "CKM_RSA_PKCS"
+#define    SUN_CKM_RSA_X_509        "CKM_RSA_X_509"
+#define    SUN_CKM_MD5_RSA_PKCS        "CKM_MD5_RSA_PKCS"
+#define    SUN_CKM_SHA1_RSA_PKCS        "CKM_SHA1_RSA_PKCS"
+#define    SUN_CKM_SHA256_RSA_PKCS        "CKM_SHA256_RSA_PKCS"
+#define    SUN_CKM_SHA384_RSA_PKCS        "CKM_SHA384_RSA_PKCS"
+#define    SUN_CKM_SHA512_RSA_PKCS        "CKM_SHA512_RSA_PKCS"
+#define    SUN_CKM_EC_KEY_PAIR_GEN        "CKM_EC_KEY_PAIR_GEN"
+#define    SUN_CKM_ECDH1_DERIVE        "CKM_ECDH1_DERIVE"
+#define    SUN_CKM_ECDSA_SHA1        "CKM_ECDSA_SHA1"
+#define    SUN_CKM_ECDSA            "CKM_ECDSA"
+
+/* Shared operation context format for CKM_RC4 */
+typedef struct {
+#if defined(__amd64)
+    uint32_t    i, j;
+    uint32_t    arr[256];
+    uint32_t    flag;
+#else
+    uchar_t        arr[256];
+    uchar_t        i, j;
+#endif /* __amd64 */
+    uint64_t    pad;        /* For 64-bit alignment */
+} arcfour_state_t;
+
+/* Data arguments of cryptographic operations */
+
+typedef enum crypto_data_format {
+    CRYPTO_DATA_RAW = 1,
+    CRYPTO_DATA_UIO,
+    CRYPTO_DATA_MBLK
+} crypto_data_format_t;
+
+typedef struct crypto_data {
+    crypto_data_format_t    cd_format;    /* Format identifier    */
+    off_t            cd_offset;    /* Offset from the beginning */
+    size_t            cd_length;    /* # of bytes in use */
+    caddr_t            cd_miscdata;    /* ancillary data */
+    union {
+        /* Raw format */
+        iovec_t cdu_raw;        /* Pointer and length        */
+
+        /* uio scatter-gather format */
+        uio_t    *cdu_uio;
+
+        /* mblk scatter-gather format */
+        mblk_t    *cdu_mp;        /* The mblk chain */
+
+    } cdu;    /* Crypto Data Union */
+} crypto_data_t;
+
+#define    cd_raw        cdu.cdu_raw
+#define    cd_uio        cdu.cdu_uio
+#define    cd_mp        cdu.cdu_mp
+
+#define    CRYPTO_SET_RAW_DATA(var, str, len)    \
+    (var).cd_format = CRYPTO_DATA_RAW;    \
+    (var).cd_offset = 0;            \
+    (var).cd_length = (len);        \
+    (var).cd_miscdata = NULL;        \
+    (var).cd_raw.iov_base = (caddr_t)(str);    \
+    (var).cd_raw.iov_len = (len);
+
+#define    CRYPTO_DATA_IS_USERSPACE(buf) \
+    ((buf->cd_format == CRYPTO_DATA_UIO && \
+    buf->cd_uio->uio_segflg == UIO_USERSPACE))
+
+typedef struct crypto_dual_data {
+    crypto_data_t        dd_data;    /* The data */
+    off_t            dd_offset2;    /* Used by dual operation */
+    size_t            dd_len2;    /* # of bytes to take    */
+} crypto_dual_data_t;
+
+#define    dd_format    dd_data.cd_format
+#define    dd_offset1    dd_data.cd_offset
+#define    dd_len1        dd_data.cd_length
+#define    dd_miscdata    dd_data.cd_miscdata
+#define    dd_raw        dd_data.cd_raw
+#define    dd_uio        dd_data.cd_uio
+#define    dd_mp        dd_data.cd_mp
+
+/* The keys, and their contents */
+
+typedef enum {
+    CRYPTO_KEY_RAW = 1,    /* ck_data is a cleartext key */
+    CRYPTO_KEY_REFERENCE,    /* ck_obj_id is an opaque reference */
+    CRYPTO_KEY_ATTR_LIST    /* ck_attrs is a list of object attributes */
+} crypto_key_format_t;
+
+typedef uint64_t crypto_attr_type_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
+
+typedef uint32_t    crypto_object_id_t;
+
+typedef struct crypto_object_attribute {
+    crypto_attr_type_t    oa_type;    /* attribute type */
+    caddr_t            oa_value;    /* attribute value */
+    ssize_t            oa_value_len;    /* length of attribute value */
+} crypto_object_attribute_t;
+
+typedef struct crypto_key {
+    crypto_key_format_t    ck_format;    /* format identifier */
+    union {
+        /* for CRYPTO_KEY_RAW ck_format */
+        struct {
+            uint_t    cku_v_length;    /* # of bits in ck_data   */
+            void    *cku_v_data;    /* ptr to key value */
+        } cku_key_value;
+
+        /* for CRYPTO_KEY_REFERENCE ck_format */
+        crypto_object_id_t cku_key_id;    /* reference to object key */
+
+        /* for CRYPTO_KEY_ATTR_LIST ck_format */
+        struct {
+            uint_t cku_a_count;    /* number of attributes */
+            crypto_object_attribute_t *cku_a_oattr;
+        } cku_key_attrs;
+    } cku_data;                /* Crypto Key union */
+} crypto_key_t;
+
+#ifdef  _SYSCALL32
+
+typedef struct crypto_object_attribute32 {
+    uint64_t    oa_type;    /* attribute type */
+    caddr32_t    oa_value;    /* attribute value */
+    ssize32_t    oa_value_len;    /* length of attribute value */
+} crypto_object_attribute32_t;
+
+typedef struct crypto_key32 {
+    crypto_key_format_t    ck_format;    /* format identifier */
+    union {
+        /* for CRYPTO_KEY_RAW ck_format */
+        struct {
+            uint32_t cku_v_length;    /* # of bytes in ck_data */
+            caddr32_t cku_v_data;    /* ptr to key value */
+        } cku_key_value;
+
+        /* for CRYPTO_KEY_REFERENCE ck_format */
+        crypto_object_id_t cku_key_id; /* reference to object key */
+
+        /* for CRYPTO_KEY_ATTR_LIST ck_format */
+        struct {
+            uint32_t cku_a_count;    /* number of attributes */
+            caddr32_t cku_a_oattr;
+        } cku_key_attrs;
+    } cku_data;                /* Crypto Key union */
+} crypto_key32_t;
+
+#endif  /* _SYSCALL32 */
+
+#define    ck_data        cku_data.cku_key_value.cku_v_data
+#define    ck_length    cku_data.cku_key_value.cku_v_length
+#define    ck_obj_id    cku_data.cku_key_id
+#define    ck_count    cku_data.cku_key_attrs.cku_a_count
+#define    ck_attrs    cku_data.cku_key_attrs.cku_a_oattr
+
+/*
+ * Raw key lengths are expressed in number of bits.
+ * The following macro returns the minimum number of
+ * bytes that can contain the specified number of bits.
+ * Round up without overflowing the integer type.
+ */
+#define    CRYPTO_BITS2BYTES(n) ((n) == 0 ? 0 : (((n) - 1) >> 3) + 1)
+#define    CRYPTO_BYTES2BITS(n) ((n) << 3)
+
+/* Providers */
+
+typedef enum {
+    CRYPTO_HW_PROVIDER = 0,
+    CRYPTO_SW_PROVIDER,
+    CRYPTO_LOGICAL_PROVIDER
+} crypto_provider_type_t;
+
+typedef uint32_t     crypto_provider_id_t;
+#define    KCF_PROVID_INVALID    ((uint32_t)-1)
+
+typedef struct crypto_provider_entry {
+    crypto_provider_id_t    pe_provider_id;
+    uint_t            pe_mechanism_count;
+} crypto_provider_entry_t;
+
+typedef struct crypto_dev_list_entry {
+    char            le_dev_name[MAXNAMELEN];
+    uint_t            le_dev_instance;
+    uint_t            le_mechanism_count;
+} crypto_dev_list_entry_t;
+
+/* User type for authentication ioctls and SPI entry points */
+
+typedef enum crypto_user_type {
+    CRYPTO_SO = 0,
+    CRYPTO_USER
+} crypto_user_type_t;
+
+/* Version for provider management ioctls and SPI entry points */
+
+typedef struct crypto_version {
+    uchar_t    cv_major;
+    uchar_t    cv_minor;
+} crypto_version_t;
+
+/* session data structure opaque to the consumer */
+typedef void *crypto_session_t;
+
+/* provider data structure opaque to the consumer */
+typedef void *crypto_provider_t;
+
+/* Limits used by both consumers and providers */
+#define    CRYPTO_EXT_SIZE_LABEL        32
+#define    CRYPTO_EXT_SIZE_MANUF        32
+#define    CRYPTO_EXT_SIZE_MODEL        16
+#define    CRYPTO_EXT_SIZE_SERIAL        16
+#define    CRYPTO_EXT_SIZE_TIME        16
+
+typedef struct crypto_provider_ext_info {
+    uchar_t            ei_label[CRYPTO_EXT_SIZE_LABEL];
+    uchar_t            ei_manufacturerID[CRYPTO_EXT_SIZE_MANUF];
+    uchar_t            ei_model[CRYPTO_EXT_SIZE_MODEL];
+    uchar_t            ei_serial_number[CRYPTO_EXT_SIZE_SERIAL];
+    ulong_t            ei_flags;
+    ulong_t            ei_max_session_count;
+    ulong_t            ei_max_pin_len;
+    ulong_t            ei_min_pin_len;
+    ulong_t            ei_total_public_memory;
+    ulong_t            ei_free_public_memory;
+    ulong_t            ei_total_private_memory;
+    ulong_t            ei_free_private_memory;
+    crypto_version_t    ei_hardware_version;
+    crypto_version_t    ei_firmware_version;
+    uchar_t            ei_time[CRYPTO_EXT_SIZE_TIME];
+    int            ei_hash_max_input_len;
+    int            ei_hmac_max_input_len;
+} crypto_provider_ext_info_t;
+
+typedef uint_t        crypto_session_id_t;
+
+typedef enum cmd_type {
+    COPY_FROM_DATA,
+    COPY_TO_DATA,
+    COMPARE_TO_DATA,
+    MD5_DIGEST_DATA,
+    SHA1_DIGEST_DATA,
+    SHA2_DIGEST_DATA,
+    GHASH_DATA
+} cmd_type_t;
+
+#define    CRYPTO_DO_UPDATE    0x01
+#define    CRYPTO_DO_FINAL        0x02
+#define    CRYPTO_DO_MD5        0x04
+#define    CRYPTO_DO_SHA1        0x08
+#define    CRYPTO_DO_SIGN        0x10
+#define    CRYPTO_DO_VERIFY    0x20
+#define    CRYPTO_DO_SHA2        0x40
+
+#define    PROVIDER_OWNS_KEY_SCHEDULE    0x00000001
+
+/*
+ * Common cryptographic status and error codes.
+ */
+#define    CRYPTO_SUCCESS                0x00000000
+#define    CRYPTO_CANCEL                0x00000001
+#define    CRYPTO_HOST_MEMORY            0x00000002
+#define    CRYPTO_GENERAL_ERROR            0x00000003
+#define    CRYPTO_FAILED                0x00000004
+#define    CRYPTO_ARGUMENTS_BAD            0x00000005
+#define    CRYPTO_ATTRIBUTE_READ_ONLY        0x00000006
+#define    CRYPTO_ATTRIBUTE_SENSITIVE        0x00000007
+#define    CRYPTO_ATTRIBUTE_TYPE_INVALID        0x00000008
+#define    CRYPTO_ATTRIBUTE_VALUE_INVALID        0x00000009
+#define    CRYPTO_CANCELED                0x0000000A
+#define    CRYPTO_DATA_INVALID            0x0000000B
+#define    CRYPTO_DATA_LEN_RANGE            0x0000000C
+#define    CRYPTO_DEVICE_ERROR            0x0000000D
+#define    CRYPTO_DEVICE_MEMORY            0x0000000E
+#define    CRYPTO_DEVICE_REMOVED            0x0000000F
+#define    CRYPTO_ENCRYPTED_DATA_INVALID        0x00000010
+#define    CRYPTO_ENCRYPTED_DATA_LEN_RANGE        0x00000011
+#define    CRYPTO_KEY_HANDLE_INVALID        0x00000012
+#define    CRYPTO_KEY_SIZE_RANGE            0x00000013
+#define    CRYPTO_KEY_TYPE_INCONSISTENT        0x00000014
+#define    CRYPTO_KEY_NOT_NEEDED            0x00000015
+#define    CRYPTO_KEY_CHANGED            0x00000016
+#define    CRYPTO_KEY_NEEDED            0x00000017
+#define    CRYPTO_KEY_INDIGESTIBLE            0x00000018
+#define    CRYPTO_KEY_FUNCTION_NOT_PERMITTED    0x00000019
+#define    CRYPTO_KEY_NOT_WRAPPABLE        0x0000001A
+#define    CRYPTO_KEY_UNEXTRACTABLE        0x0000001B
+#define    CRYPTO_MECHANISM_INVALID        0x0000001C
+#define    CRYPTO_MECHANISM_PARAM_INVALID        0x0000001D
+#define    CRYPTO_OBJECT_HANDLE_INVALID        0x0000001E
+#define    CRYPTO_OPERATION_IS_ACTIVE        0x0000001F
+#define    CRYPTO_OPERATION_NOT_INITIALIZED    0x00000020
+#define    CRYPTO_PIN_INCORRECT            0x00000021
+#define    CRYPTO_PIN_INVALID            0x00000022
+#define    CRYPTO_PIN_LEN_RANGE            0x00000023
+#define    CRYPTO_PIN_EXPIRED            0x00000024
+#define    CRYPTO_PIN_LOCKED            0x00000025
+#define    CRYPTO_SESSION_CLOSED            0x00000026
+#define    CRYPTO_SESSION_COUNT            0x00000027
+#define    CRYPTO_SESSION_HANDLE_INVALID        0x00000028
+#define    CRYPTO_SESSION_READ_ONLY        0x00000029
+#define    CRYPTO_SESSION_EXISTS            0x0000002A
+#define    CRYPTO_SESSION_READ_ONLY_EXISTS        0x0000002B
+#define    CRYPTO_SESSION_READ_WRITE_SO_EXISTS    0x0000002C
+#define    CRYPTO_SIGNATURE_INVALID        0x0000002D
+#define    CRYPTO_SIGNATURE_LEN_RANGE        0x0000002E
+#define    CRYPTO_TEMPLATE_INCOMPLETE        0x0000002F
+#define    CRYPTO_TEMPLATE_INCONSISTENT        0x00000030
+#define    CRYPTO_UNWRAPPING_KEY_HANDLE_INVALID    0x00000031
+#define    CRYPTO_UNWRAPPING_KEY_SIZE_RANGE    0x00000032
+#define    CRYPTO_UNWRAPPING_KEY_TYPE_INCONSISTENT    0x00000033
+#define    CRYPTO_USER_ALREADY_LOGGED_IN        0x00000034
+#define    CRYPTO_USER_NOT_LOGGED_IN        0x00000035
+#define    CRYPTO_USER_PIN_NOT_INITIALIZED        0x00000036
+#define    CRYPTO_USER_TYPE_INVALID        0x00000037
+#define    CRYPTO_USER_ANOTHER_ALREADY_LOGGED_IN    0x00000038
+#define    CRYPTO_USER_TOO_MANY_TYPES        0x00000039
+#define    CRYPTO_WRAPPED_KEY_INVALID        0x0000003A
+#define    CRYPTO_WRAPPED_KEY_LEN_RANGE        0x0000003B
+#define    CRYPTO_WRAPPING_KEY_HANDLE_INVALID    0x0000003C
+#define    CRYPTO_WRAPPING_KEY_SIZE_RANGE        0x0000003D
+#define    CRYPTO_WRAPPING_KEY_TYPE_INCONSISTENT    0x0000003E
+#define    CRYPTO_RANDOM_SEED_NOT_SUPPORTED    0x0000003F
+#define    CRYPTO_RANDOM_NO_RNG            0x00000040
+#define    CRYPTO_DOMAIN_PARAMS_INVALID        0x00000041
+#define    CRYPTO_BUFFER_TOO_SMALL            0x00000042
+#define    CRYPTO_INFORMATION_SENSITIVE        0x00000043
+#define    CRYPTO_NOT_SUPPORTED            0x00000044
+
+#define    CRYPTO_QUEUED                0x00000045
+#define    CRYPTO_BUFFER_TOO_BIG            0x00000046
+#define    CRYPTO_INVALID_CONTEXT            0x00000047
+#define    CRYPTO_INVALID_MAC            0x00000048
+#define    CRYPTO_MECH_NOT_SUPPORTED        0x00000049
+#define    CRYPTO_INCONSISTENT_ATTRIBUTE        0x0000004A
+#define    CRYPTO_NO_PERMISSION            0x0000004B
+#define    CRYPTO_INVALID_PROVIDER_ID        0x0000004C
+#define    CRYPTO_VERSION_MISMATCH            0x0000004D
+#define    CRYPTO_BUSY                0x0000004E
+#define    CRYPTO_UNKNOWN_PROVIDER            0x0000004F
+#define    CRYPTO_MODVERIFICATION_FAILED        0x00000050
+#define    CRYPTO_OLD_CTX_TEMPLATE            0x00000051
+#define    CRYPTO_WEAK_KEY                0x00000052
+#define    CRYPTO_FIPS140_ERROR            0x00000053
+/*
+ * Don't forget to update CRYPTO_LAST_ERROR and the error_number_table[]
+ * in kernelUtil.c when new error code is added.
+ */
+#define    CRYPTO_LAST_ERROR            0x00000053
+
+/*
+ * Special values that can be used to indicate that information is unavailable
+ * or that there is not practical limit. These values can be used
+ * by fields of the SPI crypto_provider_ext_info(9S) structure.
+ * The value of CRYPTO_UNAVAILABLE_INFO should be the same as
+ * CK_UNAVAILABLE_INFO in the PKCS#11 spec.
+ */
+#define    CRYPTO_UNAVAILABLE_INFO        ((ulong_t)(-1))
+#define    CRYPTO_EFFECTIVELY_INFINITE    0x0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CRYPTO_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/sys_old/crypto/spi.h	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,791 @@
+/*
+ * Copyright (c) 2003, 2011, 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 _SYS_CRYPTO_SPI_H
+#define    _SYS_CRYPTO_SPI_H
+
+/*
+ * CSPI: Cryptographic Service Provider Interface.
+ */
+
+#include <sys/types.h>
+#include <sys/crypto/common.h>
+
+#ifdef    __cplusplus
+extern "C" {
+#endif
+
+#ifdef    _KERNEL
+#include <sys/dditypes.h>
+#include <sys/ddi.h>
+#include <sys/kmem.h>
+
+#define    CRYPTO_SPI_VERSION_1    1
+#define    CRYPTO_SPI_VERSION_2    2
+#define    CRYPTO_SPI_VERSION_3    3
+#define    CRYPTO_SPI_VERSION_4    4
+#define    CRYPTO_SPI_VERSION_5    5
+
+#define    CRYPTO_OPS_OFFSET(f)        offsetof(crypto_ops_t, co_##f)
+#define    CRYPTO_PROVIDER_OFFSET(f)    \
+    offsetof(crypto_provider_management_ops_t, f)
+#define    CRYPTO_OBJECT_OFFSET(f)        offsetof(crypto_object_ops_t, f)
+#define    CRYPTO_SESSION_OFFSET(f)    offsetof(crypto_session_ops_t, f)
+
+#endif
+
+/*
+ * Provider-private handle. This handle is specified by a provider
+ * when it registers by means of the pi_provider_handle field of
+ * the crypto_provider_info structure, and passed to the provider
+ * when its entry points are invoked.
+ */
+typedef void *crypto_provider_handle_t;
+
+/*
+ * Context templates can be used to by software providers to pre-process
+ * keying material, such as key schedules. They are allocated by
+ * a software provider create_ctx_template(9E) entry point, and passed
+ * as argument to initialization and atomic provider entry points.
+ */
+typedef void *crypto_spi_ctx_template_t;
+
+/*
+ * Request handles are used by the kernel to identify an asynchronous
+ * request being processed by a provider. It is passed by the kernel
+ * to a hardware provider when submitting a request, and must be
+ * specified by a provider when calling crypto_op_notification(9F)
+ */
+typedef void *crypto_req_handle_t;
+
+/*
+ * The context structure is passed from kcf to a provider in kernel and
+ * internally in libsoftcrypto between ucrypto and the algorithm.
+ * It contains the information needed to process a multi-part or
+ * single part operation. The context structure is not used
+ * by atomic operations.
+ *
+ * Parameters needed to perform a cryptographic operation, such
+ * as keys, mechanisms, input and output buffers, are passed
+ * as separate arguments to Provider routines.
+ */
+typedef struct crypto_ctx {
+    crypto_provider_handle_t cc_provider;
+    crypto_session_id_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;
+
+#ifdef    _KERNEL
+
+/* Values for cc_flags field */
+#define    CRYPTO_INIT_OPSTATE    0x00000001 /* allocate and init cc_opstate */
+#define    CRYPTO_USE_OPSTATE    0x00000002 /* .. start using it as context */
+
+/*
+ * Extended provider information.
+ */
+
+/*
+ * valid values for ei_flags field of extended info structure
+ * They match the RSA Security, Inc PKCS#11 tokenInfo flags.
+ */
+#define    CRYPTO_EXTF_RNG                    0x00000001
+#define    CRYPTO_EXTF_WRITE_PROTECTED            0x00000002
+#define    CRYPTO_EXTF_LOGIN_REQUIRED            0x00000004
+#define    CRYPTO_EXTF_USER_PIN_INITIALIZED        0x00000008
+#define    CRYPTO_EXTF_CLOCK_ON_TOKEN            0x00000040
+#define    CRYPTO_EXTF_PROTECTED_AUTHENTICATION_PATH    0x00000100
+#define    CRYPTO_EXTF_DUAL_CRYPTO_OPERATIONS        0x00000200
+#define    CRYPTO_EXTF_TOKEN_INITIALIZED            0x00000400
+#define    CRYPTO_EXTF_USER_PIN_COUNT_LOW            0x00010000
+#define    CRYPTO_EXTF_USER_PIN_FINAL_TRY            0x00020000
+#define    CRYPTO_EXTF_USER_PIN_LOCKED            0x00040000
+#define    CRYPTO_EXTF_USER_PIN_TO_BE_CHANGED        0x00080000
+#define    CRYPTO_EXTF_SO_PIN_COUNT_LOW            0x00100000
+#define    CRYPTO_EXTF_SO_PIN_FINAL_TRY            0x00200000
+#define    CRYPTO_EXTF_SO_PIN_LOCKED            0x00400000
+#define    CRYPTO_EXTF_SO_PIN_TO_BE_CHANGED        0x00800000
+
+/*
+ * The crypto_control_ops structure contains pointers to control
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_control_ops {
+    void (*provider_status)(crypto_provider_handle_t, uint_t *);
+} crypto_control_ops_t;
+
+/*
+ * The crypto_ctx_ops structure contains points to context and context
+ * templates management operations for cryptographic providers. It is
+ * passed through the crypto_ops(9S) structure when providers register
+ * with the kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_ctx_ops {
+    int (*create_ctx_template)(crypto_provider_handle_t,
+        crypto_mechanism_t *, crypto_key_t *,
+        crypto_spi_ctx_template_t *, size_t *, crypto_req_handle_t);
+    int (*free_context)(crypto_ctx_t *);
+} crypto_ctx_ops_t;
+
+/*
+ * The crypto_digest_ops structure contains pointers to digest
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_digest_ops {
+    int (*digest_init)(crypto_ctx_t *, crypto_mechanism_t *,
+        crypto_req_handle_t);
+    int (*digest)(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
+        crypto_req_handle_t);
+    int (*digest_update)(crypto_ctx_t *, crypto_data_t *,
+        crypto_req_handle_t);
+    int (*digest_key)(crypto_ctx_t *, crypto_key_t *, crypto_req_handle_t);
+    int (*digest_final)(crypto_ctx_t *, crypto_data_t *,
+        crypto_req_handle_t);
+    int (*digest_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_data_t *,
+        crypto_data_t *, crypto_req_handle_t);
+} crypto_digest_ops_t;
+
+/*
+ * The crypto_cipher_ops structure contains pointers to encryption
+ * and decryption operations for cryptographic providers.  It is
+ * passed through the crypto_ops(9S) structure when providers register
+ * with the kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_cipher_ops {
+    int (*encrypt_init)(crypto_ctx_t *,
+        crypto_mechanism_t *, crypto_key_t *,
+        crypto_spi_ctx_template_t, crypto_req_handle_t);
+    int (*encrypt)(crypto_ctx_t *,
+        crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*encrypt_update)(crypto_ctx_t *,
+        crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*encrypt_final)(crypto_ctx_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*encrypt_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+        crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+
+    int (*decrypt_init)(crypto_ctx_t *,
+        crypto_mechanism_t *, crypto_key_t *,
+        crypto_spi_ctx_template_t, crypto_req_handle_t);
+    int (*decrypt)(crypto_ctx_t *,
+        crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*decrypt_update)(crypto_ctx_t *,
+        crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*decrypt_final)(crypto_ctx_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*decrypt_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+        crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+} crypto_cipher_ops_t;
+
+/*
+ * The crypto_mac_ops structure contains pointers to MAC
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_mac_ops {
+    int (*mac_init)(crypto_ctx_t *,
+        crypto_mechanism_t *, crypto_key_t *,
+        crypto_spi_ctx_template_t, crypto_req_handle_t);
+    int (*mac)(crypto_ctx_t *,
+        crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*mac_update)(crypto_ctx_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*mac_final)(crypto_ctx_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*mac_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+        crypto_data_t *, crypto_spi_ctx_template_t,
+        crypto_req_handle_t);
+    int (*mac_verify_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+        crypto_data_t *, crypto_spi_ctx_template_t,
+        crypto_req_handle_t);
+} crypto_mac_ops_t;
+
+/*
+ * The crypto_sign_ops structure contains pointers to signing
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_sign_ops {
+    int (*sign_init)(crypto_ctx_t *,
+        crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t,
+        crypto_req_handle_t);
+    int (*sign)(crypto_ctx_t *,
+        crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*sign_update)(crypto_ctx_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*sign_final)(crypto_ctx_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*sign_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+        crypto_data_t *, crypto_spi_ctx_template_t,
+        crypto_req_handle_t);
+    int (*sign_recover_init)(crypto_ctx_t *, crypto_mechanism_t *,
+        crypto_key_t *, crypto_spi_ctx_template_t,
+        crypto_req_handle_t);
+    int (*sign_recover)(crypto_ctx_t *,
+        crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*sign_recover_atomic)(crypto_provider_handle_t,
+        crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
+        crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
+        crypto_req_handle_t);
+} crypto_sign_ops_t;
+
+/*
+ * The crypto_verify_ops structure contains pointers to verify
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_verify_ops {
+    int (*verify_init)(crypto_ctx_t *,
+        crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t,
+        crypto_req_handle_t);
+    int (*verify)(crypto_ctx_t *,
+        crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*verify_update)(crypto_ctx_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*verify_final)(crypto_ctx_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*verify_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+        crypto_data_t *, crypto_spi_ctx_template_t,
+        crypto_req_handle_t);
+    int (*verify_recover_init)(crypto_ctx_t *, crypto_mechanism_t *,
+        crypto_key_t *, crypto_spi_ctx_template_t,
+        crypto_req_handle_t);
+    int (*verify_recover)(crypto_ctx_t *,
+        crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*verify_recover_atomic)(crypto_provider_handle_t,
+        crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
+        crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
+        crypto_req_handle_t);
+} crypto_verify_ops_t;
+
+/*
+ * The crypto_dual_ops structure contains pointers to dual
+ * cipher and sign/verify operations for cryptographic providers.
+ * It is passed through the crypto_ops(9S) structure when
+ * providers register with the kernel using
+ * crypto_register_provider(9F).
+ */
+typedef struct crypto_dual_ops {
+    int (*digest_encrypt_update)(
+        crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*decrypt_digest_update)(
+        crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*sign_encrypt_update)(
+        crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
+        crypto_data_t *, crypto_req_handle_t);
+    int (*decrypt_verify_update)(
+        crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
+        crypto_data_t *, crypto_req_handle_t);
+} crypto_dual_ops_t;
+
+/*
+ * The crypto_dual_cipher_mac_ops structure contains pointers to dual
+ * cipher and MAC operations for cryptographic providers.
+ * It is passed through the crypto_ops(9S) structure when
+ * providers register with the kernel using
+ * crypto_register_provider(9F).
+ */
+typedef struct crypto_dual_cipher_mac_ops {
+    int (*encrypt_mac_init)(crypto_ctx_t *,
+        crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
+        crypto_key_t *, crypto_spi_ctx_template_t,
+        crypto_spi_ctx_template_t, crypto_req_handle_t);
+    int (*encrypt_mac)(crypto_ctx_t *,
+        crypto_data_t *, crypto_dual_data_t *, crypto_data_t *,
+        crypto_req_handle_t);
+    int (*encrypt_mac_update)(crypto_ctx_t *,
+        crypto_data_t *, crypto_dual_data_t *, crypto_req_handle_t);
+    int (*encrypt_mac_final)(crypto_ctx_t *,
+        crypto_dual_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*encrypt_mac_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
+        crypto_key_t *, crypto_data_t *, crypto_dual_data_t *,
+        crypto_data_t *, crypto_spi_ctx_template_t,
+        crypto_spi_ctx_template_t, crypto_req_handle_t);
+
+    int (*mac_decrypt_init)(crypto_ctx_t *,
+        crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
+        crypto_key_t *, crypto_spi_ctx_template_t,
+        crypto_spi_ctx_template_t, crypto_req_handle_t);
+    int (*mac_decrypt)(crypto_ctx_t *,
+        crypto_dual_data_t *, crypto_data_t *, crypto_data_t *,
+        crypto_req_handle_t);
+    int (*mac_decrypt_update)(crypto_ctx_t *,
+        crypto_dual_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*mac_decrypt_final)(crypto_ctx_t *,
+        crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+    int (*mac_decrypt_atomic)(crypto_provider_handle_t,
+        crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
+        crypto_mechanism_t *, crypto_key_t *, crypto_dual_data_t *,
+        crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
+        crypto_spi_ctx_template_t, crypto_req_handle_t);
+    int (*mac_verify_decrypt_atomic)(crypto_provider_handle_t,
+        crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
+        crypto_mechanism_t *, crypto_key_t *, crypto_dual_data_t *,
+        crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
+        crypto_spi_ctx_template_t, crypto_req_handle_t);
+} crypto_dual_cipher_mac_ops_t;
+
+/*
+ * The crypto_random_number_ops structure contains pointers to random
+ * number operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_random_number_ops {
+    int (*seed_random)(crypto_provider_handle_t, crypto_session_id_t,
+        uchar_t *, size_t, uint_t, uint32_t, crypto_req_handle_t);
+    int (*generate_random)(crypto_provider_handle_t, crypto_session_id_t,
+        uchar_t *, size_t, crypto_req_handle_t);
+} crypto_random_number_ops_t;
+
+/*
+ * Flag values for seed_random.
+ */
+#define    CRYPTO_SEED_NOW        0x00000001
+
+/*
+ * The crypto_session_ops structure contains pointers to session
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_session_ops {
+    int (*session_open)(crypto_provider_handle_t, crypto_session_id_t *,
+        crypto_req_handle_t);
+    int (*session_close)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_req_handle_t);
+    int (*session_login)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_user_type_t, char *, size_t, crypto_req_handle_t);
+    int (*session_logout)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_req_handle_t);
+} crypto_session_ops_t;
+
+/*
+ * The crypto_object_ops structure contains pointers to object
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_object_ops {
+    int (*object_create)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
+        crypto_req_handle_t);
+    int (*object_copy)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_object_id_t, crypto_object_attribute_t *, uint_t,
+        crypto_object_id_t *, crypto_req_handle_t);
+    int (*object_destroy)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_object_id_t, crypto_req_handle_t);
+    int (*object_get_size)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_object_id_t, size_t *, crypto_req_handle_t);
+    int (*object_get_attribute_value)(crypto_provider_handle_t,
+        crypto_session_id_t, crypto_object_id_t,
+        crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
+    int (*object_set_attribute_value)(crypto_provider_handle_t,
+        crypto_session_id_t, crypto_object_id_t,
+        crypto_object_attribute_t *,  uint_t, crypto_req_handle_t);
+    int (*object_find_init)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_object_attribute_t *, uint_t, void **,
+        crypto_req_handle_t);
+    int (*object_find)(crypto_provider_handle_t, void *,
+        crypto_object_id_t *, uint_t, uint_t *, crypto_req_handle_t);
+    int (*object_find_final)(crypto_provider_handle_t, void *,
+        crypto_req_handle_t);
+} crypto_object_ops_t;
+
+/*
+ * The crypto_key_ops structure contains pointers to key
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_key_ops {
+    int (*key_generate)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
+        crypto_object_id_t *, crypto_req_handle_t);
+    int (*key_generate_pair)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
+        crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
+        crypto_object_id_t *, crypto_req_handle_t);
+    int (*key_wrap)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, crypto_object_id_t *,
+        uchar_t *, size_t *, crypto_req_handle_t);
+    int (*key_unwrap)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, uchar_t *, size_t *,
+        crypto_object_attribute_t *, uint_t,
+        crypto_object_id_t *, crypto_req_handle_t);
+    int (*key_derive)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
+        uint_t, crypto_object_id_t *, crypto_req_handle_t);
+    int (*key_check)(crypto_provider_handle_t, crypto_mechanism_t *,
+        crypto_key_t *);
+} crypto_key_ops_t;
+
+/*
+ * The crypto_provider_management_ops structure contains pointers
+ * to management operations for cryptographic providers.  It is passed
+ * through the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_provider_management_ops {
+    int (*ext_info)(crypto_provider_handle_t,
+        crypto_provider_ext_info_t *, crypto_req_handle_t);
+    int (*init_token)(crypto_provider_handle_t, char *, size_t,
+        char *, crypto_req_handle_t);
+    int (*init_pin)(crypto_provider_handle_t, crypto_session_id_t,
+        char *, size_t, crypto_req_handle_t);
+    int (*set_pin)(crypto_provider_handle_t, crypto_session_id_t,
+        char *, size_t, char *, size_t, crypto_req_handle_t);
+} crypto_provider_management_ops_t;
+
+typedef struct crypto_mech_ops {
+    int (*copyin_mechanism)(crypto_provider_handle_t,
+        crypto_mechanism_t *, crypto_mechanism_t *, int *, int);
+    int (*copyout_mechanism)(crypto_provider_handle_t,
+        crypto_mechanism_t *, crypto_mechanism_t *, int *, int);
+    int (*free_mechanism)(crypto_provider_handle_t, crypto_mechanism_t *);
+} crypto_mech_ops_t;
+
+typedef struct crypto_nostore_key_ops {
+    int (*nostore_key_generate)(crypto_provider_handle_t,
+        crypto_session_id_t, crypto_mechanism_t *,
+        crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
+        uint_t, crypto_req_handle_t);
+    int (*nostore_key_generate_pair)(crypto_provider_handle_t,
+        crypto_session_id_t, crypto_mechanism_t *,
+        crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
+        uint_t, crypto_object_attribute_t *, uint_t,
+        crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
+    int (*nostore_key_derive)(crypto_provider_handle_t, crypto_session_id_t,
+        crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
+        uint_t, crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
+} crypto_nostore_key_ops_t;
+
+/*
+ * crypto_fips140_ops provides a function for FIPS 140 Power-On Self Test for
+ * those providers that are part of the Cryptographic Framework bounday.  See
+ * crypto_fips140_ops(9s) for details.
+ */
+typedef struct crypto_fips140_ops {
+    void (*fips140_post)(int *);
+} crypto_fips140_ops_t;
+
+/*
+ * The crypto_ops(9S) structure contains the structures containing
+ * the pointers to functions implemented by cryptographic providers.
+ * It is specified as part of the crypto_provider_info(9S)
+ * supplied by a provider when it registers with the kernel
+ * by calling crypto_register_provider(9F).
+ */
+typedef struct crypto_ops_v1 {
+    crypto_control_ops_t            *co_control_ops;
+    crypto_digest_ops_t            *co_digest_ops;
+    crypto_cipher_ops_t            *co_cipher_ops;
+    crypto_mac_ops_t            *co_mac_ops;
+    crypto_sign_ops_t            *co_sign_ops;
+    crypto_verify_ops_t            *co_verify_ops;
+    crypto_dual_ops_t            *co_dual_ops;
+    crypto_dual_cipher_mac_ops_t        *co_dual_cipher_mac_ops;
+    crypto_random_number_ops_t        *co_random_ops;
+    crypto_session_ops_t            *co_session_ops;
+    crypto_object_ops_t            *co_object_ops;
+    crypto_key_ops_t            *co_key_ops;
+    crypto_provider_management_ops_t    *co_provider_ops;
+    crypto_ctx_ops_t            *co_ctx_ops;
+} crypto_ops_v1_t;
+
+typedef struct crypto_ops_v2 {
+    crypto_ops_v1_t                v1_ops;
+    crypto_mech_ops_t            *co_mech_ops;
+} crypto_ops_v2_t;
+
+typedef struct crypto_ops_v3 {
+    crypto_ops_v2_t                v2_ops;
+    crypto_nostore_key_ops_t        *co_nostore_key_ops;
+} crypto_ops_v3_t;
+
+typedef struct crypto_ops_v4 {
+    crypto_ops_v3_t                v3_ops;
+    crypto_fips140_ops_t            *co_fips140_ops;
+} crypto_ops_v4_t;
+
+typedef struct crypto_ops_v5 {
+    crypto_ops_v4_t                v4_ops;
+    boolean_t                co_uio_userspace_ok;
+} crypto_ops_v5_t;
+
+typedef struct crypto_ops {
+    union {
+        crypto_ops_v5_t    cou_v5;
+        crypto_ops_v4_t    cou_v4;
+        crypto_ops_v3_t    cou_v3;
+        crypto_ops_v2_t    cou_v2;
+        crypto_ops_v1_t    cou_v1;
+    } cou;
+} crypto_ops_t;
+
+#define    co_control_ops            cou.cou_v1.co_control_ops
+#define    co_digest_ops            cou.cou_v1.co_digest_ops
+#define    co_cipher_ops            cou.cou_v1.co_cipher_ops
+#define    co_mac_ops            cou.cou_v1.co_mac_ops
+#define    co_sign_ops            cou.cou_v1.co_sign_ops
+#define    co_verify_ops            cou.cou_v1.co_verify_ops
+#define    co_dual_ops            cou.cou_v1.co_dual_ops
+#define    co_dual_cipher_mac_ops        cou.cou_v1.co_dual_cipher_mac_ops
+#define    co_random_ops            cou.cou_v1.co_random_ops
+#define    co_session_ops            cou.cou_v1.co_session_ops
+#define    co_object_ops            cou.cou_v1.co_object_ops
+#define    co_key_ops            cou.cou_v1.co_key_ops
+#define    co_provider_ops            cou.cou_v1.co_provider_ops
+#define    co_ctx_ops            cou.cou_v1.co_ctx_ops
+#define    co_mech_ops            cou.cou_v2.co_mech_ops
+#define    co_nostore_key_ops        cou.cou_v3.co_nostore_key_ops
+#define    co_fips140_ops            cou.cou_v4.co_fips140_ops
+#define    co_uio_userspace_ok        cou.cou_v5.co_uio_userspace_ok
+
+/*
+ * Provider device specification passed during registration.
+ *
+ * Software providers set the pi_provider_type field of provider_info_t
+ * to CRYPTO_SW_PROVIDER, and set the pd_sw field of
+ * crypto_provider_dev_t to the address of their modlinkage.
+ *
+ * Hardware providers set the pi_provider_type field of provider_info_t
+ * to CRYPTO_HW_PROVIDER, and set the pd_hw field of
+ * crypto_provider_dev_t to the dev_info structure corresponding
+ * to the device instance being registered.
+ *
+ * Logical providers set the pi_provider_type field of provider_info_t
+ * to CRYPTO_LOGICAL_PROVIDER, and set the pd_hw field of
+ * crypto_provider_dev_t to the dev_info structure corresponding
+ * to the device instance being registered.
+ */
+
+typedef union crypto_provider_dev {
+    struct modlinkage    *pd_sw; /* for CRYPTO_SW_PROVIDER */
+    dev_info_t        *pd_hw; /* for CRYPTO_HW_PROVIDER */
+} crypto_provider_dev_t;
+
+/*
+ * The mechanism info structure crypto_mech_info_t contains a function group
+ * bit mask cm_func_group_mask. This field, of type crypto_func_group_t,
+ * specifies the provider entry point that can be used a particular
+ * mechanism. The function group mask is a combination of the following values.
+ */
+
+typedef uint32_t crypto_func_group_t;
+
+#endif /* _KERNEL */
+
+#define    CRYPTO_FG_ENCRYPT        0x00000001 /* encrypt_init() */
+#define    CRYPTO_FG_DECRYPT        0x00000002 /* decrypt_init() */
+#define    CRYPTO_FG_DIGEST        0x00000004 /* digest_init() */
+#define    CRYPTO_FG_SIGN            0x00000008 /* sign_init() */
+#define    CRYPTO_FG_SIGN_RECOVER        0x00000010 /* sign_recover_init() */
+#define    CRYPTO_FG_VERIFY        0x00000020 /* verify_init() */
+#define    CRYPTO_FG_VERIFY_RECOVER    0x00000040 /* verify_recover_init() */
+#define    CRYPTO_FG_GENERATE        0x00000080 /* key_generate() */
+#define    CRYPTO_FG_GENERATE_KEY_PAIR    0x00000100 /* key_generate_pair() */
+#define    CRYPTO_FG_WRAP            0x00000200 /* key_wrap() */
+#define    CRYPTO_FG_UNWRAP        0x00000400 /* key_unwrap() */
+#define    CRYPTO_FG_DERIVE        0x00000800 /* key_derive() */
+#define    CRYPTO_FG_MAC            0x00001000 /* mac_init() */
+#define    CRYPTO_FG_ENCRYPT_MAC        0x00002000 /* encrypt_mac_init() */
+#define    CRYPTO_FG_MAC_DECRYPT        0x00004000 /* decrypt_mac_init() */
+#define    CRYPTO_FG_ENCRYPT_ATOMIC    0x00008000 /* encrypt_atomic() */
+#define    CRYPTO_FG_DECRYPT_ATOMIC    0x00010000 /* decrypt_atomic() */
+#define    CRYPTO_FG_MAC_ATOMIC        0x00020000 /* mac_atomic() */
+#define    CRYPTO_FG_DIGEST_ATOMIC        0x00040000 /* digest_atomic() */
+#define    CRYPTO_FG_SIGN_ATOMIC        0x00080000 /* sign_atomic() */
+#define    CRYPTO_FG_SIGN_RECOVER_ATOMIC   0x00100000 /* sign_recover_atomic() */
+#define    CRYPTO_FG_VERIFY_ATOMIC        0x00200000 /* verify_atomic() */
+#define    CRYPTO_FG_VERIFY_RECOVER_ATOMIC    0x00400000 /* verify_recover_atomic() */
+#define    CRYPTO_FG_ENCRYPT_MAC_ATOMIC    0x00800000 /* encrypt_mac_atomic() */
+#define    CRYPTO_FG_MAC_DECRYPT_ATOMIC    0x01000000 /* mac_decrypt_atomic() */
+#define    CRYPTO_FG_RESERVED        0x80000000
+
+/*
+ * Maximum length of the pi_provider_description field of the
+ * crypto_provider_info structure.
+ */
+#define    CRYPTO_PROVIDER_DESCR_MAX_LEN    64
+
+#ifdef _KERNEL
+
+/* Bit mask for all the simple operations */
+#define    CRYPTO_FG_SIMPLEOP_MASK    (CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | \
+    CRYPTO_FG_DIGEST | CRYPTO_FG_SIGN | CRYPTO_FG_VERIFY | CRYPTO_FG_MAC | \
+    CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC |        \
+    CRYPTO_FG_MAC_ATOMIC | CRYPTO_FG_DIGEST_ATOMIC | CRYPTO_FG_SIGN_ATOMIC | \
+    CRYPTO_FG_VERIFY_ATOMIC)
+
+/* Bit mask for all the dual operations */
+#define    CRYPTO_FG_MAC_CIPHER_MASK    (CRYPTO_FG_ENCRYPT_MAC |    \
+    CRYPTO_FG_MAC_DECRYPT | CRYPTO_FG_ENCRYPT_MAC_ATOMIC |         \
+    CRYPTO_FG_MAC_DECRYPT_ATOMIC)
+
+/* Add other combos to CRYPTO_FG_DUAL_MASK */
+#define    CRYPTO_FG_DUAL_MASK    CRYPTO_FG_MAC_CIPHER_MASK
+
+/*
+ * The crypto_mech_info structure specifies one of the mechanisms
+ * supported by a cryptographic provider. The pi_mechanisms field of
+ * the crypto_provider_info structure contains a pointer to an array
+ * of crypto_mech_info's.
+ */
+typedef struct crypto_mech_info {
+    crypto_mech_name_t    cm_mech_name;
+    crypto_mech_type_t    cm_mech_number;
+    crypto_func_group_t    cm_func_group_mask;
+    ssize_t            cm_min_key_length;
+    ssize_t            cm_max_key_length;
+    uint32_t        cm_mech_flags;
+} crypto_mech_info_t;
+
+/* Alias the old name to the new name for compatibility. */
+#define    cm_keysize_unit    cm_mech_flags
+
+/*
+ * crypto_kcf_provider_handle_t is a handle allocated by the kernel.
+ * It is returned after the provider registers with
+ * crypto_register_provider(), and must be specified by the provider
+ * when calling crypto_unregister_provider(), and
+ * crypto_provider_notification().
+ */
+typedef uint_t crypto_kcf_provider_handle_t;
+
+/*
+ * Provider information. Passed as argument to crypto_register_provider(9F).
+ * Describes the provider and its capabilities. Multiple providers can
+ * register for the same device instance. In this case, the same
+ * pi_provider_dev must be specified with a different pi_provider_handle.
+ */
+typedef struct crypto_provider_info_v1 {
+    uint_t                pi_interface_version;
+    char                *pi_provider_description;
+    crypto_provider_type_t        pi_provider_type;
+    crypto_provider_dev_t        pi_provider_dev;
+    crypto_provider_handle_t    pi_provider_handle;
+    crypto_ops_t            *pi_ops_vector;
+    uint_t                pi_mech_list_count;
+    crypto_mech_info_t        *pi_mechanisms;
+    uint_t                pi_logical_provider_count;
+    crypto_kcf_provider_handle_t    *pi_logical_providers;
+} crypto_provider_info_v1_t;
+
+typedef struct crypto_provider_info_v2 {
+    crypto_provider_info_v1_t    v1_info;
+    uint_t                pi_flags;
+} crypto_provider_info_v2_t;
+
+typedef struct crypto_provider_info {
+    union {
+        crypto_provider_info_v2_t piu_v2;
+        crypto_provider_info_v1_t piu_v1;
+    } piu;
+} crypto_provider_info_t;
+
+#define    pi_interface_version        piu.piu_v1.pi_interface_version
+#define    pi_provider_description        piu.piu_v1.pi_provider_description
+#define    pi_provider_type        piu.piu_v1.pi_provider_type
+#define    pi_provider_dev            piu.piu_v1.pi_provider_dev
+#define    pi_provider_handle        piu.piu_v1.pi_provider_handle
+#define    pi_ops_vector            piu.piu_v1.pi_ops_vector
+#define    pi_mech_list_count        piu.piu_v1.pi_mech_list_count
+#define    pi_mechanisms            piu.piu_v1.pi_mechanisms
+#define    pi_logical_provider_count    piu.piu_v1.pi_logical_provider_count
+#define    pi_logical_providers        piu.piu_v1.pi_logical_providers
+#define    pi_flags            piu.piu_v2.pi_flags
+
+/* hidden providers can only be accessed via a logical provider */
+#define    CRYPTO_HIDE_PROVIDER        0x00000001
+/*
+ * provider can not do multi-part digest (updates) and has a limit
+ * on maximum input data that it can digest. The provider sets
+ * this value in crypto_provider_ext_info_t by implementing
+ * the ext_info entry point in the co_provider_ops vector.
+ */
+#define    CRYPTO_HASH_NO_UPDATE        0x00000002
+/*
+ * provider can not do multi-part HMAC (updates) and has a limit
+ * on maximum input data that it can hmac. The provider sets
+ * this value in crypto_provider_ext_info_t by implementing
+ * the ext_info entry point in the co_provider_ops vector.
+ */
+#define    CRYPTO_HMAC_NO_UPDATE        0x00000008
+
+/* provider can handle the request without returning a CRYPTO_QUEUED */
+#define    CRYPTO_SYNCHRONOUS        0x00000004
+
+#define    CRYPTO_PIFLAGS_RESERVED2    0x40000000
+#define    CRYPTO_PIFLAGS_RESERVED1    0x80000000
+
+/*
+ * Provider status passed by a provider to crypto_provider_notification(9F)
+ * and returned by the provider_stauts(9E) entry point.
+ */
+#define    CRYPTO_PROVIDER_READY        0
+#define    CRYPTO_PROVIDER_BUSY        1
+#define    CRYPTO_PROVIDER_FAILED        2
+
+/*
+ * Functions exported by Solaris to cryptographic providers. Providers
+ * call these functions to register and unregister, notify the kernel
+ * of state changes, and notify the kernel when a asynchronous request
+ * completed.
+ */
+extern int crypto_register_provider(crypto_provider_info_t *,
+        crypto_kcf_provider_handle_t *);
+extern int crypto_unregister_provider(crypto_kcf_provider_handle_t);
+extern void crypto_provider_notification(crypto_kcf_provider_handle_t, uint_t);
+extern void crypto_op_notification(crypto_req_handle_t, int);
+extern int crypto_kmflag(crypto_req_handle_t);
+
+#endif    /* _KERNEL */
+
+#ifdef    __cplusplus
+}
+#endif
+
+#endif    /* _SYS_CRYPTO_SPI_H */
--- a/test/TEST.groups	Mon Oct 20 12:54:36 2014 -0400
+++ b/test/TEST.groups	Mon Oct 20 21:18:48 2014 +0000
@@ -120,6 +120,7 @@
 jdk_security2 = \
     javax/crypto \
     javax/xml/crypto \
+    com/oracle/security/ucrypto \
     com/sun/crypto
 
 jdk_security3 = \
@@ -390,6 +391,10 @@
   :jdk_desktop \
   com/sun/corba \
   com/sun/jndi/cosnaming \
+  com/oracle/security/ucrypto/Test8004873.java \
+  com/oracle/security/ucrypto/TestAES.java \
+  com/oracle/security/ucrypto/TestDigest.java \
+  com/oracle/security/ucrypto/TestRSA.java \
   sun/net/ftp \
   sun/net/www/protocol/ftp \
   sun/security/tools/policytool \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/CipherSignNotSupported.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8029849
+ * @summary Make sure signing via encrypt and verifying via decrypt are not
+ * supported by OracleUcrypto provider.
+ * @author Anthony Scarpino
+ */
+
+import java.util.Random;
+import java.security.KeyPairGenerator;
+import java.security.KeyPair;
+import javax.crypto.Cipher;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+public class CipherSignNotSupported extends UcryptoTest {
+
+    public static void main(String[] args) throws Exception {
+        main(new CipherSignNotSupported(), null);
+    }
+
+    public void doTest(Provider p) throws Exception {
+        Cipher c = null;
+        Random random = new Random();
+        byte[] pt = new byte[117];
+        byte[] ct = new byte[200];
+        random.nextBytes(pt);
+
+        try {
+            c = Cipher.getInstance("RSA/ECB/PKCS1Padding", p);
+        } catch (NoSuchAlgorithmException e) {
+            if (System.getProperty("os.version").compareTo("5.10") == 0) {
+                System.out.println("RSA not supported in S10");
+                return;
+            }
+            throw e;
+        }
+
+        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+        kpg.initialize(1024);
+        KeyPair kp = kpg.generateKeyPair();
+
+        // Encryption
+        c.init(Cipher.ENCRYPT_MODE, kp.getPublic());
+        ct = c.doFinal(pt);
+        // Decryption
+        c.init(Cipher.DECRYPT_MODE, kp.getPrivate());
+        c.doFinal(ct);
+        // Sign
+        try {
+            c.init(Cipher.ENCRYPT_MODE, kp.getPrivate());
+            ct = c.doFinal(pt);
+            throw new RuntimeException("Encrypt operation should have failed.");
+        } catch (InvalidKeyException e) {
+            if (e.getMessage().compareTo("RSAPublicKey required for " +
+                    "encryption") != 0) {
+                System.out.println("Wrong exception thrown.");
+                throw e;
+            }
+        }
+        // Verify
+        try {
+            c.init(Cipher.DECRYPT_MODE, kp.getPublic());
+            c.doFinal(ct);
+            throw new RuntimeException("Decrypt operation should have failed.");
+        } catch (InvalidKeyException e) {
+            if (e.getMessage().compareTo("RSAPrivateCrtKey required for " +
+                    "decryption") != 0) {
+                System.out.println("Wrong exception thrown.");
+                throw e;
+            }
+        }
+
+        System.out.println("Pass");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/Test8004873.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug     8004873
+ * @summary Need to include data buffered by Padding impl when calculating
+ * output buffer sizes.
+ */
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import java.util.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class Test8004873 extends UcryptoTest {
+
+    private static final String[] PADDEDCIPHER_ALGOS = {
+        "AES/ECB/PKCS5Padding",
+        "AES/CBC/PKCS5Padding",
+        "AES/CFB128/PKCS5Padding"
+    };
+
+    private static final SecretKey AES_KEY;
+
+    static {
+        byte[] keyValue = {
+            62, 124, -2, -15, 86, -25, 18, -112, 110, 31, 96, 59,
+            89, 70, 60, 103};
+        AES_KEY = new SecretKeySpec(keyValue, "AES");
+    }
+
+    public static void main(String[] args) throws Exception {
+        main(new Test8004873(), null);
+    }
+
+    public void doTest(Provider prov) throws Exception {
+        boolean result = true;
+        for (String algo : PADDEDCIPHER_ALGOS) {
+            if (!testOOS(algo, prov)) {
+                result = false;
+                System.out.println(algo + " Test Failed!");
+            }
+        }
+        if (!result) {
+            throw new Exception("One or more test failed!");
+        }
+    }
+
+    private boolean testOOS(String algo, Provider prov)
+        throws Exception {
+
+        String password = "abcd1234";
+        Cipher c;
+        try {
+            c = Cipher.getInstance(algo, prov);
+        } catch(NoSuchAlgorithmException nsae) {
+            System.out.println("Skipping Unsupported algo: " + algo);
+            return true;
+        }
+        c.init(Cipher.ENCRYPT_MODE, AES_KEY);
+        AlgorithmParameters params = c.getParameters();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        CipherOutputStream cos = new CipherOutputStream(baos, c);
+        ObjectOutputStream oos = new ObjectOutputStream(cos);
+        oos.writeObject(password);
+        oos.flush();
+        oos.close();
+        byte[] encrypted = baos.toByteArray();
+
+        c.init(Cipher.DECRYPT_MODE, AES_KEY, params);
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(encrypted);
+        CipherInputStream cis = new CipherInputStream(bais, c);
+        ObjectInputStream ois = new ObjectInputStream(cis);
+
+        String recovered = (String) ois.readObject();
+        return recovered.equals(password);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/TestAES.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,343 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7088989 8014374
+ * @summary Ensure the AES ciphers of OracleUcrypto provider works correctly
+ */
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import java.util.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class TestAES extends UcryptoTest {
+
+    private static final String[] PADDEDCIPHER_ALGOS = {
+        "AES/ECB/PKCS5Padding",
+        "AES/CBC/PKCS5Padding",
+        "AES/CFB128/PKCS5Padding"
+    };
+
+    private static final String[] CIPHER_ALGOS = {
+        "AES/ECB/NoPadding",
+        "AES/CBC/NoPadding",
+        "AES/CFB128/NoPadding",
+        "AES/CTR/NoPadding",
+    };
+
+    private static final SecretKey CIPHER_KEY =
+        new SecretKeySpec(new byte[16], "AES");
+
+    public static void main(String[] args) throws Exception {
+        main(new TestAES(), null);
+    }
+
+    public void doTest(Provider prov) throws Exception {
+        // Provider for testing Interoperability
+        Provider sunJCEProv = Security.getProvider("SunJCE");
+
+        testCipherInterop(CIPHER_ALGOS, CIPHER_KEY, prov, sunJCEProv);
+        testCipherInterop(PADDEDCIPHER_ALGOS, CIPHER_KEY, prov, sunJCEProv);
+
+        testCipherOffset(CIPHER_ALGOS, CIPHER_KEY, prov);
+        testCipherOffset(PADDEDCIPHER_ALGOS, CIPHER_KEY, prov);
+
+        testCipherKeyWrapping(PADDEDCIPHER_ALGOS, CIPHER_KEY, prov, sunJCEProv);
+        testCipherGCM(CIPHER_KEY, prov);
+    }
+
+    private static void testCipherInterop(String[] algos, SecretKey key,
+                                          Provider p,
+                                          Provider interopP) {
+        boolean testPassed = true;
+        byte[] in = new byte[32];
+        (new SecureRandom()).nextBytes(in);
+
+        for (String algo : algos) {
+            try {
+                // check ENC
+                Cipher c;
+                try {
+                    c = Cipher.getInstance(algo, p);
+                } catch (NoSuchAlgorithmException nsae) {
+                    System.out.println("Skipping Unsupported CIP algo: " + algo);
+                    continue;
+                }
+                c.init(Cipher.ENCRYPT_MODE, key, (AlgorithmParameters)null, null);
+                byte[] eout = c.doFinal(in, 0, in.length);
+
+                AlgorithmParameters params = c.getParameters();
+                Cipher c2 = Cipher.getInstance(algo, interopP);
+                c2.init(Cipher.ENCRYPT_MODE, key, params, null);
+                byte[] eout2 = c2.doFinal(in, 0, in.length);
+
+                if (!Arrays.equals(eout, eout2)) {
+                    System.out.println(algo + ": DIFF FAILED");
+                    testPassed = false;
+                } else {
+                    System.out.println(algo + ": ENC Passed");
+                }
+
+                // check DEC
+                c.init(Cipher.DECRYPT_MODE, key, params, null);
+                byte[] dout = c.doFinal(eout);
+                c2.init(Cipher.DECRYPT_MODE, key, params, null);
+                byte[] dout2 = c2.doFinal(eout2);
+
+                if (!Arrays.equals(dout, dout2)) {
+                    System.out.println(algo + ": DIFF FAILED");
+                    testPassed = false;
+                } else {
+                    System.out.println(algo + ": DEC Passed");
+                }
+            } catch(Exception ex) {
+                System.out.println("Unexpected Exception: " + algo);
+                ex.printStackTrace();
+                testPassed = false;
+            }
+        }
+
+        if (!testPassed) {
+            throw new RuntimeException("One or more CIPHER test failed!");
+        } else {
+            System.out.println("CIPHER Interop Tests Passed");
+        }
+    }
+
+    private static void testCipherOffset(String[] algos, SecretKey key,
+                                         Provider p) {
+        boolean testPassed = true;
+        byte[] in = new byte[16];
+        (new SecureRandom()).nextBytes(in);
+        int blockSize = 16;
+
+        for (int j = 1; j < (in.length - 1); j++) {
+            System.out.println("Input offset size: " + j);
+            for (int i = 0; i < algos.length; i++) {
+                try {
+                    // check ENC
+                    Cipher c;
+                    try {
+                        c = Cipher.getInstance(algos[i], p);
+                    } catch (NoSuchAlgorithmException nsae) {
+                        System.out.println("Skip Unsupported CIP algo: " + algos[i]);
+                        continue;
+                    }
+                    c.init(Cipher.ENCRYPT_MODE, key, (AlgorithmParameters)null, null);
+                    byte[] eout = new byte[c.getOutputSize(in.length)];
+                    int firstPartLen = in.length - j - 1;
+                    //System.out.print("1st UPDATE: " + firstPartLen);
+                    int k = c.update(in, 0, firstPartLen, eout, 0);
+                    k += c.update(in, firstPartLen, 1, eout, k);
+                    k += c.doFinal(in, firstPartLen+1, j, eout, k);
+
+                    AlgorithmParameters params = c.getParameters();
+
+                    Cipher c2 = Cipher.getInstance(algos[i], p);
+                    c2.init(Cipher.ENCRYPT_MODE, key, params, null);
+                    byte[] eout2 = new byte[c2.getOutputSize(in.length)];
+                    int k2 = c2.update(in, 0, j, eout2, 0);
+                    k2 += c2.update(in, j, 1, eout2, k2);
+                    k2 += c2.doFinal(in, j+1, firstPartLen, eout2, k2);
+
+                    if (!checkArrays(eout, k, eout2, k2)) testPassed = false;
+
+                    // check DEC
+                    c.init(Cipher.DECRYPT_MODE, key, params, null);
+                    byte[] dout = new byte[c.getOutputSize(eout.length)];
+                    k = c.update(eout, 0, firstPartLen, dout, 0);
+                    k += c.update(eout, firstPartLen, 1, dout, k);
+                    k += c.doFinal(eout, firstPartLen+1, eout.length - firstPartLen - 1, dout, k);
+                    if (!checkArrays(in, in.length, dout, k)) testPassed = false;
+                } catch(Exception ex) {
+                    System.out.println("Unexpected Exception: " + algos[i]);
+                    ex.printStackTrace();
+                    testPassed = false;
+                }
+            }
+        }
+        if (!testPassed) {
+            throw new RuntimeException("One or more CIPHER test failed!");
+        } else {
+            System.out.println("CIPHER Offset Tests Passed");
+        }
+    }
+
+    private static void testCipherKeyWrapping(String[] algos, SecretKey key,
+                                              Provider p, Provider interopP)
+        throws NoSuchAlgorithmException {
+        boolean testPassed = true;
+
+        // Test SecretKey, PrivateKey and PublicKey
+        Key[] tbwKeys = new Key[3];
+        int[] tbwKeyTypes = { Cipher.SECRET_KEY, Cipher.PRIVATE_KEY, Cipher.PUBLIC_KEY };
+        tbwKeys[0] = new SecretKeySpec(new byte[20], "Blowfish");
+        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+        kpg.initialize(1024);
+        KeyPair kp = kpg.generateKeyPair();
+        tbwKeys[1] = kp.getPrivate();
+        tbwKeys[2] = kp.getPublic();
+
+        for (int i = 0; i < algos.length; i++) {
+            try {
+                System.out.println(algos[i] + " - Native WRAP/Java UNWRAP");
+
+                Cipher c1;
+                try {
+                    c1 = Cipher.getInstance(algos[i], p);
+                } catch (NoSuchAlgorithmException nsae) {
+                    System.out.println("Skipping Unsupported CIP algo: " + algos[i]);
+                    continue;
+                }
+                c1.init(Cipher.WRAP_MODE, key, (AlgorithmParameters)null, null);
+                AlgorithmParameters params = c1.getParameters();
+                Cipher c2 = Cipher.getInstance(algos[i], interopP);
+                c2.init(Cipher.UNWRAP_MODE, key, params, null);
+
+                for (int j = 0; j < tbwKeys.length ; j++) {
+                    byte[] wrappedKey = c1.wrap(tbwKeys[j]);
+                    Key recovered = c2.unwrap(wrappedKey,
+                                              tbwKeys[j].getAlgorithm(), tbwKeyTypes[j]);
+                    if (!checkKeys(tbwKeys[j], recovered)) testPassed = false;
+                }
+
+                System.out.println(algos[i] + " - Java WRAP/Native UNWRAP");
+                c1 = Cipher.getInstance(algos[i], interopP);
+                c1.init(Cipher.WRAP_MODE, key, (AlgorithmParameters)null, null);
+                params = c1.getParameters();
+                c2 = Cipher.getInstance(algos[i], p);
+                c2.init(Cipher.UNWRAP_MODE, key, params, null);
+
+                for (int j = 0; j < tbwKeys.length ; j++) {
+                    byte[] wrappedKey = c1.wrap(tbwKeys[j]);
+                    Key recovered = c2.unwrap(wrappedKey,
+                                              tbwKeys[j].getAlgorithm(), tbwKeyTypes[j]);
+                    if (!checkKeys(tbwKeys[j], recovered)) testPassed = false;
+                }
+
+            } catch(Exception ex) {
+                System.out.println("Unexpected Exception: " + algos[i]);
+                ex.printStackTrace();
+                testPassed = false;
+            }
+        }
+        if (!testPassed) {
+            throw new RuntimeException("One or more CIPHER test failed!");
+        } else {
+            System.out.println("CIPHER KeyWrapping Tests Passed");
+        }
+    }
+
+
+    private static void testCipherGCM(SecretKey key,
+                                      Provider p) {
+        boolean testPassed = true;
+        byte[] in = new byte[16];
+        (new SecureRandom()).nextBytes(in);
+
+        byte[] iv = new byte[16];
+        (new SecureRandom()).nextBytes(iv);
+
+
+        String algo = "AES/GCM/NoPadding";
+        int tagLen[] = { 128, 120, 112, 104, 96, 64, 32 };
+
+        try {
+            Cipher c;
+            try {
+                c = Cipher.getInstance(algo, p);
+            } catch (NoSuchAlgorithmException nsae) {
+                System.out.println("Skipping Unsupported CIP algo: " + algo);
+                return;
+            }
+            for (int i = 0; i < tagLen.length; i++) {
+                // change iv value to pass the key+iv uniqueness cehck for
+                // GCM encryption
+                iv[0] += 1;
+                AlgorithmParameterSpec paramSpec = new GCMParameterSpec(tagLen[i], iv);
+                // check ENC
+                c.init(Cipher.ENCRYPT_MODE, key, paramSpec, null);
+                c.updateAAD(iv);
+                byte[] eout = c.doFinal(in, 0, in.length);
+
+                AlgorithmParameters param = c.getParameters();
+                // check DEC
+                c.init(Cipher.DECRYPT_MODE, key, param, null);
+                c.updateAAD(iv);
+                byte[] dout = c.doFinal(eout, 0, eout.length);
+
+                if (!Arrays.equals(dout, in)) {
+                    System.out.println(algo + ": PT and RT DIFF FAILED");
+                    testPassed = false;
+                } else {
+                    System.out.println(algo + ": tagLen " + tagLen[i] + " done");
+                }
+            }
+        } catch(Exception ex) {
+            System.out.println("Unexpected Exception: " + algo);
+            ex.printStackTrace();
+            testPassed = false;
+        }
+        if (!testPassed) {
+            throw new RuntimeException("One or more CIPHER test failed!");
+        } else {
+            System.out.println("CIPHER GCM Tests Passed");
+        }
+    }
+
+    private static boolean checkArrays(byte[] a1, int a1Len, byte[] a2, int a2Len) {
+        boolean equal = true;
+        if (a1Len != a2Len) {
+            System.out.println("DIFFERENT OUT LENGTH");
+            equal = false;
+        } else {
+            for (int p = 0; p < a1Len; p++) {
+                if (a1[p] != a2[p]) {
+                    System.out.println("DIFF FAILED");
+                    equal = false;
+                    break;
+                }
+            }
+        }
+        return equal;
+    }
+
+    private static boolean checkKeys(Key k1, Key k2) {
+        boolean equal = true;
+        if (!k1.getAlgorithm().equalsIgnoreCase(k2.getAlgorithm())) {
+            System.out.println("DIFFERENT Key Algorithm");
+            equal = false;
+        } else if (!k1.getFormat().equalsIgnoreCase(k2.getFormat())) {
+            System.out.println("DIFFERENT Key Format");
+            equal = false;
+        } else if (!Arrays.equals(k1.getEncoded(), k2.getEncoded())) {
+            System.out.println("DIFFERENT Key Encoding");
+            equal = false;
+        }
+        return equal;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/TestCICOWithGCM.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8014374
+ * @summary Test basic CipherInputStream/OutputStream func w/ GCM mode.
+ * @author Valerie Peng
+ */
+
+import java.security.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+import java.math.*;
+import java.io.*;
+import com.sun.crypto.provider.*;
+
+import java.util.*;
+
+public class TestCICOWithGCM extends UcryptoTest {
+    public static void main(String[] args) throws Exception {
+        main(new TestCICOWithGCM(), null);
+    }
+
+    public void doTest(Provider p) throws Exception {
+        // check if GCM support exists
+        try {
+            Cipher.getInstance("AES/GCM/NoPadding", p);
+        } catch (NoSuchAlgorithmException nsae) {
+            System.out.println("Skipping Test due to no GCM support");
+            return;
+        }
+
+        Random rdm = new Random();
+
+        //init Secret Key
+        byte[] keyValue = new byte[16];
+        rdm.nextBytes(keyValue);
+        SecretKey key = new SecretKeySpec(keyValue, "AES");
+
+        //do initialization of the plainText
+        byte[] plainText = new byte[800];
+        rdm.nextBytes(plainText);
+
+        //init ciphers
+        Cipher encCipher = Cipher.getInstance("AES/GCM/NoPadding", p);
+        encCipher.init(Cipher.ENCRYPT_MODE, key);
+        Cipher decCipher = Cipher.getInstance("AES/GCM/NoPadding", p);
+        decCipher.init(Cipher.DECRYPT_MODE, key, encCipher.getParameters());
+
+        //init cipher streams
+        ByteArrayInputStream baInput = new ByteArrayInputStream(plainText);
+        CipherInputStream ciInput = new CipherInputStream(baInput, encCipher);
+        ByteArrayOutputStream baOutput = new ByteArrayOutputStream();
+        CipherOutputStream ciOutput = new CipherOutputStream(baOutput, decCipher);
+
+        //do test
+        byte[] buffer = new byte[800];
+        int len = ciInput.read(buffer);
+        System.out.println("read " + len + " bytes from input buffer");
+
+        while (len != -1) {
+            ciOutput.write(buffer, 0, len);
+            System.out.println("wite " + len + " bytes to output buffer");
+            len = ciInput.read(buffer);
+            if (len != -1) {
+                System.out.println("read " + len + " bytes from input buffer");
+            } else {
+                System.out.println("finished reading");
+            }
+        }
+
+        ciOutput.flush();
+        ciInput.close();
+        ciOutput.close();
+        byte[] recovered = baOutput.toByteArray();
+        System.out.println("recovered " + recovered.length + " bytes");
+        if (!Arrays.equals(plainText, recovered)) {
+            throw new RuntimeException("diff check failed!");
+        } else {
+            System.out.println("diff check passed");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/TestCICOWithGCMAndAAD.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8014374
+ * @summary Test CipherInputStream/OutputStream func w/ GCM mode and AAD.
+ * @author Valerie Peng
+ */
+
+import java.io.*;
+import java.security.*;
+import java.util.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class TestCICOWithGCMAndAAD extends UcryptoTest {
+    public static void main(String[] args) throws Exception {
+        main(new TestCICOWithGCMAndAAD(), null);
+    }
+
+    public void doTest(Provider p) throws Exception {
+        // check if GCM support exists
+        try {
+            Cipher.getInstance("AES/GCM/NoPadding", p);
+        } catch (NoSuchAlgorithmException nsae) {
+            System.out.println("Skipping Test due to no GCM support");
+            return;
+        }
+
+        Random rdm = new Random();
+
+        //init Secret Key
+        byte[] keyValue = new byte[16];
+        rdm.nextBytes(keyValue);
+        SecretKey key = new SecretKeySpec(keyValue, "AES");
+
+        //Do initialization of the plainText
+        byte[] plainText = new byte[400];
+        rdm.nextBytes(plainText);
+
+        byte[] aad = new byte[128];
+        rdm.nextBytes(aad);
+        byte[] aad2 = aad.clone();
+        aad2[50]++;
+
+        GCMParameterSpec spec = new GCMParameterSpec(128, new byte[16]);
+        Cipher encCipher = Cipher.getInstance("AES/GCM/NoPadding", p);
+        encCipher.init(Cipher.ENCRYPT_MODE, key, spec);
+        encCipher.updateAAD(aad);
+        Cipher decCipher = Cipher.getInstance("AES/GCM/NoPadding", p);
+        decCipher.init(Cipher.DECRYPT_MODE, key, spec);  //encCipher.getParameters());
+        decCipher.updateAAD(aad);
+
+        byte[] recovered = test(encCipher, decCipher, plainText);
+        if (!Arrays.equals(plainText, recovered)) {
+            throw new Exception("sameAAD: diff check failed!");
+        } else System.out.println("sameAAD: passed");
+
+        encCipher.init(Cipher.ENCRYPT_MODE, key);
+        encCipher.updateAAD(aad2);
+        recovered = test(encCipher, decCipher, plainText);
+        if (recovered != null && recovered.length != 0) {
+            throw new Exception("diffAAD: no data should be returned!");
+        } else System.out.println("diffAAD: passed");
+   }
+
+   private static byte[] test(Cipher encCipher, Cipher decCipher, byte[] plainText)
+            throws Exception {
+        //init cipher streams
+        ByteArrayInputStream baInput = new ByteArrayInputStream(plainText);
+        CipherInputStream ciInput = new CipherInputStream(baInput, encCipher);
+        ByteArrayOutputStream baOutput = new ByteArrayOutputStream();
+        CipherOutputStream ciOutput = new CipherOutputStream(baOutput, decCipher);
+
+        //do test
+        byte[] buffer = new byte[200];
+        int len = ciInput.read(buffer);
+        System.out.println("read " + len + " bytes from input buffer");
+
+        while (len != -1) {
+            ciOutput.write(buffer, 0, len);
+            System.out.println("wite " + len + " bytes to output buffer");
+            len = ciInput.read(buffer);
+            if (len != -1) {
+                System.out.println("read " + len + " bytes from input buffer");
+            } else {
+                System.out.println("finished reading");
+            }
+        }
+
+        ciOutput.flush();
+        ciInput.close();
+        ciOutput.close();
+
+        return baOutput.toByteArray();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/TestDigest.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug     7088989
+ * @summary Ensure the various message digests works correctly
+ */
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import java.util.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class TestDigest extends UcryptoTest {
+
+    private static final String[] MD_ALGOS = {
+        "MD5",
+        "SHA",
+        "SHA-256",
+        "SHA-384",
+        "SHA-512"
+    };
+
+    public static void main(String[] args) throws Exception {
+        main(new TestDigest(), null);
+    }
+
+    public void doTest(Provider p) {
+        boolean testPassed = true;
+        byte[] msg = new byte[200];
+        (new SecureRandom()).nextBytes(msg);
+        String interopProvName = "SUN";
+
+        for (String a : MD_ALGOS) {
+            try {
+                MessageDigest md, md2;
+                try {
+                    md = MessageDigest.getInstance(a, p);
+                } catch (NoSuchAlgorithmException nsae) {
+                    System.out.println("Skipping Unsupported MD algo: " + a);
+                    continue;
+                }
+                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;
+                    }
+                }
+
+                // Test Interoperability for digest calls
+                md = MessageDigest.getInstance(a, p);
+                md2 = MessageDigest.getInstance(a, interopProvName);
+
+                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 Cloning functionality
+                md = MessageDigest.getInstance(a, p);
+                md2 = (MessageDigest) md.clone(); // clone right after construction
+                byte[] digest = md.digest();
+                byte[] digest2 = md2.digest();
+                if (!Arrays.equals(digest, digest2)) {
+                    System.out.println("DIFF-3.1 FAILED for: " + a);
+                    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;
+                }
+                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();
+                testPassed = false;
+            }
+        }
+        if (!testPassed) {
+            throw new RuntimeException("One or more MD test failed!");
+        } else {
+            System.out.println("MD Tests Passed");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/TestGCMKeyAndIvCheck.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8014374
+ * @summary Ensure that same key+iv can't be repeatedly used for encryption.
+ * @author Valerie Peng
+ */
+
+import java.security.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+import java.math.*;
+import com.sun.crypto.provider.*;
+
+import java.util.*;
+
+public class TestGCMKeyAndIvCheck extends UcryptoTest {
+
+    private static final byte[] AAD = new byte[5];
+    private static final byte[] PT = new byte[33];
+
+    private static void checkISE(Cipher c) throws Exception {
+        // Subsequent encryptions should fail
+        try {
+            c.updateAAD(AAD);
+            throw new Exception("Should throw ISE for updateAAD()");
+        } catch (IllegalStateException ise) {
+            // expected
+        }
+
+        try {
+            c.update(PT);
+            throw new Exception("Should throw ISE for update()");
+        } catch (IllegalStateException ise) {
+            // expected
+        }
+        try {
+            c.doFinal(PT);
+            throw new Exception("Should throw ISE for doFinal()");
+        } catch (IllegalStateException ise) {
+            // expected
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        main(new TestGCMKeyAndIvCheck(), null);
+    }
+
+    public void doTest(Provider p) throws Exception {
+        Cipher c;
+        try {
+            c = Cipher.getInstance("AES/GCM/NoPadding", p);
+        } catch (NoSuchAlgorithmException nsae) {
+            System.out.println("Skipping Test due to No GCM support");
+            return;
+        }
+
+        SecretKey key = new SecretKeySpec(new byte[16], "AES");
+        // First try parameter-less init.
+        c.init(Cipher.ENCRYPT_MODE, key);
+        c.updateAAD(AAD);
+        byte[] ctPlusTag = c.doFinal(PT);
+
+        // subsequent encryption should fail unless re-init w/ different key+iv
+        checkISE(c);
+
+        // Validate the retrieved parameters against the IV and tag length.
+        AlgorithmParameters params = c.getParameters();
+        if (params == null) {
+            throw new Exception("getParameters() should not return null");
+        }
+        GCMParameterSpec spec = params.getParameterSpec(GCMParameterSpec.class);
+        if (spec.getTLen() != (ctPlusTag.length - PT.length)*8) {
+            throw new Exception("Parameters contains incorrect TLen value");
+        }
+        if (!Arrays.equals(spec.getIV(), c.getIV())) {
+            throw new Exception("Parameters contains incorrect IV value");
+        }
+
+        // Should be ok to use the same key+iv for decryption
+        c.init(Cipher.DECRYPT_MODE, key, params);
+        c.updateAAD(AAD);
+        byte[] recovered = c.doFinal(ctPlusTag);
+        if (!Arrays.equals(recovered, PT)) {
+            throw new Exception("decryption result mismatch");
+        }
+
+        // Now try to encrypt again using the same key+iv; should fail also
+        try {
+            c.init(Cipher.ENCRYPT_MODE, key, params);
+            throw new Exception("Should throw exception when same key+iv is used");
+        } catch (InvalidAlgorithmParameterException iape) {
+            // expected
+        }
+
+        // Now try to encrypt again using parameter-less init; should work
+        c.init(Cipher.ENCRYPT_MODE, key);
+        c.doFinal(PT);
+
+        // make sure a different iv is used
+        byte[] iv = c.getIV();
+        if (Arrays.equals(spec.getIV(), iv)) {
+            throw new Exception("IV should be different now");
+        }
+
+        // Now try to encrypt again using a different parameter; should work
+        c.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, new byte[30]));
+        c.updateAAD(AAD);
+        c.doFinal(PT);
+        // subsequent encryption should fail unless re-init w/ different key+iv
+        checkISE(c);
+
+        // Now try decryption twice in a row; no re-init required and
+        // same parameters is used.
+        c.init(Cipher.DECRYPT_MODE, key, params);
+        c.updateAAD(AAD);
+        recovered = c.doFinal(ctPlusTag);
+
+        c.updateAAD(AAD);
+        recovered = c.doFinal(ctPlusTag);
+        if (!Arrays.equals(recovered, PT)) {
+            throw new Exception("decryption result mismatch");
+        }
+
+        // Now try decryption again and re-init using the same parameters
+        c.init(Cipher.DECRYPT_MODE, key, params);
+        c.updateAAD(AAD);
+        recovered = c.doFinal(ctPlusTag);
+
+        // init to decrypt w/o parameters; should fail with IKE as
+        // javadoc specified
+        try {
+            c.init(Cipher.DECRYPT_MODE, key);
+            throw new Exception("Should throw IKE for dec w/o params");
+        } catch (InvalidKeyException ike) {
+            // expected
+        }
+
+        // Lastly, try encryption AND decryption w/ wrong type of parameters,
+        // e.g. IvParameterSpec
+        try {
+            c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
+            throw new Exception("Should throw IAPE");
+        } catch (InvalidAlgorithmParameterException iape) {
+            // expected
+        }
+        try {
+            c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
+            throw new Exception("Should throw IAPE");
+        } catch (InvalidAlgorithmParameterException iape) {
+            // expected
+        }
+
+        System.out.println("Test Passed!");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/TestGCMKeyWrap.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8014374
+ * @summary Ensure key wrap/unwrap works using AES/GCM/NoPadding
+ */
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import java.util.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class TestGCMKeyWrap extends UcryptoTest {
+
+    public static void main(String[] args) throws Exception {
+        main(new TestGCMKeyWrap(), null);
+    }
+
+    public void doTest(Provider p) throws Exception {
+        // check if GCM support exists
+        try {
+            Cipher.getInstance("AES/GCM/NoPadding", p);
+        } catch (NoSuchAlgorithmException nsae) {
+            System.out.println("Skipping Test due to no GCM support");
+            return;
+        }
+
+        Random rdm = new Random();
+
+        //init Secret Key
+        byte[] keyValue = new byte[16];
+        rdm.nextBytes(keyValue);
+        SecretKey key = new SecretKeySpec(keyValue, "AES");
+
+        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", p);
+        cipher.init(Cipher.WRAP_MODE, key);
+
+        byte[] wrappedKey = cipher.wrap(key);
+
+        try { // make sure ISE is thrown if re-using the same key/IV
+            wrappedKey = cipher.wrap(key);
+            throw new Exception("FAIL: expected ISE not thrown");
+        } catch(IllegalStateException ise){
+            System.out.println("Expected ISE thrown for re-wrapping");
+        }
+
+        //unwrap the key
+        AlgorithmParameters params = cipher.getParameters();
+        cipher.init(Cipher.UNWRAP_MODE, key, params);
+        Key unwrappedKey = cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);
+
+        //check if we can unwrap second time
+        unwrappedKey = cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);
+
+        // Comparison
+        if (!Arrays.equals(key.getEncoded(), unwrappedKey.getEncoded())) {
+            throw new Exception("FAIL: keys are not equal");
+        } else {
+            System.out.println("Passed key equality check");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/TestGCMWithSBE.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8036970
+ * @summary Ensure that Cipher object is still usable after SBE.
+ * @author Valerie Peng
+ */
+
+import java.security.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+import java.math.*;
+import com.sun.crypto.provider.*;
+
+import java.util.*;
+
+public class TestGCMWithSBE extends UcryptoTest {
+
+    private static final byte[] PT = new byte[32];
+    private static final byte[] ONE_BYTE = new byte[1];
+
+    public static void main(String[] args) throws Exception {
+        main(new TestGCMWithSBE(), null);
+    }
+
+    public void doTest(Provider p) throws Exception {
+        Cipher c;
+        try {
+            c = Cipher.getInstance("AES/GCM/NoPadding", p);
+        } catch (NoSuchAlgorithmException nsae) {
+            System.out.println("Skipping Test due to No GCM support");
+            return;
+        }
+
+        SecretKey key = new SecretKeySpec(new byte[16], "AES");
+        c.init(Cipher.ENCRYPT_MODE, key);
+
+        // test SBE with update calls
+        byte[] ct1 = null;
+        try {
+            c.update(PT, 0, PT.length, ONE_BYTE);
+        } catch (ShortBufferException sbe) {
+            // retry should work
+            ct1 = c.update(PT, 0, PT.length);
+        }
+
+        byte[] ct2PlusTag = null;
+        // test SBE with doFinal calls
+        try {
+            c.doFinal(ONE_BYTE, 0);
+        } catch (ShortBufferException sbe) {
+            // retry should work
+            ct2PlusTag = c.doFinal();
+        }
+
+        // Validate the retrieved parameters against the IV and tag length.
+        AlgorithmParameters params = c.getParameters();
+        if (params == null) {
+            throw new Exception("getParameters() should not return null");
+        }
+        GCMParameterSpec spec = params.getParameterSpec(GCMParameterSpec.class);
+        if (spec.getTLen() != (ct1.length + ct2PlusTag.length - PT.length)*8) {
+            throw new Exception("Parameters contains incorrect TLen value");
+        }
+        if (!Arrays.equals(spec.getIV(), c.getIV())) {
+            throw new Exception("Parameters contains incorrect IV value");
+        }
+
+        // Should be ok to use the same key+iv for decryption
+        c.init(Cipher.DECRYPT_MODE, key, params);
+        byte[] pt1 = c.update(ct1);
+        if (pt1 != null && pt1.length != 0) {
+            throw new Exception("Recovered text should not be returned "
+                + "to caller before tag verification");
+        }
+
+        byte[] pt2 = null;
+        try {
+            c.doFinal(ct2PlusTag, 0, ct2PlusTag.length, ONE_BYTE);
+        } catch (ShortBufferException sbe) {
+            // retry should work
+            pt2 = c.doFinal(ct2PlusTag);
+        }
+        if (!Arrays.equals(pt2, PT)) {
+            throw new Exception("decryption result mismatch");
+        }
+
+        System.out.println("Test Passed!");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/TestKATForGCM.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8014374
+ * @summary Known Answer Test for AES cipher with GCM mode
+ * @author Valerie Peng
+ */
+
+import java.security.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+import java.math.*;
+
+import java.util.*;
+
+public class TestKATForGCM extends UcryptoTest {
+    public static void main(String[] args) throws Exception {
+        main(new TestKATForGCM(), null);
+    }
+
+    // Utility methods
+    private static byte[] HexToBytes(String hexVal) {
+        if (hexVal == null) return new byte[0];
+        byte[] result = new byte[hexVal.length()/2];
+        for (int i = 0; i < result.length; i++) {
+            // 2 characters at a time
+            String byteVal = hexVal.substring(2*i, 2*i +2);
+            result[i] = Integer.valueOf(byteVal, 16).byteValue();
+        }
+        return result;
+    }
+
+    private static class TestVector {
+        SecretKey key;
+        byte[] plainText;
+        byte[] aad;
+        byte[] cipherText;
+        byte[] tag;
+        GCMParameterSpec spec;
+        String info;
+
+        TestVector(String key, String iv, String pt, String aad,
+                   String ct, String tag) {
+            this.key = new SecretKeySpec(HexToBytes(key), "AES");
+            this.plainText = HexToBytes(pt);
+            this.aad = HexToBytes(aad);
+            this.cipherText = HexToBytes(ct);
+            this.tag = HexToBytes(tag);
+            this.spec = new GCMParameterSpec(this.tag.length * 8, HexToBytes(iv));
+            this.info = "key=" + key + ", iv=" + iv + ", pt=" + pt +
+                ",aad=" + aad + ", ct=" + ct + ", tag=" + tag;
+        }
+
+        public String toString() {
+            return info;
+        }
+    }
+
+    // These test vectors are found off NIST's CAVP page
+    // http://csrc.nist.gov/groups/STM/cavp/index.html
+    // inside the link named "GCM Test Vectors", i.e.
+    // http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip
+    // CAVS 14.0, set of test vectors w/ count = 0, keysize = 128
+    private static TestVector[] testValues = {
+        // 96-bit iv w/ 128/120/112/104/96-bit tags
+        // no plain text, no aad
+        new TestVector("11754cd72aec309bf52f7687212e8957",
+                       "3c819d9a9bed087615030b65",
+                       null, null, null,
+                       "250327c674aaf477aef2675748cf6971"),
+        new TestVector("272f16edb81a7abbea887357a58c1917",
+                       "794ec588176c703d3d2a7a07",
+                       null, null, null,
+                       "b6e6f197168f5049aeda32dafbdaeb"),
+        new TestVector("81b6844aab6a568c4556a2eb7eae752f",
+                       "ce600f59618315a6829bef4d",
+                       null, null, null,
+                       "89b43e9dbc1b4f597dbbc7655bb5"),
+        new TestVector("cde2f9a9b1a004165ef9dc981f18651b",
+                       "29512c29566c7322e1e33e8e",
+                       null, null, null,
+                       "2e58ce7dabd107c82759c66a75"),
+        new TestVector("b01e45cc3088aaba9fa43d81d481823f",
+                       "5a2c4a66468713456a4bd5e1",
+                       null, null, null,
+                       "014280f944f53c681164b2ff"),
+        // 96-bit iv w/ 128/120/112/104/96-bit tags
+        // no plain text, 16-byte aad
+        new TestVector("77be63708971c4e240d1cb79e8d77feb",
+                       "e0e00f19fed7ba0136a797f3",
+                       null,
+                       "7a43ec1d9c0a5a78a0b16533a6213cab",
+                       null,
+                       "209fcc8d3675ed938e9c7166709dd946"),
+        new TestVector("da0b615656135194ba6d3c851099bc48",
+                       "d39d4b4d3cc927885090e6c3",
+                       null,
+                       "e7e5e6f8dac913036cb2ff29e8625e0e",
+                       null,
+                       "ab967711a5770461724460b07237e2"),
+        new TestVector("7e0986937a88eef894235aba4a2f43b2",
+                       "92c4a631695907166b422d60",
+                       null,
+                       "85c185f8518f9f2cd597a8f9208fc76b",
+                       null,
+                       "3bb916b728df94fe9d1916736be1"),
+        new TestVector("c3db570d7f0c21e86b028f11465d1dc9",
+                       "f86970f58ceef89fc7cb679e",
+                       null,
+                       "c095240708c0f57c288d86090ae34ee1",
+                       null,
+                       "e043c52160d652e82c7262fcf4"),
+        new TestVector("bea48ae4980d27f357611014d4486625",
+                       "32bddb5c3aa998a08556454c",
+                       null,
+                       "8a50b0b8c7654bced884f7f3afda2ead",
+                       null,
+                       "8e0f6d8bf05ffebe6f500eb1"),
+        // 96-bit iv w/ 128/120/112/104/96-bit tags
+        // no plain text, 20-byte aad
+        new TestVector("2fb45e5b8f993a2bfebc4b15b533e0b4",
+                       "5b05755f984d2b90f94b8027",
+                       null,
+                       "e85491b2202caf1d7dce03b97e09331c32473941",
+                       null,
+                       "c75b7832b2a2d9bd827412b6ef5769db"),
+        new TestVector("9bf406339fcef9675bbcf156aa1a0661",
+                       "8be4a9543d40f542abacac95",
+                       null,
+                       "7167cbf56971793186333a6685bbd58d47d379b3",
+                       null,
+                       "5e7968d7bbd5ba58cfcc750e2ef8f1"),
+        new TestVector("a2e962fff70fd0f4d63be728b80556fc",
+                       "1fa7103483de43d09bc23db4",
+                       null,
+                       "2a58edf1d53f46e4e7ee5e77ee7aeb60fc360658",
+                       null,
+                       "fa37f2dbbefab1451eae1d0d74ca"),
+        new TestVector("6bf4fdce82926dcdfc52616ed5f23695",
+                       "cc0f5899a10615567e1193ed",
+                       null,
+                       "3340655592374c1da2f05aac3ee111014986107f",
+                       null,
+                       "8ad3385cce3b5e7c985908192c"),
+        new TestVector("4df7a13e43c3d7b66b1a72fac5ba398e",
+                       "97179a3a2d417908dcf0fb28",
+                       null,
+                       "cbb7fc0010c255661e23b07dbd804b1e06ae70ac",
+                       null,
+                       "37791edae6c137ea946cfb40"),
+        // 96-bit iv w/ 128-bit tags, 13/16/32/51-byte plain text, no aad
+        new TestVector("fe9bb47deb3a61e423c2231841cfd1fb",
+                       "4d328eb776f500a2f7fb47aa",
+                       "f1cc3818e421876bb6b8bbd6c9",
+                       null,
+                       "b88c5c1977b35b517b0aeae967",
+                       "43fd4727fe5cdb4b5b42818dea7ef8c9"),
+        new TestVector("7fddb57453c241d03efbed3ac44e371c",
+                       "ee283a3fc75575e33efd4887",
+                       "d5de42b461646c255c87bd2962d3b9a2",
+                       null,
+                       "2ccda4a5415cb91e135c2a0f78c9b2fd",
+                       "b36d1df9b9d5e596f83e8b7f52971cb3"),
+        new TestVector("9971071059abc009e4f2bd69869db338",
+                       "07a9a95ea3821e9c13c63251",
+                       "f54bc3501fed4f6f6dfb5ea80106df0bd836e6826225b75c0222f6e859b35983",
+                       null,
+                       "0556c159f84ef36cb1602b4526b12009c775611bffb64dc0d9ca9297cd2c6a01",
+                       "7870d9117f54811a346970f1de090c41"),
+        new TestVector("594157ec4693202b030f33798b07176d",
+                       "49b12054082660803a1df3df",
+
+"3feef98a976a1bd634f364ac428bb59cd51fb159ec1789946918dbd50ea6c9d594a3a31a5269b0da6936c29d063a5fa2cc8a1c",
+                      null,
+
+"c1b7a46a335f23d65b8db4008a49796906e225474f4fe7d39e55bf2efd97fd82d4167de082ae30fa01e465a601235d8d68bc69",
+                      "ba92d3661ce8b04687e8788d55417dc2"),
+        // 96-bit iv w/ 128-bit tags, 16-byte plain text, 16/20/48/90-byte aad
+        new TestVector("c939cc13397c1d37de6ae0e1cb7c423c",
+                       "b3d8cc017cbb89b39e0f67e2",
+                       "c3b3c41f113a31b73d9a5cd432103069",
+                       "24825602bd12a984e0092d3e448eda5f",
+                       "93fe7d9e9bfd10348a5606e5cafa7354",
+                       "0032a1dc85f1c9786925a2e71d8272dd"),
+        new TestVector("d4a22488f8dd1d5c6c19a7d6ca17964c",
+                       "f3d5837f22ac1a0425e0d1d5",
+                       "7b43016a16896497fb457be6d2a54122",
+                       "f1c5d424b83f96c6ad8cb28ca0d20e475e023b5a",
+                       "c2bd67eef5e95cac27e3b06e3031d0a8",
+                       "f23eacf9d1cdf8737726c58648826e9c"),
+        new TestVector("89850dd398e1f1e28443a33d40162664",
+                       "e462c58482fe8264aeeb7231",
+                       "2805cdefb3ef6cc35cd1f169f98da81a",
+"d74e99d1bdaa712864eec422ac507bddbe2b0d4633cd3dff29ce5059b49fe868526c59a2a3a604457bc2afea866e7606",
+                       "ba80e244b7fc9025cd031d0f63677e06",
+                       "d84a8c3eac57d1bb0e890a8f461d1065"),
+        new TestVector("bd7c5c63b7542b56a00ebe71336a1588",
+                       "87721f23ba9c3c8ea5571abc",
+                       "de15ddbb1e202161e8a79af6a55ac6f3",
+"a6ec8075a0d3370eb7598918f3b93e48444751624997b899a87fa6a9939f844e008aa8b70e9f4c3b1a19d3286bf543e7127bfecba1ad17a5ec53fccc26faecacc4c75369498eaa7d706aef634d0009279b11e4ba6c993e5e9ed9",
+                       "41eb28c0fee4d762de972361c863bc80",
+                       "9cb567220d0b252eb97bff46e4b00ff8"),
+        // 8/1024-bit iv w/ 128-bit tag, no plain text, no aad
+        new TestVector("1672c3537afa82004c6b8a46f6f0d026",
+                       "05",
+                       null, null, null,
+                       "8e2ad721f9455f74d8b53d3141f27e8e"),
+        new TestVector("d0f1f4defa1e8c08b4b26d576392027c",
+"42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac",
+                       null, null, null,
+                       "7ab49b57ddf5f62c427950111c5c4f0d"),
+        // 8-bit iv w/ 128-bit tag, 13-byte plain text, 90-byte aad
+        new TestVector("9f79239f0904eace50784b863e723f6b",
+                       "d9",
+                       "bdb0bb10c87965acd34d146171",
+"44db436089327726c5f01139e1f339735c9e85514ccc2f167bad728010fb34a9072a9794c8a5e7361b1d0dbcdc9ac4091e354bb2896561f0486645252e9c78c86beece91bfa4f7cc4a8794ce1f305b1b735efdbf1ed1563c0be0",
+                       "7e5a7c8dadb3f0c7335b4d9d8d",
+                       "6b6ef1f53723a89f3bb7c6d043840717"),
+        // 1024-bit iv w/ 128-bit tag, 51-byte plain text, 48-byte aad
+        new TestVector("141f1ce91989b07e7eb6ae1dbd81ea5e",
+
+"49451da24bd6074509d3cebc2c0394c972e6934b45a1d91f3ce1d3ca69e194aa1958a7c21b6f21d530ce6d2cc5256a3f846b6f9d2f38df0102c4791e57df038f6e69085646007df999751e248e06c47245f4cd3b8004585a7470dee1690e9d2d63169a58d243c0b57b3e5b4a481a3e4e8c60007094ef3adea2e8f05dd3a1396f",
+"d384305af2388699aa302f510913fed0f2cb63ba42efa8c5c9de2922a2ec2fe87719dadf1eb0aef212b51e74c9c5b934104a43",
+"630cf18a91cc5a6481ac9eefd65c24b1a3c93396bd7294d6b8ba323951727666c947a21894a079ef061ee159c05beeb4",
+"f4c34e5fbe74c0297313268296cd561d59ccc95bbfcdfcdc71b0097dbd83240446b28dc088abd42b0fc687f208190ff24c0548",
+                      "dbb93bbb56d0439cd09f620a57687f5d"),
+    };
+
+    public void doTest(Provider p) throws Exception {
+        boolean testFailed = false;
+        Cipher c = null;
+        try {
+            c = Cipher.getInstance("AES/GCM/NoPadding", p);
+        } catch (NoSuchAlgorithmException nsae) {
+            System.out.println("Skipping Test due to no GCM support");
+            return;
+        }
+
+        for (int i = 0; i < testValues.length; i++) {
+            try {
+                c.init(Cipher.ENCRYPT_MODE, testValues[i].key, testValues[i].spec);
+                c.updateAAD(testValues[i].aad);
+                byte[] ctPlusTag = c.doFinal(testValues[i].plainText);
+
+                c.init(Cipher.DECRYPT_MODE, testValues[i].key, testValues[i].spec);
+                c.updateAAD(testValues[i].aad);
+                byte[] pt = c.doFinal(ctPlusTag); // should fail if tag mismatched
+
+                // check encryption/decryption results just to be sure
+                if (!Arrays.equals(testValues[i].plainText, pt)) {
+                    System.out.println("PlainText diff failed for test# " + i);
+                    testFailed = true;
+                }
+                int ctLen = testValues[i].cipherText.length;
+                if (!Arrays.equals(testValues[i].cipherText,
+                                   Arrays.copyOf(ctPlusTag, ctLen))) {
+                    System.out.println("CipherText diff failed for test# " + i);
+                    testFailed = true;
+                }
+                int tagLen = testValues[i].tag.length;
+                if (!Arrays.equals
+                    (testValues[i].tag,
+                     Arrays.copyOfRange(ctPlusTag, ctLen, ctLen+tagLen))) {
+                    System.out.println("Tag diff failed for test# " + i);
+                    testFailed = true;
+                }
+            } catch (Exception ex) {
+                // continue testing other test vectors
+                System.out.println("Failed Test Vector: " + testValues[i]);
+                ex.printStackTrace();
+                testFailed = true;
+                continue;
+            }
+        }
+        if (testFailed) {
+            throw new Exception("Test Failed");
+        }
+        // passed all tests...hooray!
+        System.out.println("Test Passed");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/TestMalformedRSA.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,257 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8024606
+ * @summary NegativeArraySizeException in NativeRSACipher
+ */
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import java.util.*;
+import java.math.*;
+import javax.crypto.*;
+
+public class TestMalformedRSA extends UcryptoTest {
+
+    // KAT
+    private static final byte PLAINTEXT[] = Arrays.copyOf
+        (new String("Known plaintext message utilized" +
+                    "for RSA Encryption &  Decryption" +
+                    "block, SHA1, SHA256, SHA384  and" +
+                    "SHA512 RSA Signature KAT tests.").getBytes(), 128);
+
+    private static final byte MOD[] = {
+        (byte)0xd5, (byte)0x84, (byte)0x95, (byte)0x07, (byte)0xf4, (byte)0xd0,
+        (byte)0x1f, (byte)0x82, (byte)0xf3, (byte)0x79, (byte)0xf4, (byte)0x99,
+        (byte)0x48, (byte)0x10, (byte)0xe1, (byte)0x71, (byte)0xa5, (byte)0x62,
+        (byte)0x22, (byte)0xa3, (byte)0x4b, (byte)0x00, (byte)0xe3, (byte)0x5b,
+        (byte)0x3a, (byte)0xcc, (byte)0x10, (byte)0x83, (byte)0xe0, (byte)0xaf,
+        (byte)0x61, (byte)0x13, (byte)0x54, (byte)0x6a, (byte)0xa2, (byte)0x6a,
+        (byte)0x2c, (byte)0x5e, (byte)0xb3, (byte)0xcc, (byte)0xa3, (byte)0x71,
+        (byte)0x9a, (byte)0xb2, (byte)0x3e, (byte)0x78, (byte)0xec, (byte)0xb5,
+        (byte)0x0e, (byte)0x6e, (byte)0x31, (byte)0x3b, (byte)0x77, (byte)0x1f,
+        (byte)0x6e, (byte)0x94, (byte)0x41, (byte)0x60, (byte)0xd5, (byte)0x6e,
+        (byte)0xd9, (byte)0xc6, (byte)0xf9, (byte)0x29, (byte)0xc3, (byte)0x40,
+        (byte)0x36, (byte)0x25, (byte)0xdb, (byte)0xea, (byte)0x0b, (byte)0x07,
+        (byte)0xae, (byte)0x76, (byte)0xfd, (byte)0x99, (byte)0x29, (byte)0xf4,
+        (byte)0x22, (byte)0xc1, (byte)0x1a, (byte)0x8f, (byte)0x05, (byte)0xfe,
+        (byte)0x98, (byte)0x09, (byte)0x07, (byte)0x05, (byte)0xc2, (byte)0x0f,
+        (byte)0x0b, (byte)0x11, (byte)0x83, (byte)0x39, (byte)0xca, (byte)0xc7,
+        (byte)0x43, (byte)0x63, (byte)0xff, (byte)0x33, (byte)0x80, (byte)0xe7,
+        (byte)0xc3, (byte)0x78, (byte)0xae, (byte)0xf1, (byte)0x73, (byte)0x52,
+        (byte)0x98, (byte)0x1d, (byte)0xde, (byte)0x5c, (byte)0x53, (byte)0x6e,
+        (byte)0x01, (byte)0x73, (byte)0x0d, (byte)0x12, (byte)0x7e, (byte)0x77,
+        (byte)0x03, (byte)0xf1, (byte)0xef, (byte)0x1b, (byte)0xc8, (byte)0xa8,
+        (byte)0x0f, (byte)0x97
+    };
+
+    private static final byte PUB_EXP[] = {(byte)0x01, (byte)0x00, (byte)0x01};
+
+    private static final byte PRIV_EXP[] = {
+        (byte)0x85, (byte)0x27, (byte)0x47, (byte)0x61, (byte)0x4c, (byte)0xd4,
+        (byte)0xb5, (byte)0xb2, (byte)0x0e, (byte)0x70, (byte)0x91, (byte)0x8f,
+        (byte)0x3d, (byte)0x97, (byte)0xf9, (byte)0x5f, (byte)0xcc, (byte)0x09,
+        (byte)0x65, (byte)0x1c, (byte)0x7c, (byte)0x5b, (byte)0xb3, (byte)0x6d,
+        (byte)0x63, (byte)0x3f, (byte)0x7b, (byte)0x55, (byte)0x22, (byte)0xbb,
+        (byte)0x7c, (byte)0x48, (byte)0x77, (byte)0xae, (byte)0x80, (byte)0x56,
+        (byte)0xc2, (byte)0x10, (byte)0xd5, (byte)0x03, (byte)0xdb, (byte)0x31,
+        (byte)0xaf, (byte)0x8d, (byte)0x54, (byte)0xd4, (byte)0x48, (byte)0x99,
+        (byte)0xa8, (byte)0xc4, (byte)0x23, (byte)0x43, (byte)0xb8, (byte)0x48,
+        (byte)0x0b, (byte)0xc7, (byte)0xbc, (byte)0xf5, (byte)0xcc, (byte)0x64,
+        (byte)0x72, (byte)0xbf, (byte)0x59, (byte)0x06, (byte)0x04, (byte)0x1c,
+        (byte)0x32, (byte)0xf5, (byte)0x14, (byte)0x2e, (byte)0x6e, (byte)0xe2,
+        (byte)0x0f, (byte)0x5c, (byte)0xde, (byte)0x36, (byte)0x3c, (byte)0x6e,
+        (byte)0x7c, (byte)0x4d, (byte)0xcc, (byte)0xd3, (byte)0x00, (byte)0x6e,
+        (byte)0xe5, (byte)0x45, (byte)0x46, (byte)0xef, (byte)0x4d, (byte)0x25,
+        (byte)0x46, (byte)0x6d, (byte)0x7f, (byte)0xed, (byte)0xbb, (byte)0x4f,
+        (byte)0x4d, (byte)0x9f, (byte)0xda, (byte)0x87, (byte)0x47, (byte)0x8f,
+        (byte)0x74, (byte)0x44, (byte)0xb7, (byte)0xbe, (byte)0x9d, (byte)0xf5,
+        (byte)0xdd, (byte)0xd2, (byte)0x4c, (byte)0xa5, (byte)0xab, (byte)0x74,
+        (byte)0xe5, (byte)0x29, (byte)0xa1, (byte)0xd2, (byte)0x45, (byte)0x3b,
+        (byte)0x33, (byte)0xde, (byte)0xd5, (byte)0xae, (byte)0xf7, (byte)0x03,
+        (byte)0x10, (byte)0x21
+    };
+
+    private static final byte PRIME_P[] = {
+        (byte)0xf9, (byte)0x74, (byte)0x8f, (byte)0x16, (byte)0x02, (byte)0x6b,
+        (byte)0xa0, (byte)0xee, (byte)0x7f, (byte)0x28, (byte)0x97, (byte)0x91,
+        (byte)0xdc, (byte)0xec, (byte)0xc0, (byte)0x7c, (byte)0x49, (byte)0xc2,
+        (byte)0x85, (byte)0x76, (byte)0xee, (byte)0x66, (byte)0x74, (byte)0x2d,
+        (byte)0x1a, (byte)0xb8, (byte)0xf7, (byte)0x2f, (byte)0x11, (byte)0x5b,
+        (byte)0x36, (byte)0xd8, (byte)0x46, (byte)0x33, (byte)0x3b, (byte)0xd8,
+        (byte)0xf3, (byte)0x2d, (byte)0xa1, (byte)0x03, (byte)0x83, (byte)0x2b,
+        (byte)0xec, (byte)0x35, (byte)0x43, (byte)0x32, (byte)0xff, (byte)0xdd,
+        (byte)0x81, (byte)0x7c, (byte)0xfd, (byte)0x65, (byte)0x13, (byte)0x04,
+        (byte)0x7c, (byte)0xfc, (byte)0x03, (byte)0x97, (byte)0xf0, (byte)0xd5,
+        (byte)0x62, (byte)0xdc, (byte)0x0d, (byte)0xbf
+    };
+
+    private static final byte PRIME_Q[] = {
+        (byte)0xdb, (byte)0x1e, (byte)0xa7, (byte)0x3d, (byte)0xe7, (byte)0xfa,
+        (byte)0x8b, (byte)0x04, (byte)0x83, (byte)0x48, (byte)0xf3, (byte)0xa5,
+        (byte)0x31, (byte)0x9d, (byte)0x35, (byte)0x5e, (byte)0x4d, (byte)0x54,
+        (byte)0x77, (byte)0xcc, (byte)0x84, (byte)0x09, (byte)0xf3, (byte)0x11,
+        (byte)0x0d, (byte)0x54, (byte)0xed, (byte)0x85, (byte)0x39, (byte)0xa9,
+        (byte)0xca, (byte)0xa8, (byte)0xea, (byte)0xae, (byte)0x19, (byte)0x9c,
+        (byte)0x75, (byte)0xdb, (byte)0x88, (byte)0xb8, (byte)0x04, (byte)0x8d,
+        (byte)0x54, (byte)0xc6, (byte)0xa4, (byte)0x80, (byte)0xf8, (byte)0x93,
+        (byte)0xf0, (byte)0xdb, (byte)0x19, (byte)0xef, (byte)0xd7, (byte)0x87,
+        (byte)0x8a, (byte)0x8f, (byte)0x5a, (byte)0x09, (byte)0x2e, (byte)0x54,
+        (byte)0xf3, (byte)0x45, (byte)0x24, (byte)0x29
+    };
+
+    private static final byte EXP_P[] = {
+        (byte)0x6a, (byte)0xd1, (byte)0x25, (byte)0x80, (byte)0x18, (byte)0x33,
+        (byte)0x3c, (byte)0x2b, (byte)0x44, (byte)0x19, (byte)0xfe, (byte)0xa5,
+        (byte)0x40, (byte)0x03, (byte)0xc4, (byte)0xfc, (byte)0xb3, (byte)0x9c,
+        (byte)0xef, (byte)0x07, (byte)0x99, (byte)0x58, (byte)0x17, (byte)0xc1,
+        (byte)0x44, (byte)0xa3, (byte)0x15, (byte)0x7d, (byte)0x7b, (byte)0x22,
+        (byte)0x22, (byte)0xdf, (byte)0x03, (byte)0x58, (byte)0x66, (byte)0xf5,
+        (byte)0x24, (byte)0x54, (byte)0x52, (byte)0x91, (byte)0x2d, (byte)0x76,
+        (byte)0xfe, (byte)0x63, (byte)0x64, (byte)0x4e, (byte)0x0f, (byte)0x50,
+        (byte)0x2b, (byte)0x65, (byte)0x79, (byte)0x1f, (byte)0xf1, (byte)0xbf,
+        (byte)0xc7, (byte)0x41, (byte)0x26, (byte)0xcc, (byte)0xc6, (byte)0x1c,
+        (byte)0xa9, (byte)0x83, (byte)0x6f, (byte)0x03
+    };
+
+    private static final byte EXP_Q[] = {
+        (byte)0x12, (byte)0x84, (byte)0x1a, (byte)0x99, (byte)0xce, (byte)0x9a,
+        (byte)0x8b, (byte)0x58, (byte)0xcc, (byte)0x47, (byte)0x43, (byte)0xdf,
+        (byte)0x77, (byte)0xbb, (byte)0xd3, (byte)0x20, (byte)0xae, (byte)0xe4,
+        (byte)0x2e, (byte)0x63, (byte)0x67, (byte)0xdc, (byte)0xf7, (byte)0x5f,
+        (byte)0x3f, (byte)0x83, (byte)0x27, (byte)0xb7, (byte)0x14, (byte)0x52,
+        (byte)0x56, (byte)0xbf, (byte)0xc3, (byte)0x65, (byte)0x06, (byte)0xe1,
+        (byte)0x03, (byte)0xcc, (byte)0x93, (byte)0x57, (byte)0x09, (byte)0x7b,
+        (byte)0x6f, (byte)0xe8, (byte)0x81, (byte)0x4a, (byte)0x2c, (byte)0xb7,
+        (byte)0x43, (byte)0xa9, (byte)0x20, (byte)0x1d, (byte)0xf6, (byte)0x56,
+        (byte)0x8b, (byte)0xcc, (byte)0xe5, (byte)0x4c, (byte)0xd5, (byte)0x4f,
+        (byte)0x74, (byte)0x67, (byte)0x29, (byte)0x51
+    };
+
+    private static final byte CRT_COEFF[] = {
+        (byte)0x23, (byte)0xab, (byte)0xf4, (byte)0x03, (byte)0x2f, (byte)0x29,
+        (byte)0x95, (byte)0x74, (byte)0xac, (byte)0x1a, (byte)0x33, (byte)0x96,
+        (byte)0x62, (byte)0xed, (byte)0xf7, (byte)0xf6, (byte)0xae, (byte)0x07,
+        (byte)0x2a, (byte)0x2e, (byte)0xe8, (byte)0xab, (byte)0xfb, (byte)0x1e,
+        (byte)0xb9, (byte)0xb2, (byte)0x88, (byte)0x1e, (byte)0x85, (byte)0x05,
+        (byte)0x42, (byte)0x64, (byte)0x03, (byte)0xb2, (byte)0x8b, (byte)0xc1,
+        (byte)0x81, (byte)0x75, (byte)0xd7, (byte)0xba, (byte)0xaa, (byte)0xd4,
+        (byte)0x31, (byte)0x3c, (byte)0x8a, (byte)0x96, (byte)0x23, (byte)0x9d,
+        (byte)0x3f, (byte)0x06, (byte)0x3e, (byte)0x44, (byte)0xa9, (byte)0x62,
+        (byte)0x2f, (byte)0x61, (byte)0x5a, (byte)0x51, (byte)0x82, (byte)0x2c,
+        (byte)0x04, (byte)0x85, (byte)0x73, (byte)0xd1
+    };
+
+    private static KeyPair genPredefinedRSAKeyPair() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        BigInteger mod = new BigInteger(MOD);
+        BigInteger pub = new BigInteger(PUB_EXP);
+
+        PrivateKey privKey = kf.generatePrivate
+            (new RSAPrivateCrtKeySpec
+             (mod, pub, new BigInteger(PRIV_EXP),
+              new BigInteger(PRIME_P), new BigInteger(PRIME_Q),
+              new BigInteger(EXP_P), new BigInteger(EXP_Q),
+              new BigInteger(CRT_COEFF)));
+        PublicKey pubKey = kf.generatePublic(new RSAPublicKeySpec(mod, pub));
+        return new KeyPair(pubKey, privKey);
+    }
+
+    private static final String CIP_ALGOS[] = {
+        "RSA/ECB/NoPadding",
+        "RSA/ECB/PKCS1Padding"
+    };
+    private static final int INPUT_SIZE_REDUCTION[] = {
+        0,
+        11,
+    };
+
+    private static KeyPair kp[] = null;
+
+    public static void main(String argv[]) throws Exception {
+        main(new TestMalformedRSA(), null);
+    }
+
+    public void doTest(Provider prov) throws Exception {
+        // first test w/ predefine KeyPair
+        KeyPair pkp = genPredefinedRSAKeyPair();
+        System.out.println("Test against Predefined RSA Key Pair");
+        testCipher(pkp, 128, false, prov);
+    }
+
+
+    private static void testCipher(KeyPair kp, int inputSizeInBytes,
+                                   boolean checkInterop, Provider prov)
+        throws Exception {
+        Cipher c1, c2;
+        for (int i = 0; i < CIP_ALGOS.length; i++) {
+            String algo = CIP_ALGOS[i];
+            try {
+                c1 = Cipher.getInstance(algo, prov);
+            } catch (NoSuchAlgorithmException nsae) {
+                System.out.println("Skip unsupported Cipher algo: " + algo);
+                continue;
+            }
+
+            if (checkInterop) {
+                c2 = Cipher.getInstance(algo, "SunJCE");
+            } else {
+                c2 = Cipher.getInstance(algo, prov);
+            }
+            byte[] data = Arrays.copyOf
+                 (PLAINTEXT, inputSizeInBytes - INPUT_SIZE_REDUCTION[i]);
+
+            testEncryption(c1, c2, kp, data);
+        }
+    }
+
+    private static void testEncryption(Cipher c1, Cipher c2,
+            KeyPair kp, byte[] data) throws Exception {
+
+        // C1 Encrypt + C2 Decrypt
+        byte[] out1 = null;
+        byte[] recoveredText = null;
+        try {
+            c1.init(Cipher.ENCRYPT_MODE, kp.getPublic());
+            out1 = c1.doFinal(data);
+
+            // damage the cipher text
+            out1[out1.length - 1] = (byte)(out1[out1.length - 1] ^ 0xFF);
+
+            c2.init(Cipher.DECRYPT_MODE, kp.getPrivate());
+            recoveredText = c2.doFinal(out1);
+
+            // Note that decryption of "RSA/ECB/NoPadding" don't throw
+            // BadPaddingException
+            System.out.println("\t=> PASS: " + c2.getAlgorithm());
+        } catch (BadPaddingException ex) {
+            System.out.println("\tDEC ERROR: " + c2.getAlgorithm());
+            System.out.println("\t=> PASS: expected BadPaddingException");
+            ex.printStackTrace();
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/TestRSA.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,422 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug     7088989
+ * @summary Ensure the RSA ciphers and signatures works correctly
+ */
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import java.util.*;
+import java.math.*;
+import javax.crypto.*;
+
+public class TestRSA extends UcryptoTest {
+
+    // KAT
+    private static final byte PLAINTEXT[] = Arrays.copyOf
+        (new String("Known plaintext message utilized" +
+                    "for RSA Encryption &  Decryption" +
+                    "block, SHA1, SHA256, SHA384  and" +
+                    "SHA512 RSA Signature KAT tests.").getBytes(), 128);
+
+    private static final byte MOD[] = {
+        (byte)0xd5, (byte)0x84, (byte)0x95, (byte)0x07, (byte)0xf4, (byte)0xd0,
+        (byte)0x1f, (byte)0x82, (byte)0xf3, (byte)0x79, (byte)0xf4, (byte)0x99,
+        (byte)0x48, (byte)0x10, (byte)0xe1, (byte)0x71, (byte)0xa5, (byte)0x62,
+        (byte)0x22, (byte)0xa3, (byte)0x4b, (byte)0x00, (byte)0xe3, (byte)0x5b,
+        (byte)0x3a, (byte)0xcc, (byte)0x10, (byte)0x83, (byte)0xe0, (byte)0xaf,
+        (byte)0x61, (byte)0x13, (byte)0x54, (byte)0x6a, (byte)0xa2, (byte)0x6a,
+        (byte)0x2c, (byte)0x5e, (byte)0xb3, (byte)0xcc, (byte)0xa3, (byte)0x71,
+        (byte)0x9a, (byte)0xb2, (byte)0x3e, (byte)0x78, (byte)0xec, (byte)0xb5,
+        (byte)0x0e, (byte)0x6e, (byte)0x31, (byte)0x3b, (byte)0x77, (byte)0x1f,
+        (byte)0x6e, (byte)0x94, (byte)0x41, (byte)0x60, (byte)0xd5, (byte)0x6e,
+        (byte)0xd9, (byte)0xc6, (byte)0xf9, (byte)0x29, (byte)0xc3, (byte)0x40,
+        (byte)0x36, (byte)0x25, (byte)0xdb, (byte)0xea, (byte)0x0b, (byte)0x07,
+        (byte)0xae, (byte)0x76, (byte)0xfd, (byte)0x99, (byte)0x29, (byte)0xf4,
+        (byte)0x22, (byte)0xc1, (byte)0x1a, (byte)0x8f, (byte)0x05, (byte)0xfe,
+        (byte)0x98, (byte)0x09, (byte)0x07, (byte)0x05, (byte)0xc2, (byte)0x0f,
+        (byte)0x0b, (byte)0x11, (byte)0x83, (byte)0x39, (byte)0xca, (byte)0xc7,
+        (byte)0x43, (byte)0x63, (byte)0xff, (byte)0x33, (byte)0x80, (byte)0xe7,
+        (byte)0xc3, (byte)0x78, (byte)0xae, (byte)0xf1, (byte)0x73, (byte)0x52,
+        (byte)0x98, (byte)0x1d, (byte)0xde, (byte)0x5c, (byte)0x53, (byte)0x6e,
+        (byte)0x01, (byte)0x73, (byte)0x0d, (byte)0x12, (byte)0x7e, (byte)0x77,
+        (byte)0x03, (byte)0xf1, (byte)0xef, (byte)0x1b, (byte)0xc8, (byte)0xa8,
+        (byte)0x0f, (byte)0x97
+    };
+
+    private static final byte PUB_EXP[] = {(byte)0x01, (byte)0x00, (byte)0x01};
+
+    private static final byte PRIV_EXP[] = {
+        (byte)0x85, (byte)0x27, (byte)0x47, (byte)0x61, (byte)0x4c, (byte)0xd4,
+        (byte)0xb5, (byte)0xb2, (byte)0x0e, (byte)0x70, (byte)0x91, (byte)0x8f,
+        (byte)0x3d, (byte)0x97, (byte)0xf9, (byte)0x5f, (byte)0xcc, (byte)0x09,
+        (byte)0x65, (byte)0x1c, (byte)0x7c, (byte)0x5b, (byte)0xb3, (byte)0x6d,
+        (byte)0x63, (byte)0x3f, (byte)0x7b, (byte)0x55, (byte)0x22, (byte)0xbb,
+        (byte)0x7c, (byte)0x48, (byte)0x77, (byte)0xae, (byte)0x80, (byte)0x56,
+        (byte)0xc2, (byte)0x10, (byte)0xd5, (byte)0x03, (byte)0xdb, (byte)0x31,
+        (byte)0xaf, (byte)0x8d, (byte)0x54, (byte)0xd4, (byte)0x48, (byte)0x99,
+        (byte)0xa8, (byte)0xc4, (byte)0x23, (byte)0x43, (byte)0xb8, (byte)0x48,
+        (byte)0x0b, (byte)0xc7, (byte)0xbc, (byte)0xf5, (byte)0xcc, (byte)0x64,
+        (byte)0x72, (byte)0xbf, (byte)0x59, (byte)0x06, (byte)0x04, (byte)0x1c,
+        (byte)0x32, (byte)0xf5, (byte)0x14, (byte)0x2e, (byte)0x6e, (byte)0xe2,
+        (byte)0x0f, (byte)0x5c, (byte)0xde, (byte)0x36, (byte)0x3c, (byte)0x6e,
+        (byte)0x7c, (byte)0x4d, (byte)0xcc, (byte)0xd3, (byte)0x00, (byte)0x6e,
+        (byte)0xe5, (byte)0x45, (byte)0x46, (byte)0xef, (byte)0x4d, (byte)0x25,
+        (byte)0x46, (byte)0x6d, (byte)0x7f, (byte)0xed, (byte)0xbb, (byte)0x4f,
+        (byte)0x4d, (byte)0x9f, (byte)0xda, (byte)0x87, (byte)0x47, (byte)0x8f,
+        (byte)0x74, (byte)0x44, (byte)0xb7, (byte)0xbe, (byte)0x9d, (byte)0xf5,
+        (byte)0xdd, (byte)0xd2, (byte)0x4c, (byte)0xa5, (byte)0xab, (byte)0x74,
+        (byte)0xe5, (byte)0x29, (byte)0xa1, (byte)0xd2, (byte)0x45, (byte)0x3b,
+        (byte)0x33, (byte)0xde, (byte)0xd5, (byte)0xae, (byte)0xf7, (byte)0x03,
+        (byte)0x10, (byte)0x21
+    };
+
+    private static final byte PRIME_P[] = {
+        (byte)0xf9, (byte)0x74, (byte)0x8f, (byte)0x16, (byte)0x02, (byte)0x6b,
+        (byte)0xa0, (byte)0xee, (byte)0x7f, (byte)0x28, (byte)0x97, (byte)0x91,
+        (byte)0xdc, (byte)0xec, (byte)0xc0, (byte)0x7c, (byte)0x49, (byte)0xc2,
+        (byte)0x85, (byte)0x76, (byte)0xee, (byte)0x66, (byte)0x74, (byte)0x2d,
+        (byte)0x1a, (byte)0xb8, (byte)0xf7, (byte)0x2f, (byte)0x11, (byte)0x5b,
+        (byte)0x36, (byte)0xd8, (byte)0x46, (byte)0x33, (byte)0x3b, (byte)0xd8,
+        (byte)0xf3, (byte)0x2d, (byte)0xa1, (byte)0x03, (byte)0x83, (byte)0x2b,
+        (byte)0xec, (byte)0x35, (byte)0x43, (byte)0x32, (byte)0xff, (byte)0xdd,
+        (byte)0x81, (byte)0x7c, (byte)0xfd, (byte)0x65, (byte)0x13, (byte)0x04,
+        (byte)0x7c, (byte)0xfc, (byte)0x03, (byte)0x97, (byte)0xf0, (byte)0xd5,
+        (byte)0x62, (byte)0xdc, (byte)0x0d, (byte)0xbf
+    };
+
+    private static final byte PRIME_Q[] = {
+        (byte)0xdb, (byte)0x1e, (byte)0xa7, (byte)0x3d, (byte)0xe7, (byte)0xfa,
+        (byte)0x8b, (byte)0x04, (byte)0x83, (byte)0x48, (byte)0xf3, (byte)0xa5,
+        (byte)0x31, (byte)0x9d, (byte)0x35, (byte)0x5e, (byte)0x4d, (byte)0x54,
+        (byte)0x77, (byte)0xcc, (byte)0x84, (byte)0x09, (byte)0xf3, (byte)0x11,
+        (byte)0x0d, (byte)0x54, (byte)0xed, (byte)0x85, (byte)0x39, (byte)0xa9,
+        (byte)0xca, (byte)0xa8, (byte)0xea, (byte)0xae, (byte)0x19, (byte)0x9c,
+        (byte)0x75, (byte)0xdb, (byte)0x88, (byte)0xb8, (byte)0x04, (byte)0x8d,
+        (byte)0x54, (byte)0xc6, (byte)0xa4, (byte)0x80, (byte)0xf8, (byte)0x93,
+        (byte)0xf0, (byte)0xdb, (byte)0x19, (byte)0xef, (byte)0xd7, (byte)0x87,
+        (byte)0x8a, (byte)0x8f, (byte)0x5a, (byte)0x09, (byte)0x2e, (byte)0x54,
+        (byte)0xf3, (byte)0x45, (byte)0x24, (byte)0x29
+    };
+
+    private static final byte EXP_P[] = {
+        (byte)0x6a, (byte)0xd1, (byte)0x25, (byte)0x80, (byte)0x18, (byte)0x33,
+        (byte)0x3c, (byte)0x2b, (byte)0x44, (byte)0x19, (byte)0xfe, (byte)0xa5,
+        (byte)0x40, (byte)0x03, (byte)0xc4, (byte)0xfc, (byte)0xb3, (byte)0x9c,
+        (byte)0xef, (byte)0x07, (byte)0x99, (byte)0x58, (byte)0x17, (byte)0xc1,
+        (byte)0x44, (byte)0xa3, (byte)0x15, (byte)0x7d, (byte)0x7b, (byte)0x22,
+        (byte)0x22, (byte)0xdf, (byte)0x03, (byte)0x58, (byte)0x66, (byte)0xf5,
+        (byte)0x24, (byte)0x54, (byte)0x52, (byte)0x91, (byte)0x2d, (byte)0x76,
+        (byte)0xfe, (byte)0x63, (byte)0x64, (byte)0x4e, (byte)0x0f, (byte)0x50,
+        (byte)0x2b, (byte)0x65, (byte)0x79, (byte)0x1f, (byte)0xf1, (byte)0xbf,
+        (byte)0xc7, (byte)0x41, (byte)0x26, (byte)0xcc, (byte)0xc6, (byte)0x1c,
+        (byte)0xa9, (byte)0x83, (byte)0x6f, (byte)0x03
+    };
+
+    private static final byte EXP_Q[] = {
+        (byte)0x12, (byte)0x84, (byte)0x1a, (byte)0x99, (byte)0xce, (byte)0x9a,
+        (byte)0x8b, (byte)0x58, (byte)0xcc, (byte)0x47, (byte)0x43, (byte)0xdf,
+        (byte)0x77, (byte)0xbb, (byte)0xd3, (byte)0x20, (byte)0xae, (byte)0xe4,
+        (byte)0x2e, (byte)0x63, (byte)0x67, (byte)0xdc, (byte)0xf7, (byte)0x5f,
+        (byte)0x3f, (byte)0x83, (byte)0x27, (byte)0xb7, (byte)0x14, (byte)0x52,
+        (byte)0x56, (byte)0xbf, (byte)0xc3, (byte)0x65, (byte)0x06, (byte)0xe1,
+        (byte)0x03, (byte)0xcc, (byte)0x93, (byte)0x57, (byte)0x09, (byte)0x7b,
+        (byte)0x6f, (byte)0xe8, (byte)0x81, (byte)0x4a, (byte)0x2c, (byte)0xb7,
+        (byte)0x43, (byte)0xa9, (byte)0x20, (byte)0x1d, (byte)0xf6, (byte)0x56,
+        (byte)0x8b, (byte)0xcc, (byte)0xe5, (byte)0x4c, (byte)0xd5, (byte)0x4f,
+        (byte)0x74, (byte)0x67, (byte)0x29, (byte)0x51
+    };
+
+    private static final byte CRT_COEFF[] = {
+        (byte)0x23, (byte)0xab, (byte)0xf4, (byte)0x03, (byte)0x2f, (byte)0x29,
+        (byte)0x95, (byte)0x74, (byte)0xac, (byte)0x1a, (byte)0x33, (byte)0x96,
+        (byte)0x62, (byte)0xed, (byte)0xf7, (byte)0xf6, (byte)0xae, (byte)0x07,
+        (byte)0x2a, (byte)0x2e, (byte)0xe8, (byte)0xab, (byte)0xfb, (byte)0x1e,
+        (byte)0xb9, (byte)0xb2, (byte)0x88, (byte)0x1e, (byte)0x85, (byte)0x05,
+        (byte)0x42, (byte)0x64, (byte)0x03, (byte)0xb2, (byte)0x8b, (byte)0xc1,
+        (byte)0x81, (byte)0x75, (byte)0xd7, (byte)0xba, (byte)0xaa, (byte)0xd4,
+        (byte)0x31, (byte)0x3c, (byte)0x8a, (byte)0x96, (byte)0x23, (byte)0x9d,
+        (byte)0x3f, (byte)0x06, (byte)0x3e, (byte)0x44, (byte)0xa9, (byte)0x62,
+        (byte)0x2f, (byte)0x61, (byte)0x5a, (byte)0x51, (byte)0x82, (byte)0x2c,
+        (byte)0x04, (byte)0x85, (byte)0x73, (byte)0xd1
+    };
+
+    private static KeyPair genRSAKey(int keyLength) throws Exception {
+        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+        kpg.initialize(keyLength);
+        return kpg.generateKeyPair();
+    }
+
+    private static KeyPair genPredefinedRSAKeyPair() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        BigInteger mod = new BigInteger(MOD);
+        BigInteger pub = new BigInteger(PUB_EXP);
+
+        PrivateKey privKey = kf.generatePrivate
+            (new RSAPrivateCrtKeySpec
+             (mod, pub, new BigInteger(PRIV_EXP),
+              new BigInteger(PRIME_P), new BigInteger(PRIME_Q),
+              new BigInteger(EXP_P), new BigInteger(EXP_Q),
+              new BigInteger(CRT_COEFF)));
+        PublicKey pubKey = kf.generatePublic(new RSAPublicKeySpec(mod, pub));
+        return new KeyPair(pubKey, privKey);
+    }
+
+    private static final String CIP_ALGOS[] = {
+        "RSA/ECB/NoPadding",
+        "RSA/ECB/PKCS1Padding"
+    };
+    private static final int INPUT_SIZE_REDUCTION[] = {
+        0,
+        11,
+    };
+    private static final String SIG_ALGOS[] = {
+        "MD5WithRSA",
+        "SHA1WithRSA",
+        "SHA256WithRSA",
+        "SHA384WithRSA",
+        "SHA512WithRSA"
+    };
+
+    private static KeyPair kp[] = null;
+
+    public static void main(String argv[]) throws Exception {
+        main(new TestRSA(), null);
+    }
+
+    public void doTest(Provider prov) throws Exception {
+        // first test w/ predefine KeyPair
+        KeyPair pkp = genPredefinedRSAKeyPair();
+        System.out.println("Test against Predefined RSA Key Pair");
+        testCipher(pkp, 128, true, prov);
+        testSignature(pkp, true, prov);
+
+        for (int i = 0; i < 10; i++) {
+            // then test w/ various key lengths
+            int keyLens[] = { 1024, 2048 };
+            kp = new KeyPair[keyLens.length];
+
+            testCipher(keyLens, false, prov);
+            testSignature(keyLens, false, prov);
+        }
+    }
+
+
+    private static void testCipher(KeyPair kp, int inputSizeInBytes,
+                                   boolean checkInterop, Provider prov)
+        throws Exception {
+        Cipher c1, c2;
+        for (int i = 0; i < CIP_ALGOS.length; i++) {
+            String algo = CIP_ALGOS[i];
+            try {
+                c1 = Cipher.getInstance(algo, prov);
+            } catch (NoSuchAlgorithmException nsae) {
+                System.out.println("Skip unsupported Cipher algo: " + algo);
+                continue;
+            }
+
+            if (checkInterop) {
+                c2 = Cipher.getInstance(algo, "SunJCE");
+            } else {
+                c2 = Cipher.getInstance(algo, prov);
+            }
+            byte[] data = Arrays.copyOf
+                 (PLAINTEXT, inputSizeInBytes - INPUT_SIZE_REDUCTION[i]);
+
+            testEncryption(c1, c2, kp, data);
+        }
+    }
+
+    private static void testCipher(int keyLens[], boolean checkInterop,
+                                   Provider prov)
+        throws Exception {
+        // RSA CipherText will always differ due to the random nonce in padding
+        // so we check whether both
+        // 1) Java Encrypt/C Decrypt
+        // 2) C Encrypt/Java Decrypt
+        // works
+        Cipher c1, c2;
+        for (int i = 0; i < CIP_ALGOS.length; i++) {
+            String algo = CIP_ALGOS[i];
+            try {
+                c1 = Cipher.getInstance(algo, prov);
+            } catch (NoSuchAlgorithmException nsae) {
+                System.out.println("Skip unsupported Cipher algo: " + algo);
+                continue;
+            }
+
+            if (checkInterop) {
+                c2 = Cipher.getInstance(algo, "SunJCE");
+            } else {
+                c2 = Cipher.getInstance(algo, prov);
+            }
+
+            for (int h = 0; h < keyLens.length; h++) {
+                // Defer key pair generation until now when it'll soon be used.
+                if (kp[h] == null) {
+                    kp[h] = genRSAKey(keyLens[h]);
+                }
+                System.out.println("\tTesting Cipher " + algo + " w/ KeySize " + keyLens[h]);
+                byte[] data = Arrays.copyOf
+                    (PLAINTEXT, keyLens[h]/8 - INPUT_SIZE_REDUCTION[i]);
+                testEncryption(c1, c2, kp[h], data);
+            }
+        }
+    }
+
+    private static void testEncryption(Cipher c1, Cipher c2, KeyPair kp, byte[] data)
+        throws Exception {
+        // C1 Encrypt + C2 Decrypt
+        byte[] out1 = null;
+        byte[] recoveredText = null;
+        try {
+            c1.init(Cipher.ENCRYPT_MODE, kp.getPublic());
+            out1 = c1.doFinal(data);
+            c2.init(Cipher.DECRYPT_MODE, kp.getPrivate());
+            recoveredText = c2.doFinal(out1);
+        } catch (Exception ex) {
+            System.out.println("\tDEC ERROR: unexpected exception");
+            ex.printStackTrace();
+            throw ex;
+        }
+        if(!Arrays.equals(recoveredText, data)) {
+            throw new RuntimeException("\tDEC ERROR: different PT bytes!");
+        }
+        // C2 Encrypt + C1 Decrypt
+        byte[] cipherText = null;
+        try {
+            c2.init(Cipher.ENCRYPT_MODE, kp.getPublic());
+            cipherText = c2.doFinal(data);
+            c1.init(Cipher.DECRYPT_MODE, kp.getPrivate());
+            try {
+                out1 = c1.doFinal(cipherText);
+            } catch (Exception ex) {
+                System.out.println("\tENC ERROR: invalid encrypted output");
+                ex.printStackTrace();
+                throw ex;
+            }
+        } catch (Exception ex) {
+            System.out.println("\tENC ERROR: unexpected exception");
+            ex.printStackTrace();
+            throw ex;
+        }
+        if (!Arrays.equals(out1, data)) {
+            throw new RuntimeException("\tENC ERROR: Decrypted result DIFF!");
+        }
+        System.out.println("\t=> PASS");
+    }
+
+    private static void testSignature(KeyPair kp, boolean checkInterop,
+                                      Provider prov) throws Exception {
+        byte[] data = PLAINTEXT;
+        Signature sig1, sig2;
+        for (int i = 0; i < SIG_ALGOS.length; i++) {
+            String algo = SIG_ALGOS[i];
+            try {
+                sig1 = Signature.getInstance(algo, prov);
+            } catch (NoSuchAlgorithmException nsae) {
+                System.out.println("Skip unsupported Signature algo: " + algo);
+                continue;
+            }
+
+            if (checkInterop) {
+                sig2 = Signature.getInstance(algo, "SunRsaSign");
+            } else {
+                sig2 = Signature.getInstance(algo, prov);
+            }
+            testSigning(sig1, sig2, kp, data);
+        }
+    }
+
+    private static void testSignature(int keyLens[], boolean checkInterop,
+                                      Provider prov) throws Exception {
+        byte[] data = PLAINTEXT;
+        Signature sig1, sig2;
+        for (int i = 0; i < SIG_ALGOS.length; i++) {
+            String algo = SIG_ALGOS[i];
+            try {
+                sig1 = Signature.getInstance(algo, prov);
+            } catch (NoSuchAlgorithmException nsae) {
+                System.out.println("Skip unsupported Signature algo: " + algo);
+                continue;
+            }
+
+            if (checkInterop) {
+                sig2 = Signature.getInstance(algo, "SunRsaSign");
+            } else {
+                sig2 = Signature.getInstance(algo, prov);
+            }
+
+            for (int h = 0; h < keyLens.length; h++) {
+                // Defer key pair generation until now when it'll soon be used.
+                if (kp[h] == null) {
+                    kp[h] = genRSAKey(keyLens[h]);
+                }
+                System.out.println("\tTesting Signature " + algo + " w/ KeySize " + keyLens[h]);
+
+                testSigning(sig1, sig2, kp[h], data);
+            }
+        }
+    }
+
+    private static void testSigning(Signature sig1, Signature sig2, KeyPair kp, byte[] data)
+            throws Exception {
+        boolean sameSig = false;
+        byte[] out = null;
+        try {
+            sig1.initSign(kp.getPrivate());
+            sig1.update(data);
+            out = sig1.sign();
+        } catch (Exception ex) {
+            System.out.println("\tSIGN ERROR: unexpected exception!");
+            ex.printStackTrace();
+        }
+
+        sig2.initSign(kp.getPrivate());
+        sig2.update(data);
+        byte[] out2 = sig2.sign();
+        if (!Arrays.equals(out2, out)) {
+            throw new RuntimeException("\tSIGN ERROR: Signature DIFF!");
+        }
+
+        boolean verify = false;
+        try {
+            System.out.println("\tVERIFY1 using native out");
+            sig1.initVerify(kp.getPublic());
+            sig1.update(data);
+            verify = sig1.verify(out);
+            if (!verify) {
+                throw new RuntimeException("VERIFY1 FAIL!");
+            }
+        } catch (Exception ex) {
+            System.out.println("\tVERIFY1 ERROR: unexpected exception!");
+            ex.printStackTrace();
+            throw ex;
+        }
+        System.out.println("\t=> PASS");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/oracle/security/ucrypto/UcryptoTest.java	Mon Oct 20 21:18:48 2014 +0000
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.*;
+import java.util.*;
+import java.lang.reflect.*;
+import java.security.*;
+
+// common infrastructure for OracleUcrypto provider tests
+public abstract class UcryptoTest {
+
+    protected static final boolean hasUcrypto;
+    static {
+        hasUcrypto = (Security.getProvider("OracleUcrypto") != null);
+    }
+
+    private static Provider getCustomizedUcrypto(String config) throws Exception {
+        Class clazz = Class.forName("com.oracle.security.ucrypto.OracleUcrypto");
+        Constructor cons = clazz.getConstructor(new Class[] {String.class});
+        Object obj = cons.newInstance(new Object[] {config});
+        return (Provider)obj;
+    }
+
+    public abstract void doTest(Provider p) throws Exception;
+
+    public static void main(UcryptoTest test, String config) throws Exception {
+        Provider prov = null;
+        if (hasUcrypto) {
+            if (config != null) {
+                prov = getCustomizedUcrypto(config);
+            } else {
+                prov = Security.getProvider("OracleUcrypto");
+            }
+        }
+        if (prov == null) {
+            // un-available, skip testing...
+            System.out.println("No OracleUcrypto provider found, skipping test");
+            return;
+        }
+        test.doTest(prov);
+    }
+}