Projects
openEuler:24.03:SP1:Everything
openjdk-1.8.0
_service:tar_scm:kae-phase1.patch
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:kae-phase1.patch of Package openjdk-1.8.0
From 4993e7a69c88f01dc8c858cfa429c3904a632462 Mon Sep 17 00:00:00 2001 Date: Tue, 16 Mar 2021 06:03:50 +0000 Subject: [PATCH 3/3] add kae feature --- common/autoconf/generated-configure.sh | 28 + common/autoconf/jdk-options.m4 | 14 + common/autoconf/spec.gmk.in | 1 + jdk/make/CompileJavaClasses.gmk | 28 +- jdk/make/CreateJars.gmk | 1 + jdk/make/CreateSecurityJars.gmk | 29 + jdk/make/SignJars.gmk | 6 + jdk/make/lib/SecurityLibraries.gmk | 25 + jdk/make/mapfiles/libj2kae/mapfile-vers | 57 ++ jdk/make/profile-includes.txt | 12 + .../security/openssl/KAEAESCipher.java | 725 ++++++++++++++++ .../openeuler/security/openssl/KAEDigest.java | 264 ++++++ .../openeuler/security/openssl/KAEMac.java | 228 +++++ .../security/openssl/KAEProvider.java | 180 ++++ .../security/openssl/KAERSACipher.java | 796 ++++++++++++++++++ .../openssl/KAERSAKeyPairGenerator.java | 164 ++++ .../security/openssl/KAERSAPaddingType.java | 80 ++ .../openeuler/security/openssl/KAEUtils.java | 196 +++++ .../security/openssl/kae_cipher_aes.c | 255 ++++++ .../security/openssl/kae_cipher_rsa.c | 463 ++++++++++ .../openeuler/security/openssl/kae_digest.c | 227 +++++ .../security/openssl/kae_exception.c | 116 +++ .../security/openssl/kae_exception.h | 52 ++ .../openssl/kae_keypairgenerator_rsa.c | 173 ++++ .../org/openeuler/security/openssl/kae_log.h | 33 + .../org/openeuler/security/openssl/kae_mac.c | 201 +++++ .../openeuler/security/openssl/kae_provider.c | 47 ++ .../org/openeuler/security/openssl/kae_util.c | 102 +++ .../org/openeuler/security/openssl/kae_util.h | 39 + jdk/test/java/net/URLPermission/policy.1 | 1 + jdk/test/java/net/URLPermission/policy.2 | 1 + jdk/test/java/net/URLPermission/policy.3 | 1 + .../bench/security/openssl/AESBenchmark.java | 108 +++ .../bench/security/openssl/BenchmarkBase.java | 100 +++ .../security/openssl/DigestBenchmark.java | 69 ++ .../bench/security/openssl/HMacBenchmark.java | 73 ++ .../security/openssl/RSACipherBenchmark.java | 107 +++ .../openssl/RSAKeyPairGeneratorBenchmark.java | 63 ++ .../sun/security/krb5/auto/BasicProc.java | 4 +- 39 files changed, 5066 insertions(+), 3 deletions(-) create mode 100644 jdk/make/mapfiles/libj2kae/mapfile-vers create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEAESCipher.java create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEMac.java create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSACipher.java create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAPaddingType.java create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEUtils.java create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_aes.c create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.c create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.h create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_log.h create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_mac.c create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/DigestBenchmark.java create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/RSACipherBenchmark.java create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index d754f1d6..ea43a7a0 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -845,6 +845,7 @@ JDK_MINOR_VERSION JDK_MAJOR_VERSION USER_RELEASE_SUFFIX ENABLE_JFR +ENABLE_KAE COMPRESS_JARS UNLIMITED_CRYPTO CACERTS_FILE @@ -1060,6 +1061,7 @@ enable_hotspot_test_in_build with_cacerts_file enable_unlimited_crypto enable_jfr +enable_kae with_milestone with_update_version with_user_release_suffix @@ -1847,6 +1849,7 @@ Optional Features: --enable-unlimited-crypto Enable unlimited crypto policy [disabled] --disable-jfr Disable Java Flight Recorder support [enabled] + --enable-kae Enable KAE support on aarch64 [disabled] --disable-debug-symbols disable generation of debug symbols [enabled] --disable-zip-debug-info disable zipping of debug-info files [enabled] @@ -19843,6 +19846,27 @@ fi $as_echo "$ENABLE_JFR" >&6; } + ############################################################################### + # + # Enable or disable KAE + # + # Check whether --enable-kae was given. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build KAE" >&5 +$as_echo_n "checking whether to build KAE... " >&6; } +if test "${enable_kae+set}" = set; then : + enableval=$enable_kae; enable_kae="${enableval}" +else + #default disable kae + enable_kae="no" +fi + + if test "x$enable_kae" = "xyes"; then + ENABLE_KAE=true + elif test "x$enable_kae" = "xno"; then + ENABLE_KAE=false + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENABLE_KAE" >&5 +$as_echo "$ENABLE_KAE" >&6; } # Source the version numbers . $AUTOCONF_DIR/version-numbers diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index e4eb2352..23db9275 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -461,6 +461,20 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS], fi AC_MSG_RESULT([$ENABLE_JFR]) AC_SUBST(ENABLE_JFR) + + ############################################################################### + # + # Enable or disable kae + # + AC_ARG_ENABLE(kae, [AS_HELP_STRING([--enable-kae], + [enable KAE @<:@enabled@:>@])],, + [enable_kae=no]) + if test "x$enable_kae" = "xyes"; then + ENABLE_KAE=true + else + ENABLE_KAE=false + fi + AC_SUBST(ENABLE_KAE) ]) ############################################################################### diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 506cf617..4c3a9f61 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -602,6 +602,7 @@ endif # Build setup ENABLE_JFR=@ENABLE_JFR@ +ENABLE_KAE=@ENABLE_KAE@ ENABLE_INTREE_EC=@ENABLE_INTREE_EC@ USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@ USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@ diff --git a/jdk/make/CompileJavaClasses.gmk b/jdk/make/CompileJavaClasses.gmk index 3ec63e87..b0ae8e97 100644 --- a/jdk/make/CompileJavaClasses.gmk +++ b/jdk/make/CompileJavaClasses.gmk @@ -284,6 +284,7 @@ endif # The security classes should not end up in the classes directory as that will prevent them # from working when running the exploded jdk image. Compile them separately to a different # directory from where the jars can be created. + SECURITY_PKGS := \ com/oracle/security/ucrypto \ com/sun/crypto/provider \ @@ -294,6 +295,9 @@ SECURITY_PKGS := \ sun/security/pkcs11 \ # +# KAE classes +KAE_PKG := org/openeuler/security/openssl + AIX_SRC_DIRS := ifeq ($(OPENJDK_TARGET_OS),aix) AIX_SRC_DIRS += $(JDK_TOPDIR)/src/aix/classes @@ -339,7 +343,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JDK,\ $(JDK_OUTPUTDIR)/gensrc_no_srczip \ $(CLOSED_SRC_DIRS),\ INCLUDES:=$(JDK_USER_DEFINED_FILTER),\ - EXCLUDES:=$(EXCLUDES) $(SECURITY_PKGS),\ + EXCLUDES:=$(EXCLUDES) $(SECURITY_PKGS) $(KAE_PKG),\ EXCLUDE_FILES:=$(EXFILES),\ BIN:=$(JDK_OUTPUTDIR)/classes,\ COPY:=$(COPY_PATTERNS),\ @@ -363,6 +367,26 @@ $(eval $(call SetupJavaCompilation,BUILD_SECURITY, \ $(BUILD_SECURITY): $(BUILD_JDK) + +########################################################################################## +ifeq ($(ENABLE_KAE), true) + ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) + $(eval $(call SetupJavaCompilation,BUILD_KAE, \ + SETUP := GENERATE_JDKBYTECODE, \ + SRC := $(JDK_TOPDIR)/src/share/classes \ + $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes \ + $(MACOSX_SRC_DIRS) \ + $(CLOSED_SRC_DIRS), \ + INCLUDES := $(KAE_PKG), \ + EXCLUDES := $(EXCLUDES), \ + EXCLUDE_FILES := $(EXFILES), \ + BIN := $(JDK_OUTPUTDIR)/classes_kae, \ + HEADERS := $(JDK_OUTPUTDIR)/gensrc_headers)) + + $(BUILD_KAE): $(BUILD_JDK) + endif +endif + ########################################################################################## $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin: @@ -410,7 +434,7 @@ $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin: ########################################################################################## -all: $(BUILD_JDK) $(BUILD_SECURITY) $(COPY_EXTRA) \ +all: $(BUILD_JDK) $(BUILD_SECURITY) $(BUILD_KAE) $(COPY_EXTRA) \ $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin \ $(BUILD_ACCESSBRIDGE_32) $(BUILD_ACCESSBRIDGE_64) \ $(BUILD_ACCESSBRIDGE_LEGACY) diff --git a/jdk/make/CreateJars.gmk b/jdk/make/CreateJars.gmk index 559a62b6..cb3f26b3 100644 --- a/jdk/make/CreateJars.gmk +++ b/jdk/make/CreateJars.gmk @@ -168,6 +168,7 @@ RT_JAR_EXCLUDES += \ META-INF/services/com.sun.tools.attach.spi.AttachProvider \ META-INF/services/com.sun.tools.xjc.Plugin \ META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor \ + org/openeuler/security \ org/relaxng/datatype \ sun/awt/HKSCS.class \ sun/awt/motif/X11GB2312.class \ diff --git a/jdk/make/CreateSecurityJars.gmk b/jdk/make/CreateSecurityJars.gmk index da9cc207..e991d994 100644 --- a/jdk/make/CreateSecurityJars.gmk +++ b/jdk/make/CreateSecurityJars.gmk @@ -371,6 +371,35 @@ ifeq ($(OPENJDK_TARGET_OS), solaris) endif endif +########################################################################################## + +ifeq ($(ENABLE_KAE), true) + ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) + KAE_JAR_DST := $(JDK_OUTPUTDIR)/lib/ext/kae_openssl.jar + KAE_JAR_UNSIGNED := $(JDK_OUTPUTDIR)/jce/unsigned/kae_openssl.jar + + $(eval $(call SetupArchive,BUILD_OPENSSL_JAR, , \ + SRCS := $(JDK_OUTPUTDIR)/classes_kae, \ + SUFFIXES := .class, \ + INCLUDES := org/openeuler/security/openssl, \ + JAR := $(KAE_JAR_UNSIGNED), \ + MANIFEST := $(JCE_MANIFEST), \ + SKIP_METAINF := true)) + $(KAE_JAR_UNSIGNED): $(JCE_MANIFEST) + ifndef OPENJDK + KAE_JAR_SRC := $(JDK_TOPDIR)/make/closed/tools/crypto/openssl/kae_openssl.jar + $(KAE_JAR_DST): $(KAE_JAR_SRC) + @$(ECHO) $(LOG_INFO) Copying prebuilt $(@F) + $(install-file) + else + $(KAE_JAR_DST): $(KAE_JAR_UNSIGNED) + $(install-file) + endif + + TARGETS += $(KAE_JAR_UNSIGNED) $(KAE_JAR_DST) + + endif +endif all: $(TARGETS) diff --git a/jdk/make/SignJars.gmk b/jdk/make/SignJars.gmk index 21647889..babd8684 100644 --- a/jdk/make/SignJars.gmk +++ b/jdk/make/SignJars.gmk @@ -99,6 +99,12 @@ JAR_LIST := \ ucrypto.jar \ # +ifeq ($(ENABLE_KAE), true) + ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) + JAR_LIST += kae_openssl.jar + endif +endif + UNSIGNED_JARS := $(wildcard $(addprefix $(JDK_OUTPUTDIR)/jce/unsigned/, $(JAR_LIST))) ifeq ($(UNSIGNED_JARS), ) diff --git a/jdk/make/lib/SecurityLibraries.gmk b/jdk/make/lib/SecurityLibraries.gmk index a8eeceb3..62226836 100644 --- a/jdk/make/lib/SecurityLibraries.gmk +++ b/jdk/make/lib/SecurityLibraries.gmk @@ -287,3 +287,28 @@ ifeq ($(OPENJDK_TARGET_OS), solaris) endif endif +########################################################################################## +ifeq ($(ENABLE_KAE), true) + ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) + $(eval $(call SetupNativeCompilation,BUILD_LIBJ2KAE, \ + LIBRARY := j2kae, \ + OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ + SRC := $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/org/openeuler/security/openssl, \ + LANG := C, \ + OPTIMIZATION := LOW, \ + EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/org/openeuler/security/openssl, \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libj2kae/mapfile-vers, \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ + $(call SET_SHARED_LIBRARY_ORIGIN), \ + LDFLAGS_SUFFIX_linux := $(LIBDL) -lssl -lcrypto, \ + LDFLAGS_SUFFIX_posix := $(LIBDL), \ + LDFLAGS_SUFFIX_solaris := -lc, \ + VERSIONINFO_RESOURCE := $(JDK_TOPDIR)/src/windows/resource/version.rc, \ + OBJECT_DIR := $(JDK_OUTPUTDIR)/objs/libj2kae, \ + DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES))) + + BUILD_LIBRARIES += $(BUILD_LIBJ2KAE) + endif +endif diff --git a/jdk/make/mapfiles/libj2kae/mapfile-vers b/jdk/make/mapfiles/libj2kae/mapfile-vers new file mode 100644 index 00000000..6ed331b2 --- /dev/null +++ b/jdk/make/mapfiles/libj2kae/mapfile-vers @@ -0,0 +1,57 @@ +# +# Copyright (c) 2020, Huawei Technologies Co., Ltd. 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. +# + +# Define public interface. + +SUNWprivate_1.1 { + global: + JNI_OnLoad; + Java_org_openeuler_security_openssl_KAEProvider_initOpenssl; + Java_org_openeuler_security_openssl_KAEDigest_nativeInit; + Java_org_openeuler_security_openssl_KAEDigest_nativeUpdate; + Java_org_openeuler_security_openssl_KAEDigest_nativeDigest; + Java_org_openeuler_security_openssl_KAEDigest_nativeClone; + Java_org_openeuler_security_openssl_KAEDigest_nativeFree; + Java_org_openeuler_security_openssl_KAEAESCipher_nativeInit; + Java_org_openeuler_security_openssl_KAEAESCipher_nativeUpdate; + Java_org_openeuler_security_openssl_KAEAESCipher_nativeFinal; + Java_org_openeuler_security_openssl_KAEAESCipher_nativeFree; + Java_org_openeuler_security_openssl_KAEMac_nativeInit; + Java_org_openeuler_security_openssl_KAEMac_nativeUpdate; + Java_org_openeuler_security_openssl_KAEMac_nativeFinal; + Java_org_openeuler_security_openssl_KAEMac_nativeFree; + Java_org_openeuler_security_openssl_KAERSAKeyPairGenerator_nativeGenerateKeyPair; + Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPrivateCrtKey; + Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPrivateKey; + Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPublicKey; + Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPrivateEncrypt; + Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPrivateDecrypt; + Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPublicEncrypt; + Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPublicDecrypt; + Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAEncryptOAEPPadding; + Java_org_openeuler_security_openssl_KAERSACipher_nativeRSADecryptOAEPPadding; + Java_org_openeuler_security_openssl_KAERSACipher_nativeFreeKey; + + local: + *; +}; diff --git a/jdk/make/profile-includes.txt b/jdk/make/profile-includes.txt index 68bb27e5..013c426c 100644 --- a/jdk/make/profile-includes.txt +++ b/jdk/make/profile-includes.txt @@ -195,6 +195,12 @@ PROFILE_1_JRE_LIB_FILES += \ security/trusted.libraries \ tzdb.dat +ifeq ($(ENABLE_KAE), true) + ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) + PROFILE_1_JRE_LIB_FILES += ext/kae_openssl.jar + endif +endif + ifeq ($(OPENJDK_TARGET_OS), windows) PROFILE_1_JRE_LIB_FILES += tzmappings else @@ -225,6 +231,12 @@ PROFILE_1_JRE_JAR_FILES := \ security/policy/limited/local_policy.jar \ security/policy/unlimited/local_policy.jar +ifeq ($(ENABLE_KAE), true) + ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) + PROFILE_1_JRE_JAR_FILES += ext/kae_openssl.jar + endif +endif + PROFILE_2_JRE_BIN_FILES := \ rmid$(EXE_SUFFIX) \ diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEAESCipher.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEAESCipher.java new file mode 100644 index 00000000..2dd5bf4a --- /dev/null +++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEAESCipher.java @@ -0,0 +1,725 @@ +/* + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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 org.openeuler.security.openssl; + +import sun.security.jca.JCAUtil; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.security.*; +import java.security.spec.*; +import java.util.Arrays; +import java.util.Locale; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/* + * Cipher wrapper class utilizing openssl APIs. This class currently supports + * - AES/ECB/NOPADDING + * - AES/ECB/PKCS5PADDING + * - AES/CBC/NOPADDING + * - AES/CBC/PKCS5PADDING + * - AES/CTR/NOPADDING + */ +abstract class KAEAESCipher extends CipherSpi { + + public static class Aes extends KAEAESCipher { + public Aes(Mode mode, Padding padding) { + super(mode, padding, -1); + } + + public static class Cbc extends Aes { + public Cbc(Padding padding) { + super(Mode.CBC, padding); + } + public static class NoPadding extends Cbc { + public NoPadding() { + super(Padding.NOPADDING); + } + } + public static class PKCS5Padding extends Cbc { + public PKCS5Padding() { + super(Padding.PKCS5PADDING); + } + } + } + public static class Ecb extends Aes { + public Ecb(Padding padding) { + super(Mode.ECB, padding); + } + public static class NoPadding extends Ecb { + public NoPadding() { + super(Padding.NOPADDING); + } + } + public static class PKCS5Padding extends Ecb { + public PKCS5Padding() { + super(Padding.PKCS5PADDING); + } + } + } + + public static class Ctr extends Aes { + public Ctr(Padding padding) { + super(Mode.CTR, padding); + } + public static class NoPadding extends Ctr { + public NoPadding() { + super(Padding.NOPADDING); + } + } + } + } + + public static class Aes_128 extends KAEAESCipher { + public Aes_128(Mode mode, Padding padding) { + super(mode, padding, 16); + } + public static class Cbc extends Aes_128 { + public Cbc(Padding padding) { + super(Mode.CBC, padding); + } + public static class NoPadding extends Cbc { + public NoPadding() { + super(Padding.NOPADDING); + } + } + public static class PKCS5Padding extends Cbc { + public PKCS5Padding() { + super(Padding.PKCS5PADDING); + } + } + } + public static class Ecb extends Aes_128 { + public Ecb(Padding padding) { + super(Mode.ECB, padding); + } + public static class NoPadding extends Ecb { + public NoPadding() { + super(Padding.NOPADDING); + } + } + public static class PKCS5Padding extends Ecb { + public PKCS5Padding() { + super(Padding.PKCS5PADDING); + } + } + } + + public static class Ctr extends Aes_128 { + public Ctr(Padding padding) { + super(Mode.CTR, padding); + } + public static class NoPadding extends Ctr { + public NoPadding() { + super(Padding.NOPADDING); + } + } + } + } + + public static class Aes_192 extends KAEAESCipher { + public Aes_192(Mode mode, Padding padding) { + super(mode, padding, 24); + } + public static class Cbc extends Aes_192 { + public Cbc(Padding padding) { + super(Mode.CBC, padding); + } + public static class NoPadding extends Cbc { + public NoPadding() { + super(Padding.NOPADDING); + } + } + public static class PKCS5Padding extends Cbc { + public PKCS5Padding() { + super(Padding.PKCS5PADDING); + } + } + } + public static class Ecb extends Aes_192 { + public Ecb(Padding padding) { + super(Mode.ECB, padding); + } + public static class NoPadding extends Ecb { + public NoPadding() { + super(Padding.NOPADDING); + } + } + public static class PKCS5Padding extends Ecb { + public PKCS5Padding() { + super(Padding.PKCS5PADDING); + } + } + } + + public static class Ctr extends Aes_192 { + public Ctr(Padding padding) { + super(Mode.CTR, padding); + } + public static class NoPadding extends Ctr { + public NoPadding() { + super(Padding.NOPADDING); + } + } + } + } + + public static class Aes_256 extends KAEAESCipher { + public Aes_256(Mode mode, Padding padding) { + super(mode, padding, 32); + } + public static class Cbc extends Aes_256 { + public Cbc(Padding padding) { + super(Mode.CBC, padding); + } + public static class NoPadding extends Cbc { + public NoPadding() { + super(Padding.NOPADDING); + } + } + public static class PKCS5Padding extends Cbc { + public PKCS5Padding() { + super(Padding.PKCS5PADDING); + } + } + } + public static class Ecb extends Aes_256 { + public Ecb(Padding padding) { + super(Mode.ECB, padding); + } + public static class NoPadding extends Ecb { + public NoPadding() { + super(Padding.NOPADDING); + } + } + public static class PKCS5Padding extends Ecb { + public PKCS5Padding() { + super(Padding.PKCS5PADDING); + } + } + } + + public static class Ctr extends Aes_256 { + public Ctr(Padding padding) { + super(Mode.CTR, padding); + } + public static class NoPadding extends Ctr { + public NoPadding() { + super(Padding.NOPADDING); + } + } + } + } + + enum Padding { + NOPADDING, + PKCS5PADDING + } + + enum Mode { + ECB, + CBC, + CTR, + } + + private final String keyAlgo = "AES"; + private final int blockSize = 16; + private Mode mode; + private Padding padding; + private int fixedKeySize; + + private CipherContextRef pCtx = null; + private byte[] keyValue; + protected byte[] iv; + private boolean initialized = false; + private boolean encrypt = false; + private int bytesBuffered = 0; + + private boolean calledUpdate; + private String cipherName; + + private static final PublicKey constructPublicKey(byte[] encodedKey, String encodedKeyAlgorithm) throws NoSuchAlgorithmException, InvalidKeyException { + PublicKey key; + try { + KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); + key = keyFactory.generatePublic(keySpec); + } catch (NoSuchAlgorithmException e) { + throw new NoSuchAlgorithmException("No provider found for " + encodedKeyAlgorithm + " KeyFactory"); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException("Cannot construct public key", e); + } + 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 e) { + throw new NoSuchAlgorithmException("No provider found for " + encodedKeyAlgorithm + " KeyFactory"); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException("Cannot construct private key", e); + } + return key; + } + + private static final SecretKey constructSecretKey(byte[] encodedKey, String encodedKeyAlgorithm) { + return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); + } + + static final Key constructKey(int keyType, byte[] encodedKey, + String encodedKeyAlgorithm) throws NoSuchAlgorithmException, InvalidKeyException { + Key res = null; + switch (keyType) { + case Cipher.SECRET_KEY: + res = constructSecretKey(encodedKey, encodedKeyAlgorithm); + break; + case Cipher.PRIVATE_KEY: + res = constructPrivateKey(encodedKey, encodedKeyAlgorithm); + break; + case Cipher.PUBLIC_KEY: + res = constructPublicKey(encodedKey, encodedKeyAlgorithm); + break; + default: + throw new InvalidKeyException("Unknown keytype " + keyType); + } + return res; + } + + KAEAESCipher(Mode mode, Padding padding, int fixedKeySize) { + this.mode = mode; + this.padding = padding; + this.fixedKeySize = fixedKeySize; + } + + private static class CipherContextRef extends PhantomReference<KAEAESCipher> implements Comparable<CipherContextRef> { + + private static ReferenceQueue<KAEAESCipher> refQueue = new ReferenceQueue<>(); + private static Set<CipherContextRef> refList = new ConcurrentSkipListSet<>(); + private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); + + final long ctxAddress; + + private static void drainRefQueueBounded() { + while (true) { + CipherContextRef next = (CipherContextRef) refQueue.poll(); + if (next == null) { + break; + } + next.dispose(true); + } + } + + CipherContextRef(KAEAESCipher kaeCipher, long ctxAddress) { + super(kaeCipher, refQueue); + this.ctxAddress = ctxAddress; + if (!disableKaeDispose) { + refList.add(this); + drainRefQueueBounded(); + } + } + + @Override + public int compareTo(CipherContextRef o) { + if (this.ctxAddress == o.ctxAddress) { + return 0; + } else { + return (this.ctxAddress < o.ctxAddress) ? -1 : 1; + } + } + + void dispose(boolean needFree) { + if (!disableKaeDispose) { + refList.remove(this); + try { + if (needFree) { + nativeFree(ctxAddress); + } + } finally { + this.clear(); + } + } else { + nativeFree(ctxAddress); + } + } + } + + + @Override + protected void engineSetMode(String modeStr) throws NoSuchAlgorithmException { + if (modeStr == null) { + throw new NoSuchAlgorithmException("null mode"); + } + + if (modeStr.equalsIgnoreCase("ECB")) { + mode = Mode.ECB; + } else if (modeStr.equalsIgnoreCase("CBC")) { + mode = Mode.CBC; + } else if (modeStr.equalsIgnoreCase("CTR")) { + mode = Mode.CTR; + } else { + throw new NoSuchAlgorithmException("Unsupported mode " + mode); + } + + } + + @Override + protected void engineSetPadding(String paddingStr) throws NoSuchPaddingException { + if (paddingStr == null) { + throw new NoSuchPaddingException("null padding"); + } + + if (paddingStr.equalsIgnoreCase("NOPADDING")) { + this.padding = Padding.NOPADDING; + } else if(paddingStr.equalsIgnoreCase("PKCS5PADDING")) { + if (mode == Mode.CTR) { + throw new NoSuchPaddingException("PKCS#5 padding not supported with CTR mode"); + } + this.padding = Padding.PKCS5PADDING; + } else { + throw new NoSuchPaddingException("Unsupported padding "+padding); + } + } + + + @Override + protected int engineGetBlockSize() { + return blockSize; + } + + @Override + protected int engineGetOutputSize(int inputLen) { + return getOutputSizeByOperation(inputLen, true); + } + + @Override + protected byte[] engineGetIV() { + return iv == null ? null : iv.clone(); + } + + @Override + protected AlgorithmParameters engineGetParameters() { + if (iv == null) { + return null; + } + IvParameterSpec ivSpec = new IvParameterSpec(iv.clone()); + try { + AlgorithmParameters params = AlgorithmParameters.getInstance(keyAlgo); + params.init(ivSpec); + return params; + } catch (GeneralSecurityException e) { + throw new RuntimeException("Could not encode parameters", e); + } + } + + @Override + protected 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); + } + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + AlgorithmParameterSpec ivSpec = null; + if (params != null) { + try { + ivSpec = params.getParameterSpec(IvParameterSpec.class); + } catch (InvalidParameterSpecException e) { + throw new InvalidAlgorithmParameterException("Could not decode IV", e); + } + } + engineInit(opmode, key, ivSpec, random); + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + checkKey(key); + boolean doEncrypt = (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE); + + byte[] ivBytes = null; + + if (params != null) { + if (!(params instanceof IvParameterSpec)) { + throw new InvalidKeyException("IvParameterSpec required. Received: " + params.getClass().getName()); + } else { + ivBytes = ((IvParameterSpec) params).getIV(); + if (ivBytes.length != blockSize) { + throw new InvalidAlgorithmParameterException("Wrong IV length: must be " + blockSize + + " bytes long. Received length:" + ivBytes.length); + } + } + } + if (mode == Mode.ECB) { + if (params != null) { + throw new InvalidAlgorithmParameterException("No Parameters for ECB mode"); + } + } else if (ivBytes == null) { + if (doEncrypt) { + ivBytes = new byte[blockSize]; + if (random == null) { + random = JCAUtil.getSecureRandom(); + } + random.nextBytes(ivBytes); + } else { + throw new InvalidAlgorithmParameterException("Parameters required for decryption"); + } + } + implInit(doEncrypt, key.getEncoded(), ivBytes); + } + + private void implInit(boolean encrypt, byte[] keyVal, byte[] ivVal) { + + reset(true); + this.encrypt = encrypt; + this.keyValue = keyVal; + this.iv = ivVal; + this.cipherName = "aes-" + (keyVal.length * 8) + "-" + mode.toString().toLowerCase(Locale.US); + + // OpenSSL only supports PKCS5 Padding + long pCtxVal; + try { + pCtxVal = nativeInit(cipherName, encrypt, keyValue, iv, padding == Padding.PKCS5PADDING); + } catch (RuntimeException e) { + throw new ProviderException("Invoke nativeInit failed for " + cipherName, e); + } + + initialized = (pCtxVal != 0L); + if (initialized) { + pCtx = new CipherContextRef(this, pCtxVal); + } else { + throw new NullPointerException("pCtxVal == 0"); + } + calledUpdate = false; + } + + final int checkKey(Key key) throws InvalidKeyException { + if (key == null || key.getEncoded() == null) { + throw new InvalidKeyException("Key cannot be null"); + } else { + if (!keyAlgo.equalsIgnoreCase(key.getAlgorithm())) { + throw new InvalidKeyException("Key algorithm must be " + keyAlgo); + } + int keyLen = key.getEncoded().length; + if (fixedKeySize == -1) { + if (keyLen != 16 && keyLen != 24 & keyLen != 32) { + throw new InvalidKeyException("Key size is not valid. Got key length of: " + keyLen); + } + } else { + if (keyLen != fixedKeySize) { + throw new InvalidKeyException("Only " + fixedKeySize + "-byte keys are accepted. Got: " + keyLen); + } + } + return keyLen; + } + } + + @Override + protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { + byte[] out = new byte[getOutputSizeByOperation(inputLen, false)]; + int n = implUpdate(input, inputOffset, inputLen, out, 0); + if (n == 0) { + return new byte[0]; + } else if (out.length != n) { + out = Arrays.copyOf(out, n); + } + return out; + } + + @Override + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, + int outputOffset) throws ShortBufferException { + int min = getOutputSizeByOperation(inputLen, false); + if (output.length - outputOffset < min) { + throw new ShortBufferException("min" + min + "-byte buffer needed"); + } + return implUpdate(input, inputOffset, inputLen, output, outputOffset); + } + + private int implUpdate(byte[] in, int inOfs, int inLen, byte[] output, int outOfs) { + ensureInitialized(); + if (inLen <= 0) { + return 0; + } + int k; + try { + k = nativeUpdate(pCtx.ctxAddress, in, inOfs, inLen, output, outOfs); + } catch (ArrayIndexOutOfBoundsException e) { + reset(true); + throw new ProviderException("Invoke nativeUpdate failed for " + cipherName, e); + } + bytesBuffered += (inLen - k); + + calledUpdate = true; + return k; + } + + protected int getOutputSizeByOperation(int inLen, boolean isDoFinal) { + if (inLen <= 0) { + inLen = 0; + } + if (!isDoFinal && inLen == 0) { + return 0; + } + if (padding == Padding.NOPADDING) { + return inLen + bytesBuffered; + } else { + int len = inLen + bytesBuffered; + + /* + * The amount of data written may be anything from zero bytes to (inl + cipher_block_size - 1) for encrypt. + * Refer to {@link https://www.openssl.org/docs/man1.1.0/man3/EVP_CipherUpdate.html} for details. + */ + len += (len % blockSize != 0 || encrypt) ? blockSize : 0; + return len - (len % blockSize); + } + } + + @Override + protected byte[] engineDoFinal(byte[] input, int inputOffset, + int inputLen) throws IllegalBlockSizeException, BadPaddingException { + byte[] out = new byte[getOutputSizeByOperation(inputLen, true)]; + try { + int outLen = engineDoFinal(input, inputOffset, inputLen, out, 0); + if (out.length != outLen) { + out = Arrays.copyOf(out, outLen); + } + return out; + } catch (ShortBufferException e) { + throw new ProviderException(e); + } + } + + @Override + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, + int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + int outLen = 0; + int min = getOutputSizeByOperation(inputLen, true); + if (output.length - outputOffset < min) { + throw new ShortBufferException("min" + min + "-byte buffer needed"); + } + if (inputLen > 0) { + outLen = implUpdate(input, inputOffset, inputLen, output, outputOffset); + outputOffset += outLen; + } + outLen += implDoFinal(output, outputOffset); + return outLen; + } + + @Override + protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { + byte[] res = 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"); + } + res = engineDoFinal(encodedKey, 0, encodedKey.length); + } catch (BadPaddingException e) { + // Should never happen + } + return res; + } + + @Override + protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, + int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { + byte[] encodedKey; + try { + encodedKey = engineDoFinal(wrappedKey, 0, wrappedKey.length); + } catch (IllegalBlockSizeException | BadPaddingException e) { + throw (InvalidKeyException) (new InvalidKeyException()).initCause(e); + } + return constructKey(wrappedKeyType, encodedKey, wrappedKeyAlgorithm); + } + + private int implDoFinal(byte[] out, int outOfs) { + + if (!encrypt && !calledUpdate) { + return 0; + } + ensureInitialized(); + + int outLen; + try { + outLen = nativeFinal(pCtx.ctxAddress, out, outOfs); + } catch (ArrayIndexOutOfBoundsException | BadPaddingException e) { + throw new ProviderException("Invoke nativeFinal failed for " + cipherName, e); + } finally { + reset(true); + } + + return outLen; + } + + protected void reset(boolean doCancel) { + initialized = false; + bytesBuffered = 0; + calledUpdate = false; + if (pCtx != null) { + pCtx.dispose(doCancel); + pCtx = null; + } + } + + protected native static long nativeInit(String cipherType, boolean encrypt, byte[] key, byte[] iv, boolean padding) throws RuntimeException; + + protected native static int nativeUpdate(long pContext, byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) throws ArrayIndexOutOfBoundsException; + + protected native static int nativeFinal(long pContext, byte[] out, + int outOfs) throws ArrayIndexOutOfBoundsException, BadPaddingException; + + protected native static void nativeFree(long pContext); + + protected void ensureInitialized() { + if (!initialized) { + reset(true); + long pCtxVal = nativeInit(cipherName, encrypt, keyValue, iv, padding == Padding.PKCS5PADDING); + initialized = (pCtxVal != 0L); + if (initialized) { + pCtx = new CipherContextRef(this, pCtxVal); + } else { + throw new RuntimeException("Cannot initialize Cipher"); + } + } + } +} + diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java new file mode 100644 index 00000000..bb5c8681 --- /dev/null +++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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 org.openeuler.security.openssl; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.security.DigestException; +import java.security.MessageDigestSpi; +import java.security.ProviderException; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +/** + * KAE Digest + */ +abstract class KAEDigest extends MessageDigestSpi implements Cloneable { + + public static final class MD5 extends KAEDigest { + private static final long initContext = nativeInit("md5"); + + public MD5() { + super("md5", 16, initContext); + } + } + + public static final class SM3 extends KAEDigest { + private static final long initContext = nativeInit("sm3"); + + public SM3() { + super("sm3", 32, initContext); + } + } + + public static final class SHA256 extends KAEDigest { + private static final long initContext = nativeInit("sha256"); + + public SHA256() { + super("sha256", 32, initContext); + } + } + + public static final class SHA384 extends KAEDigest { + private static final long initContext = nativeInit("sha384"); + + public SHA384() { + super("sha384", 48, initContext); + } + } + + private final int digestLength; + + private final String algorithm; + private final long initContext; + + // field for ensuring native memory is freed + private DigestContextRef contextRef = null; + + KAEDigest(String algorithm, int digestLength, long initContext) { + this.algorithm = algorithm; + this.digestLength = digestLength; + this.initContext = initContext; + } + + private static class DigestContextRef extends PhantomReference<KAEDigest> + implements Comparable<DigestContextRef> { + + private static ReferenceQueue<KAEDigest> referenceQueue = new ReferenceQueue<>(); + private static Set<DigestContextRef> referenceList = new ConcurrentSkipListSet<>(); + private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); + + private final long ctxAddress; + + DigestContextRef(KAEDigest kaeDigest, long ctxAddress) { + super(kaeDigest, referenceQueue); + this.ctxAddress = ctxAddress; + if (!disableKaeDispose) { + referenceList.add(this); + drainRefQueueBounded(); + } + } + + @Override + public int compareTo(DigestContextRef other) { + if (this.ctxAddress == other.ctxAddress) { + return 0; + } else { + return (this.ctxAddress < other.ctxAddress) ? -1 : 1; + } + } + + private static void drainRefQueueBounded() { + while (true) { + DigestContextRef next = (DigestContextRef) referenceQueue.poll(); + if (next == null) { + break; + } + next.dispose(); + } + } + + void dispose() { + if (!disableKaeDispose) { + referenceList.remove(this); + try { + nativeFree(ctxAddress); + } finally { + this.clear(); + } + } else { + nativeFree(ctxAddress); + } + } + } + + // single byte update. See JCA doc. + @Override + protected synchronized void engineUpdate(byte input) { + byte[] oneByte = new byte[]{input}; + engineUpdate(oneByte, 0, 1); + } + + + // array update. See JCA doc. + @Override + protected synchronized void engineUpdate(byte[] input, int offset, int len) { + if (len == 0 || input == null) { + return; + } + if ((offset < 0) || (len < 0) || (offset > input.length - len)) { + throw new ArrayIndexOutOfBoundsException(); + } + if (contextRef == null) { + contextRef = createDigestContext(this); + } + + try { + nativeUpdate(contextRef.ctxAddress, input, offset, len); + } catch (Exception e) { + engineReset(); + throw new ProviderException("nativeUpdate failed for " + algorithm, e); + } + } + + + // return the digest. See JCA doc. + @Override + protected synchronized byte[] engineDigest() { + final byte[] output = new byte[digestLength]; + try { + engineDigest(output, 0, digestLength); + } catch (Exception e) { + throw new ProviderException("Internal error", e); + } + return output; + } + + // return the digest in the specified array. See JCA doc. + @Override + protected int engineDigest(byte[] output, int offset, int len) throws DigestException { + if (output == null) { + return 0; + } + if (len < digestLength) { + throw new DigestException("Length must be at least " + + digestLength + " for " + algorithm + " digests"); + } + if ((offset < 0) || (len < 0) || (offset > output.length - len)) { + throw new DigestException("Buffer too short to store digest"); + } + if (contextRef == null) { + contextRef = createDigestContext(this); + } + try { + nativeDigest(contextRef.ctxAddress, output, offset, digestLength); + } catch (Exception e) { + throw new ProviderException("Invoke nativeDigest failed for " + algorithm, e); + } finally { + engineReset(); + } + return digestLength; + } + + // reset this object. See JCA doc. + @Override + protected synchronized void engineReset() { + if (contextRef != null) { + contextRef.dispose(); + contextRef = null; + } + } + + // return digest length. See JCA doc. + @Override + protected int engineGetDigestLength() { + return digestLength; + } + + @Override + public synchronized Object clone() throws CloneNotSupportedException { + KAEDigest kaeDigest = (KAEDigest) super.clone(); + if (kaeDigest.contextRef != null && kaeDigest.contextRef.ctxAddress != 0) { + long addr; + try { + addr = nativeClone(kaeDigest.contextRef.ctxAddress); + } catch (Exception e) { + throw new ProviderException("Invoke nativeClone failed for " + algorithm, e); + } + kaeDigest.contextRef = new DigestContextRef(kaeDigest, addr); + } + return kaeDigest; + } + + private DigestContextRef createDigestContext(KAEDigest kaeDigest) { + long addr; + try { + addr = nativeClone(initContext); + } catch (Exception e) { + throw new ProviderException("Invoke nativeInit failed for " + algorithm, e); + } + if (addr == 0) { + throw new RuntimeException("Cannot initialize EVP_MD_CTX for " + algorithm); + } + return new DigestContextRef(kaeDigest, addr); + } + + // return pointer to the context + protected native static long nativeInit(String algorithmName); + + // update the input byte + protected native static void nativeUpdate(long ctxAddress, byte[] input, int offset, int inLen); + + // digest and store the digest message to output + protected native static int nativeDigest(long ctxAddress, byte[] output, int offset, int len); + + // digest clone + protected static native long nativeClone(long ctxAddress); + + // free the specified context + protected native static void nativeFree(long ctxAddress); +} diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEMac.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEMac.java new file mode 100644 index 00000000..54c5cbdf --- /dev/null +++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEMac.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +package org.openeuler.security.openssl; + +import javax.crypto.MacSpi; +import javax.crypto.SecretKey; +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.nio.ByteBuffer; +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +public abstract class KAEMac extends MacSpi implements Cloneable { + + private final String algorithm; + + /** + * The secret key used in this keyed MAC. + */ + private byte[] keyBytes; + + /** + * Holds the output size of the message digest. + */ + private final int digestSize; + + /** + * Holds a dummy buffer for writing single bytes to the digest. + */ + private final byte[] singleByte = new byte[1]; + + private HmacContextRef contextRef = null; + + private KAEMac(String algo, int size) { + this.algorithm = algo; + this.digestSize = size; + } + + private static class HmacContextRef extends PhantomReference<KAEMac> + implements Comparable<HmacContextRef> { + + private static ReferenceQueue<KAEMac> referenceQueue = new ReferenceQueue<>(); + private static Set<HmacContextRef> referenceList = new ConcurrentSkipListSet<>(); + private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); + + private final long address; + + HmacContextRef(KAEMac kaeMac, long address) { + super(kaeMac, referenceQueue); + this.address = address; + if (!disableKaeDispose) { + referenceList.add(this); + drainRefQueueBounded(); + } + } + + @Override + public int compareTo(HmacContextRef other) { + if (this.address == other.address) { + return 0; + } else { + return (this.address < other.address) ? -1 : 1; + } + } + + private static void drainRefQueueBounded() { + while (true) { + HmacContextRef next = (HmacContextRef) referenceQueue.poll(); + if (next == null) break; + next.dispose(true); + } + } + + void dispose(boolean needFree) { + if (!disableKaeDispose) { + referenceList.remove(this); + try { + if (needFree) { + nativeFree(address); + } + } finally { + this.clear(); + } + } else { + nativeFree(address); + } + } + } + + private void checkAndInitHmacContext () { + try { + if (contextRef == null) { + long ctxAddr = nativeInit(keyBytes, keyBytes.length, algorithm); + contextRef = new HmacContextRef(this, ctxAddr); + } + } + catch (Exception e) { + throw new ProviderException(e.getMessage()) ; + } + } + + @Override + protected int engineGetMacLength() { + return digestSize; + } + + @Override + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException { + if (!(key instanceof SecretKey)) { + throw new InvalidKeyException("key must be a SecretKey"); + } + if (params != null) { + throw new InvalidAlgorithmParameterException("unknown parameter type"); + } + keyBytes = key.getEncoded(); + if (keyBytes == null) { + throw new InvalidKeyException("key cannot be encoded"); + } + } + + @Override + protected void engineUpdate(byte input) { + singleByte[0] = input; + engineUpdate(singleByte, 0, 1); + } + + @Override + protected void engineUpdate(byte[] input, int offset, int len) { + checkAndInitHmacContext(); + try { + nativeUpdate(contextRef.address, input, offset, len); + } + catch (Exception e) { + engineReset(); + throw new ProviderException(e.getMessage()); + } + } + + + @Override + protected byte[] engineDoFinal() { + final byte[] output = new byte[digestSize]; + checkAndInitHmacContext(); + final byte[] res; + try { + int bytesWritten = nativeFinal(contextRef.address, output, 0, digestSize); + res = new byte[bytesWritten]; + System.arraycopy(output, 0, res, 0, bytesWritten); + } + catch (Exception e) { + engineReset(); + throw new ProviderException(e.getMessage()); + } + return res; + } + + @Override + protected void engineReset() { + if (contextRef != null) { + contextRef.dispose(true); + contextRef = null; + } + } + + public static final class HmacMD5 extends KAEMac { + public HmacMD5() { + super("MD5", 16); + } + } + public static final class HmacSHA1 extends KAEMac { + public HmacSHA1() { + super("SHA1", 20); + } + } + public static final class HmacSHA224 extends KAEMac { + public HmacSHA224() throws NoSuchAlgorithmException { + super("SHA224", 28); + } + } + public static final class HmacSHA256 extends KAEMac { + public HmacSHA256() throws NoSuchAlgorithmException { + super("SHA256", 32); + } + } + public static final class HmacSHA384 extends KAEMac { + public HmacSHA384() throws NoSuchAlgorithmException { + super("SHA384", 48); + } + } + public static final class HmacSHA512 extends KAEMac { + public HmacSHA512() throws NoSuchAlgorithmException { + super("SHA512", 64); + } + } + + protected static native long nativeInit(byte[] key, int len, String algo); + + protected static native void nativeUpdate(long ctxAddr, byte[] input, int inOffset, int inLen); + + protected static native int nativeFinal(long ctxAddr, byte[] output, int outOffset, int inLen); + + protected static native void nativeFree(long ctxAddr); +} diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java new file mode 100644 index 00000000..fb84b768 --- /dev/null +++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +package org.openeuler.security.openssl; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Date; +import java.security.Provider; + +/** + * KAE Provider + */ +public class KAEProvider extends Provider { + private static Throwable excp; + private static boolean needLog = true; + + static { + Throwable status = null; + try { + System.loadLibrary("j2kae"); + initOpenssl(); + } catch (UnsatisfiedLinkError t) { + status = t; + } catch (RuntimeException e) { + status = e; + } + excp = status; + } + + private void logStart(Throwable excp) { + File file = new File(System.getProperty("user.dir"), "kae.log"); + Path fpath = file.toPath(); + if (!Files.exists(fpath)) { + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + try (BufferedWriter writer = Files.newBufferedWriter(fpath, StandardOpenOption.APPEND)) { + if (excp != null) { + writer.write(excp.getMessage()); + } else { + writer.write("KAE Engine was found"); + } + writer.write(" " + new Date()); + writer.newLine(); + } catch (IOException e) { + e.initCause(excp).printStackTrace(); + } + KAEProvider.excp = null; // Exception already logged, clean it. + } + + private void putCipherAES() { + final String blockModes = "ECB|CBC|CTR"; + final String blockPads = "NOPADDING|PKCS5PADDING"; + + put("Cipher.AES SupportedModes", blockModes); + put("Cipher.AES SupportedPaddings", blockPads); + put("Cipher.AES", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ecb$PKCS5Padding"); + + put("Cipher.AES/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Cbc$PKCS5Padding"); + put("Cipher.AES/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Cbc$NoPadding"); + put("Alg.Alias.Cipher.AES/CBC/PKCS7Padding", "AES/CBC/PKCS5Padding"); + put("Cipher.AES/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ecb$NoPadding"); + put("Cipher.AES/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ecb$PKCS5Padding"); + put("Alg.Alias.Cipher.AES/ECB/PKCS7Padding", "AES/ECB/PKCS5Padding"); + put("Cipher.AES/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ctr$NoPadding"); + + put("Cipher.AES_128/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Cbc$PKCS5Padding"); + put("Cipher.AES_128/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Cbc$NoPadding"); + put("Alg.Alias.Cipher.AES_128/CBC/PKCS7Padding", "AES_128/CBC/PKCS5Padding"); + put("Cipher.AES_128/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Ecb$NoPadding"); + put("Cipher.AES_128/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Ecb$PKCS5Padding"); + put("Alg.Alias.Cipher.AES_128/ECB/PKCS7Padding", "AES_128/ECB/PKCS5Padding"); + put("Cipher.AES_128/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Ctr$NoPadding"); + + put("Cipher.AES_192/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Cbc$PKCS5Padding"); + put("Cipher.AES_192/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Cbc$NoPadding"); + put("Alg.Alias.Cipher.AES_192/CBC/PKCS7Padding", "AES_192/CBC/PKCS5Padding"); + put("Cipher.AES_192/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Ecb$NoPadding"); + put("Cipher.AES_192/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Ecb$PKCS5Padding"); + put("Alg.Alias.Cipher.AES_192/ECB/PKCS7Padding", "AES_192/ECB/PKCS5Padding"); + put("Cipher.AES_192/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Ctr$NoPadding"); + + put("Cipher.AES_256/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Cbc$PKCS5Padding"); + put("Cipher.AES_256/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Cbc$NoPadding"); + put("Alg.Alias.Cipher.AES_256/CBC/PKCS7Padding", "AES_256/CBC/PKCS5Padding"); + put("Cipher.AES_256/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Ecb$NoPadding"); + put("Cipher.AES_256/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Ecb$PKCS5Padding"); + put("Alg.Alias.Cipher.AES_256/ECB/PKCS7Padding", "AES_256/ECB/PKCS5Padding"); + put("Cipher.AES_256/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Ctr$NoPadding"); + } + + private void putMessageDigest() { + put("MessageDigest.MD5", "org.openeuler.security.openssl.KAEDigest$MD5"); + put("MessageDigest.SHA-256", "org.openeuler.security.openssl.KAEDigest$SHA256"); + put("MessageDigest.SHA-384", "org.openeuler.security.openssl.KAEDigest$SHA384"); + } + + private void putCipherRSA() { + // rsa + put("KeyPairGenerator.RSA", "org.openeuler.security.openssl.KAERSAKeyPairGenerator$Legacy"); + put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1", "RSA"); + put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1", "RSA"); + + put("KeyPairGenerator.RSASSA-PSS", "org.openeuler.security.openssl.KAERSAKeyPairGenerator$PSS"); + put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.10", "RSASSA-PSS"); + put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); + + put("Cipher.RSA", "org.openeuler.security.openssl.KAERSACipher"); + put("Cipher.RSA SupportedModes", "ECB"); + put("Cipher.RSA SupportedPaddings", + "NOPADDING|PKCS1PADDING|OAEPPADDING" + + "|OAEPWITHMD5ANDMGF1PADDING" + + "|OAEPWITHSHA1ANDMGF1PADDING" + + "|OAEPWITHSHA-1ANDMGF1PADDING" + + "|OAEPWITHSHA-224ANDMGF1PADDING" + + "|OAEPWITHSHA-256ANDMGF1PADDING" + + "|OAEPWITHSHA-384ANDMGF1PADDING" + + "|OAEPWITHSHA-512ANDMGF1PADDING" + + "|OAEPWITHSHA-512/224ANDMGF1PADDING" + + "|OAEPWITHSHA-512/256ANDMGF1PADDING"); + put("Cipher.RSA SupportedKeyClasses", + "java.security.interfaces.RSAPublicKey" + + "|java.security.interfaces.RSAPrivateKey"); + } + + private void putMAC() { + put("MAC.HmacMD5", "org.openeuler.security.openssl.KAEMac$HmacMD5"); + put("MAC.HmacSHA1", "org.openeuler.security.openssl.KAEMac$HmacSHA1"); + put("MAC.HmacSHA224", "org.openeuler.security.openssl.KAEMac$HmacSHA224"); + put("MAC.HmacSHA256", "org.openeuler.security.openssl.KAEMac$HmacSHA256"); + put("MAC.HmacSHA384", "org.openeuler.security.openssl.KAEMac$HmacSHA384"); + put("MAC.HmacSHA512", "org.openeuler.security.openssl.KAEMac$HmacSHA512"); + } + + public KAEProvider() { + super("KAEProvider", 1.8d, "KAE provider"); + if (needLog) { + logStart(excp); + needLog = false; // Log only once + } + putMessageDigest(); + putCipherAES(); + putMAC(); + putCipherRSA(); + } + + // init openssl + static native void initOpenssl() throws RuntimeException; +} diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSACipher.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSACipher.java new file mode 100644 index 00000000..a7bc172a --- /dev/null +++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSACipher.java @@ -0,0 +1,796 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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 org.openeuler.security.openssl; + +import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; +import sun.security.jca.Providers; +import sun.security.rsa.RSACore; +import sun.security.rsa.RSAKeyFactory; +import sun.security.rsa.RSAPadding; +import sun.security.util.KeyUtil; + +import javax.crypto.*; +import javax.crypto.spec.OAEPParameterSpec; +import javax.crypto.spec.PSource; +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.security.*; +import java.security.interfaces.RSAKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.MGF1ParameterSpec; +import java.util.Arrays; +import java.util.Locale; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + + +/** + * RSA cipher implementation. Supports RSA en/decryption and signing/verifying + * using both PKCS#1 v1.5 and OAEP (v2.2) paddings and without padding (raw RSA). + * Note that raw RSA is supported mostly for completeness and should only be + * used in rare cases. + * <p> + * Objects should be instantiated by calling Cipher.getInstance() using the + * following algorithm names: + * . "RSA/ECB/PKCS1Padding" (or "RSA") for PKCS#1 v1.5 padding. + * . "RSA/ECB/OAEPwith<hash>andMGF1Padding" (or "RSA/ECB/OAEPPadding") for + * PKCS#1 v2.2 padding. + * . "RSA/ECB/NoPadding" for rsa RSA. + * <p> + * We only do one RSA operation per doFinal() call. If the application passes + * more data via calls to update() or doFinal(), we throw an + * IllegalBlockSizeException when doFinal() is called (see JCE API spec). + * Bulk encryption using RSA does not make sense and is not standardized. + * <p> + * Note: RSA keys should be at least 512 bits long + */ +public final class KAERSACipher extends CipherSpi { + // constant for an empty byte array + private final static byte[] B0 = new byte[0]; + + // mode constant for public key encryption + private final static int MODE_ENCRYPT = 1; + + // mode constant for private key decryption + private final static int MODE_DECRYPT = 2; + + // mode constant for private key encryption (signing) + private final static int MODE_SIGN = 3; + + // mode constant for public key decryption (verifying) + private final static int MODE_VERIFY = 4; + + // current mode, one of MODE_* above. Set when init() is called + private int mode; + + // active padding type, one of PAD_* above. Set by setPadding() + private KAERSAPaddingType paddingType; + + // padding object + private RSAPadding padding; + + // cipher parameter for OAEP padding and TLS RSA premaster secret + private AlgorithmParameterSpec spec = null; + + // buffer for the data + private byte[] buffer; + // offset into the buffer (number of bytes buffered) + private int bufOfs; + + // size of the output + private int outputSize; + + // hash algorithm for OAEP + private String oaepHashAlgorithm = "SHA-1"; + + // the source of randomness + private SecureRandom random; + + private RSAKey rsaKey; + + // rsa key holder + private KAERSAKeyHolder rsaKeyHolder; + + + public KAERSACipher() { + paddingType = KAERSAPaddingType.PKCS1Padding; + } + + // modes do not make sense for RSA, but allow ECB + // see JCE spec + @Override + protected void engineSetMode(String mode) throws NoSuchAlgorithmException { + if (!mode.equalsIgnoreCase("ECB")) { + throw new NoSuchAlgorithmException("Unsupported mode " + mode); + } + } + + // set the padding type + // see JCE spec + @Override + protected void engineSetPadding(String paddingName) + throws NoSuchPaddingException { + if (KAERSAPaddingType.NoPadding.getName().equalsIgnoreCase(paddingName)) { + paddingType = KAERSAPaddingType.NoPadding; + } else if (KAERSAPaddingType.PKCS1Padding.getName().equalsIgnoreCase(paddingName)) { + paddingType = KAERSAPaddingType.PKCS1Padding; + } else { + String lowerPadding = paddingName.toLowerCase(Locale.ENGLISH); + if ("oaeppadding".equals(lowerPadding)) { + paddingType = KAERSAPaddingType.OAEP; + } else if (lowerPadding.startsWith("oaepwith") && + lowerPadding.endsWith("andmgf1padding")) { + paddingType = KAERSAPaddingType.OAEP; + // "oaepwith" length is 8 + // "andmgf1padding" length is 14 + oaepHashAlgorithm = + paddingName.substring(8, paddingName.length() - 14); + // check if MessageDigest appears to be available + // avoid getInstance() call here + if (Providers.getProviderList().getService + ("MessageDigest", oaepHashAlgorithm) == null) { + throw new NoSuchPaddingException + ("MessageDigest not available for " + paddingName); + } + } else { + throw new NoSuchPaddingException + ("Padding " + paddingName + " not supported"); + } + } + } + + // return 0 as block size, we are not a block cipher + // see JCE spec + @Override + protected int engineGetBlockSize() { + return 0; + } + + // return the output size + // see JCE spec + @Override + protected int engineGetOutputSize(int inputLen) { + return outputSize; + } + + // no iv, return null + // see JCE spec + @Override + protected byte[] engineGetIV() { + return null; + } + + // see JCE spec + @Override + protected AlgorithmParameters engineGetParameters() { + if (spec != null && spec instanceof OAEPParameterSpec) { + try { + AlgorithmParameters params = + AlgorithmParameters.getInstance("OAEP"); + params.init(spec); + return params; + } catch (NoSuchAlgorithmException nsae) { + // should never happen + throw new RuntimeException("Cannot find OAEP " + + " AlgorithmParameters implementation in SunJCE provider"); + } catch (InvalidParameterSpecException ipse) { + // should never happen + throw new RuntimeException("OAEPParameterSpec not supported"); + } + } else { + return null; + } + } + + // see JCE spec + @Override + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException { + try { + init(opmode, key, random, null); + } catch (InvalidAlgorithmParameterException iape) { + // never thrown when null parameters are used; + // but re-throw it just in case + throw new InvalidKeyException("Wrong parameters", iape); + } + } + + // see JCE spec + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { + init(opmode, key, random, params); + } + + // see JCE spec + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { + if (params == null) { + init(opmode, key, random, null); + } else { + try { + OAEPParameterSpec oaepParameterSpec = + params.getParameterSpec(OAEPParameterSpec.class); + init(opmode, key, random, oaepParameterSpec); + } catch (InvalidParameterSpecException ipse) { + InvalidAlgorithmParameterException iape = + new InvalidAlgorithmParameterException("Wrong parameter"); + iape.initCause(ipse); + throw iape; + } + } + } + + // check TlsRsaPremasterSecretParameterSpec + private void checkTlsRsaPremasterSecretParameterSpec(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); + } + } + + // check OAEPParameterSpec + private void checkOAEPParameterSpec(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + if (!(params instanceof OAEPParameterSpec)) { + throw new InvalidAlgorithmParameterException + ("Wrong Parameters for OAEP Padding"); + } + + // check MGF algorithm + OAEPParameterSpec oaepParameterSpec = (OAEPParameterSpec) params; + String mgfName = oaepParameterSpec.getMGFAlgorithm(); + if (!mgfName.equalsIgnoreCase("MGF1")) { + throw new InvalidAlgorithmParameterException + ("Unsupported MGF algo: " + mgfName); + } + + // check PSource algorithm + PSource pSource = oaepParameterSpec.getPSource(); + String pSourceAlgorithm = pSource.getAlgorithm(); + if (!pSourceAlgorithm.equalsIgnoreCase("PSpecified")) { + throw new InvalidAlgorithmParameterException + ("Unsupported pSource algo: " + pSourceAlgorithm); + } + } + + // compute OAEP data buffer length + private int getOAEPBufferLen(int outputSize, OAEPParameterSpec oaepParameterSpec, boolean encrypt) + throws InvalidKeyException { + if (!encrypt) { + return outputSize; + } + String mdName = oaepParameterSpec.getDigestAlgorithm(); + String mgfMdName = ((MGF1ParameterSpec) oaepParameterSpec.getMGFParameters()) + .getDigestAlgorithm(); + int digestLen = KAEUtils.getDigestLength(mdName); + int bufferLen = outputSize - 2 - 2 * digestLen; + if (bufferLen < 0) { + throw new InvalidKeyException + ("Key is too short for encryption using OAEPPadding" + + " with " + mdName + " and MGF1" + mgfMdName); + } + return bufferLen; + } + + // non-CRT private key, use the jdk soft calculation. + private boolean useJdkSoftCalculation() { + return (rsaKey instanceof RSAPrivateKey) && !(rsaKey instanceof RSAPrivateCrtKey); + } + + // get the rsa padding + private RSAPadding getRSAPadding(KAERSAPaddingType paddingType, int paddedSize, + SecureRandom random, AlgorithmParameterSpec spec) + throws InvalidKeyException, InvalidAlgorithmParameterException { + RSAPadding rsaPadding; + if (KAERSAPaddingType.NoPadding.equals(paddingType)) { + rsaPadding = RSAPadding.getInstance(RSAPadding.PAD_NONE, paddedSize, random); + } else if (KAERSAPaddingType.PKCS1Padding.equals(paddingType)) { + int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 + : RSAPadding.PAD_BLOCKTYPE_1; + rsaPadding = RSAPadding.getInstance(blockType, paddedSize, random); + } else { + rsaPadding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, paddedSize, + random, (OAEPParameterSpec) spec); + } + return rsaPadding; + } + + private boolean isEncrypt(int opmode) throws InvalidKeyException { + boolean encrypt; + switch (opmode) { + case Cipher.ENCRYPT_MODE: + case Cipher.WRAP_MODE: + encrypt = true; + break; + case Cipher.DECRYPT_MODE: + case Cipher.UNWRAP_MODE: + encrypt = false; + break; + default: + throw new InvalidKeyException("Unknown mode: " + opmode); + } + return encrypt; + } + + // initialize this cipher + private void init(int opmode, Key key, SecureRandom random, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException { + // check the key, and convert to RSAKey + rsaKey = RSAKeyFactory.toRSAKey(key); + + // init mode + boolean encrypt = isEncrypt(opmode); + if (key instanceof RSAPublicKey) { + mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY; + } else { + mode = encrypt ? MODE_SIGN : MODE_DECRYPT; + } + + int bufferLen = RSACore.getByteLength(rsaKey.getModulus()); + outputSize = bufferLen; + bufOfs = 0; + if (KAERSAPaddingType.PKCS1Padding.equals(paddingType)) { + if (params != null) { + checkTlsRsaPremasterSecretParameterSpec(params); + spec = params; + this.random = random; // for TLS RSA premaster secret + } + if (encrypt) { + bufferLen -= 11; + } + } else if (KAERSAPaddingType.OAEP.equals(paddingType)) { + if ((mode == MODE_SIGN) || (mode == MODE_VERIFY)) { + throw new InvalidKeyException + ("OAEP cannot be used to sign or verify signatures"); + } + if (params != null) { + checkOAEPParameterSpec(params); + spec = params; + } else { + spec = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1", + MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); + } + bufferLen = getOAEPBufferLen(bufferLen, (OAEPParameterSpec) spec, encrypt); + } + buffer = new byte[bufferLen]; + + if (useJdkSoftCalculation()) { + this.padding = getRSAPadding(paddingType, outputSize, random, spec); + } + } + + // internal update method + private void update(byte[] in, int inOfs, int inLen) { + if ((inLen == 0) || (in == null)) { + return; + } + if (inLen > (buffer.length - bufOfs)) { + bufOfs = buffer.length + 1; + return; + } + System.arraycopy(in, inOfs, buffer, bufOfs, inLen); + bufOfs += inLen; + } + + // encrypt or decrypt for NoPadding or PKCS1Padding + private int doCryptNotOAEPPadding(long keyAddress, byte[] input, byte[] output) throws BadPaddingException { + int resultSize; + switch (mode) { + case MODE_SIGN: + resultSize = nativeRSAPrivateEncrypt(keyAddress, input.length, input, output, paddingType.getId()); + break; + case MODE_VERIFY: + resultSize = nativeRSAPublicDecrypt(keyAddress, input.length, input, output, paddingType.getId()); + break; + case MODE_ENCRYPT: + resultSize = nativeRSAPublicEncrypt(keyAddress, input.length, input, output, paddingType.getId()); + break; + case MODE_DECRYPT: + resultSize = nativeRSAPrivateDecrypt(keyAddress, input.length, input, output, paddingType.getId()); + break; + default: + throw new AssertionError("Internal error"); + } + return resultSize; + } + + + // encrypt or decrypt for OAEPPadding + private int doCryptOAEPPadding(long keyAddress, byte[] input, byte[] output, OAEPParameterSpec oaepParameterSpec) + throws BadPaddingException { + // oaep digest algorithm + String oaepMdAlgorithm = KAEUtils.getKAEDigestName(oaepParameterSpec.getDigestAlgorithm()); + // mgf1 digest algorithm + MGF1ParameterSpec mgf1ParameterSpec = (MGF1ParameterSpec) oaepParameterSpec.getMGFParameters(); + String mgf1MdAlgorithm = KAEUtils.getKAEDigestName(mgf1ParameterSpec.getDigestAlgorithm()); + // label + PSource pSource = oaepParameterSpec.getPSource(); + byte[] label = ((PSource.PSpecified) pSource).getValue(); + int resultSize; + switch (mode) { + case MODE_ENCRYPT: + resultSize = nativeRSAEncryptOAEPPadding(keyAddress, input.length, input, output, paddingType.getId(), + oaepMdAlgorithm, mgf1MdAlgorithm, label); + break; + case MODE_DECRYPT: + resultSize = nativeRSADecryptOAEPPadding(keyAddress, input.length, input, output, paddingType.getId(), + oaepMdAlgorithm, mgf1MdAlgorithm, label); + break; + default: + throw new AssertionError("Internal error"); + } + return resultSize; + } + + // get input bytes + private byte[] getInputBytes(byte[] buffer, int bufOfs, KAERSAPaddingType paddingType) { + if (bufOfs == buffer.length) { + return buffer; + } + + // if padding type is NoPadding , data should move to end + final byte[] input; + if (KAERSAPaddingType.NoPadding.equals(paddingType)) { + input = new byte[buffer.length]; + System.arraycopy(buffer, 0, input, buffer.length - bufOfs, bufOfs); + } else { + input = Arrays.copyOf(buffer, bufOfs); + } + return input; + } + + // internal doFinal() method. Here we perform the actual RSA operation + private byte[] doFinal() throws BadPaddingException, IllegalBlockSizeException { + if (bufOfs > buffer.length) { + throw new IllegalBlockSizeException("Data must not be longer " + + "than " + buffer.length + " bytes"); + } + + if (useJdkSoftCalculation()) { + return doFinalForJdkSoftCalculation(padding); + } + + // get input bytes + final byte[] input = getInputBytes(buffer, bufOfs, paddingType); + + try { + rsaKeyHolder = new KAERSAKeyHolder(this, rsaKey); + } catch (InvalidKeyException e) { + throw new RuntimeException(e.getMessage()); + } + + long keyAddress = rsaKeyHolder.keyAddress; + byte[] output = new byte[outputSize]; + int cipherTextLength; + try { + if (KAERSAPaddingType.OAEP.equals(paddingType)) { + // do crypt for OAEPPadding + cipherTextLength = doCryptOAEPPadding(keyAddress, input, output, (OAEPParameterSpec) spec); + } else { + // do crypt for NoPadding or PKCS1Padding + cipherTextLength = doCryptNotOAEPPadding(keyAddress, input, output); + } + + // If mode is signing or verifying , and the length of the ciphertext is less than output length, + // just keep output length ciphertext. + if ((mode == MODE_VERIFY || mode == MODE_DECRYPT) && cipherTextLength != output.length) { + output = Arrays.copyOf(output, cipherTextLength); + } + } finally { + bufOfs = 0; + resetKeyHolder(); + } + return output; + } + + private byte[] doFinalForJdkSoftCalculation(RSAPadding padding) throws BadPaddingException { + try { + byte[] data; + switch (mode) { + case MODE_SIGN: + data = padding.pad(buffer, 0, bufOfs); + return RSACore.rsa(data, (RSAPrivateKey) rsaKey, true); + case MODE_DECRYPT: + byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); + data = RSACore.rsa(decryptBuffer, (RSAPrivateKey) rsaKey, false); + return padding.unpad(data); + default: + throw new AssertionError("Internal error"); + } + } finally { + bufOfs = 0; + } + } + + // see JCE spec + @Override + protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { + update(in, inOfs, inLen); + return B0; + } + + // see JCE spec + @Override + protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) { + update(in, inOfs, inLen); + return 0; + } + + // see JCE spec + @Override + protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) + throws BadPaddingException, IllegalBlockSizeException { + update(in, inOfs, inLen); + return doFinal(); + } + + // see JCE spec + @Override + protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) + throws ShortBufferException, BadPaddingException, IllegalBlockSizeException { + if (outputSize > out.length - outOfs) { + throw new ShortBufferException + ("Need " + outputSize + " bytes for output"); + } + update(in, inOfs, inLen); + byte[] result = doFinal(); + int length = result.length; + System.arraycopy(result, 0, out, outOfs, length); + return length; + } + + // see JCE spec + @Override + protected byte[] engineWrap(Key key) throws InvalidKeyException, + IllegalBlockSizeException { + byte[] encoded = key.getEncoded(); + if ((encoded == null) || (encoded.length == 0)) { + throw new InvalidKeyException("Could not obtain encoded key"); + } + if (encoded.length > buffer.length) { + throw new InvalidKeyException("Key is too long for wrapping"); + } + update(encoded, 0, encoded.length); + try { + return doFinal(); + } catch (BadPaddingException e) { + // should not occur + throw new InvalidKeyException("Wrapping failed", e); + } + } + + // see JCE spec + @Override + protected Key engineUnwrap(byte[] wrappedKey, String algorithm, int type) + throws InvalidKeyException, NoSuchAlgorithmException { + if (wrappedKey.length > buffer.length) { + throw new InvalidKeyException("Key is too long for unwrapping"); + } + + boolean isTlsRsaPremasterSecret = "TlsRsaPremasterSecret".equals(algorithm); + Exception failover = null; + byte[] encoded = null; + + update(wrappedKey, 0, wrappedKey.length); + try { + encoded = doFinal(); + } catch (BadPaddingException e) { + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("Unwrapping failed", e); + } + } catch (IllegalBlockSizeException e) { + // should not occur, handled with length check above + throw new InvalidKeyException("Unwrapping failed", e); + } + + if (isTlsRsaPremasterSecret) { + if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new IllegalStateException( + "No TlsRsaPremasterSecretParameterSpec specified"); + } + + // polish the TLS premaster secret + encoded = KeyUtil.checkTlsPreMasterSecretKey( + ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(), + ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(), + random, encoded, (failover != null)); + } + return KAEUtils.ConstructKeys.constructKey(encoded, algorithm, type); + } + + // see JCE spec + @Override + protected int engineGetKeySize(Key key) throws InvalidKeyException { + RSAKey newRSAKey = RSAKeyFactory.toRSAKey(key); + return newRSAKey.getModulus().bitLength(); + } + + // reset the key holder + private void resetKeyHolder() { + if (rsaKeyHolder != null) { + rsaKeyHolder.dispose(true); + rsaKeyHolder = null; + } + } + + // create KAE rsa key + protected static native long nativeCreateRSAPrivateCrtKey(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q, + byte[] dmp1, byte[] dmq1, byte[] iqmp); + + // create KAE rsa public key + protected static native long nativeCreateRSAPublicKey(byte[] n, byte[] e); + + // encrypt by private key for padding type (NOPADDING|PKCS1PADDING) + protected static native int nativeRSAPrivateEncrypt(long keyAddress, int inLen, byte[] in, byte[] out, + int paddingType) throws BadPaddingException; + + // decrypt by private key for padding type (NOPADDING|PKCS1PADDING) + protected static native int nativeRSAPrivateDecrypt(long keyAddress, int inLen, byte[] in, byte[] out, + int paddingType) throws BadPaddingException; + + // encrypt by public key for padding type (NOPADDING|PKCS1PADDING) + protected static native int nativeRSAPublicEncrypt(long keyAddress, int inLen, byte[] in, byte[] out, + int paddingType) throws BadPaddingException; + + // decrypt by public key for padding type (NOPADDING|PKCS1PADDING) + protected static native int nativeRSAPublicDecrypt(long keyAddress, int inLen, byte[] in, byte[] out, + int paddingType) throws BadPaddingException; + + // encrypt by public for padding type (OAEPPADDING) + protected static native int nativeRSAEncryptOAEPPadding(long keyAddress, int inLen, byte[] in, byte[] out, + int paddingType, String oaepMdAlgo, String mgf1MdAlgo, + byte[] label) throws BadPaddingException; + + // decrypt by public for padding type (OAEPPADDING) + protected static native int nativeRSADecryptOAEPPadding(long keyAddress, int inLen, byte[] in, byte[] out, + int paddingType, String oaepMdAlgo, String mgf1MdAlgo, + byte[] label) throws BadPaddingException; + + // free the key + protected static native void nativeFreeKey(long keyAddress); + + /** + * The rsa openssl key holder , use PhantomReference in case of native memory leaks + */ + private static class KAERSAKeyHolder extends PhantomReference<KAERSACipher> + implements Comparable<KAERSAKeyHolder> { + private static ReferenceQueue<KAERSACipher> referenceQueue = new ReferenceQueue<>(); + private static Set<KAERSAKeyHolder> referenceList = new ConcurrentSkipListSet<>(); + private final long keyAddress; + + KAERSAKeyHolder(KAERSACipher rsaCipher, RSAKey rsaKey) throws InvalidKeyException { + super(rsaCipher, referenceQueue); + this.keyAddress = getKeyAddress(rsaKey); + referenceList.add(this); + drainRefQueueBounded(); + } + + private static void drainRefQueueBounded() { + while (true) { + KAERSAKeyHolder next = (KAERSAKeyHolder) referenceQueue.poll(); + if (next == null) { + break; + } + next.dispose(true); + } + } + + void dispose(boolean needFree) { + referenceList.remove(this); + try { + if (needFree) { + nativeFreeKey(keyAddress); + } + } finally { + this.clear(); + } + } + + @Override + public int compareTo(KAERSAKeyHolder other) { + if (this.keyAddress == other.keyAddress) { + return 0; + } else { + return (this.keyAddress < other.keyAddress) ? -1 : 1; + } + } + + private long getKeyAddress(RSAKey rsaKey) throws InvalidKeyException { + long address; + if (rsaKey instanceof RSAPrivateCrtKey) { // RSAPrivateCrtKeyImpl + address = getKeyAddress((RSAPrivateCrtKey) rsaKey); + } else if (rsaKey instanceof RSAPublicKey) { // RSAPublicKeyImpl + address = getKeyAddress((RSAPublicKey) rsaKey); + } else { + throw new InvalidKeyException("Invalid RSAKey implement " + rsaKey.getClass()); + } + return address; + } + + private long getKeyAddress(RSAPrivateCrtKey key) throws InvalidKeyException { + checkKey(key); + long address; + try { + address = nativeCreateRSAPrivateCrtKey( + key.getModulus().toByteArray(), + key.getPublicExponent().toByteArray(), + key.getPrivateExponent().toByteArray(), + key.getPrimeP().toByteArray(), + key.getPrimeQ().toByteArray(), + key.getPrimeExponentP().toByteArray(), + key.getPrimeExponentQ().toByteArray(), + key.getCrtCoefficient().toByteArray()); + return address; + } catch (Exception e) { + throw new InvalidKeyException(e); + } + } + + private long getKeyAddress(RSAPublicKey key) throws InvalidKeyException { + checkKey(key); + long address; + try { + address = nativeCreateRSAPublicKey( + key.getModulus().toByteArray(), + key.getPublicExponent().toByteArray() + ); + return address; + } catch (Exception e) { + throw new InvalidKeyException(e); + } + } + + private void checkKey(RSAPrivateCrtKey key) throws InvalidKeyException { + if (key.getModulus() == null + || key.getPublicExponent() == null + || key.getPrivateExponent() == null + || key.getPrimeP() == null + || key.getPrimeQ() == null + || key.getPrimeExponentP() == null + || key.getPrimeExponentQ() == null + || key.getCrtCoefficient() == null) { + throw new InvalidKeyException("Invalid RSA private key"); + } + } + + private void checkKey(RSAPublicKey key) throws InvalidKeyException { + if (key.getModulus() == null || key.getPublicExponent() == null) { + throw new InvalidKeyException("Invalid RSA public key"); + } + } + } +} diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java new file mode 100644 index 00000000..51d7a95e --- /dev/null +++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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 org.openeuler.security.openssl; + +import sun.security.rsa.*; +import sun.security.rsa.RSAUtil.KeyType; +import sun.security.util.SecurityProviderConstants; + +import java.math.BigInteger; +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.RSAKeyGenParameterSpec; + +public abstract class KAERSAKeyPairGenerator extends KeyPairGeneratorSpi { + // public exponent to use + private BigInteger publicExponent; + + // size of the key to generate, >= KAERSAKeyFactory.MIN_MODLEN + private int keySize; + + private final KeyType type; + + private AlgorithmParameterSpec keyParams; + + + KAERSAKeyPairGenerator(KeyType keyType, int keySize) { + this.type = keyType; + initialize(keySize, null); + } + + // initialize the generator. See JCA doc + @Override + public void initialize(int keySize, SecureRandom random) { + try { + initialize(new RSAKeyGenParameterSpec(keySize, + RSAKeyGenParameterSpec.F4), null); + } catch (InvalidAlgorithmParameterException iape) { + throw new InvalidParameterException(iape.getMessage()); + } + } + + // second initialize method. See JCA doc + @Override + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException { + if (!(params instanceof RSAKeyGenParameterSpec)) { + throw new InvalidAlgorithmParameterException + ("Params must be instance of RSAKeyGenParameterSpec"); + } + + RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) params; + int tmpKeySize = rsaSpec.getKeysize(); + BigInteger tmpPublicExponent = rsaSpec.getPublicExponent(); + keyParams = rsaSpec.getKeyParams(); + + if (tmpPublicExponent == null) { + tmpPublicExponent = RSAKeyGenParameterSpec.F4; + } else { + if (tmpPublicExponent.compareTo(RSAKeyGenParameterSpec.F0) < 0) { + throw new InvalidAlgorithmParameterException + ("Public exponent must be 3 or larger"); + } + if (tmpPublicExponent.bitLength() > tmpKeySize) { + throw new InvalidAlgorithmParameterException + ("Public exponent must be smaller than key size"); + } + } + + // do not allow unreasonably large key sizes, probably user error + try { + RSAKeyFactory.checkKeyLengths(tmpKeySize, tmpPublicExponent, + 512, 64 * 1024); + } catch (InvalidKeyException e) { + throw new InvalidAlgorithmParameterException( + "Invalid key sizes", e); + } + + this.keySize = tmpKeySize; + this.publicExponent = tmpPublicExponent; + } + + // generate the keypair. See JCA doc + @Override + public KeyPair generateKeyPair() { + // get the KAE RSA key Parameters + byte[][] params = nativeGenerateKeyPair(keySize, publicExponent.toByteArray()); + + try { + // check KAE RSA key Parameters + checkKAERSAParams(params); + + BigInteger n = new BigInteger(params[0]); + BigInteger e = new BigInteger(params[1]); + BigInteger d = new BigInteger(params[2]); + BigInteger p = new BigInteger(params[3]); + BigInteger q = new BigInteger(params[4]); + BigInteger pe = new BigInteger(params[5]); + BigInteger qe = new BigInteger(params[6]); + BigInteger coeff = new BigInteger(params[7]); + + // public key + PublicKey publicKey = RSAPublicKeyImpl.newKey(type, keyParams, n, e); + + // private key + PrivateKey privateKey = RSAPrivateCrtKeyImpl.newKey(type, keyParams, n, e, d, p, q, pe, qe, coeff); + + return new KeyPair(publicKey, privateKey); + } catch (InvalidKeyException ex) { + throw new RuntimeException(ex); + } + } + + // check KAE RSA key Parameters + private void checkKAERSAParams(byte[][] params) throws InvalidKeyException { + if (params == null || params.length < 8) { + throw new InvalidKeyException("Invalid KAE RSA key Parameter"); + } + + for (int i = 0; i < params.length; i++) { + if (params[i] == null) { + throw new InvalidKeyException("Invalid KAE RSA key Parameter , params[" + i + "] = null"); + } + } + } + + public static final class Legacy extends KAERSAKeyPairGenerator { + public Legacy() { + super(KeyType.RSA, SecurityProviderConstants.DEF_RSA_KEY_SIZE); + } + } + + public static final class PSS extends KAERSAKeyPairGenerator { + public PSS() { + super(KeyType.PSS, SecurityProviderConstants.DEF_RSASSA_PSS_KEY_SIZE); + } + } + + // generate key pair + static native byte[][] nativeGenerateKeyPair(int keySize, byte[] publicExponent) throws RuntimeException; +} diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAPaddingType.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAPaddingType.java new file mode 100644 index 00000000..04036b8d --- /dev/null +++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAPaddingType.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +package org.openeuler.security.openssl; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +enum KAERSAPaddingType { + // raw RSA + PKCS1Padding(1, "PKCS1Padding"), + + // PKCS#1 v1.5 RSA + NoPadding(3, "NoPadding"), + + // PKCS#2 v2.2 OAEP with MGF1 + OAEP(4, "OAEP", new HashSet<>( + Arrays.asList( + "OAEPPADDING", + "OAEPWITHMD5ANDMGF1PADDING", + "OAEPWITHSHA1ANDMGF1PADDING", + "OAEPWITHMD5ANDMGF1PADDING", + "OAEPWITHSHA1ANDMGF1PADDING", + "OAEPWITHSHA-1ANDMGF1PADDING", + "OAEPWITHSHA-224ANDMGF1PADDING", + "OAEPWITHSHA-256ANDMGF1PADDING", + "OAEPWITHSHA-384ANDMGF1PADDING", + "OAEPWITHSHA-512ANDMGF1PADDING", + "OAEPWITHSHA-512/224ANDMGF1PADDING", + "OAEPWITHSHA-512/256ANDMGF1PADDING")) + ); + + private final int id; + private final String name; + private final Set<String> supportPaddings; + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + KAERSAPaddingType(int id, String name) { + this(id, name, Collections.singleton(name)); + } + + KAERSAPaddingType(int id, String name, Set<String> supportPaddings) { + this.id = id; + this.name = name; + this.supportPaddings = supportPaddings; + } + + public Set<String> getSupportPaddings() { + return supportPaddings; + } +} diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEUtils.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEUtils.java new file mode 100644 index 00000000..f563fd07 --- /dev/null +++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEUtils.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +package org.openeuler.security.openssl; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.*; + +class KAEUtils { + enum MessageDigestType { + MD2("MD2", "md2", 16), + MD5("MD5", "md5", 16), + SHA1("SHA-1", "sha1", 20, + new HashSet<>(Arrays.asList("SHA1", "1.3.14.3.2.26", "OID.1.3.14.3.2.26"))), + SHA224("SHA-224", "sha224", 28, + new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.4", "OID.2.16.840.1.101.3.4.2.4"))), + SHA256("SHA-256", "sha256", 32, + new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1"))), + SHA384("SHA-384", "sha384", 48, + new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2"))), + SHA512("SHA-512", "sha512", 64, + new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3"))), + SHA512_224("SHA-512/224", "sha512-224", 28, + new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.5", "OID.2.16.840.1.101.3.4.2.5"))), + SHA_512_256("SHA-512/256", "sha512-256", 32, + new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.6", "OID.2.16.840.1.101.3.4.2.6"))); + + final String digestName; + final String kaeDigestName; + final int digestLen; + final Set<String> aliasNames; + + public String getDigestName() { + return digestName; + } + + public String getKaeDigestName() { + return kaeDigestName; + } + + public int getDigestLen() { + return digestLen; + } + + public Set<String> getAliasNames() { + return aliasNames; + } + + MessageDigestType(String digestName, String kaeDigestName, int digestLen, Set<String> aliasNames) { + this.digestName = digestName; + this.kaeDigestName = kaeDigestName; + this.digestLen = digestLen; + this.aliasNames = aliasNames; + } + + MessageDigestType(String digestName, String kaeDigestName, int digestLen) { + this(digestName, kaeDigestName, digestLen, Collections.emptySet()); + } + } + + /** + * kae digest algorithm info map + */ + private static final Map<String, String> DIGEST_ALGORITHM_NAME_MAP = new HashMap<>(); + private static final Map<String, Integer> DIGEST_ALGORITHM_LENGTH_MAP = new HashMap<>(); + + static { + initDigest(); + } + + private static void initDigest() { + MessageDigestType[] messageDigestTypes = MessageDigestType.values(); + for (MessageDigestType messageDigestType : messageDigestTypes) { + DIGEST_ALGORITHM_NAME_MAP.put(messageDigestType.getDigestName(), messageDigestType.getKaeDigestName()); + DIGEST_ALGORITHM_LENGTH_MAP.put(messageDigestType.getDigestName(), messageDigestType.getDigestLen()); + for (String aliasName : messageDigestType.getAliasNames()) { + DIGEST_ALGORITHM_NAME_MAP.put(aliasName, messageDigestType.getKaeDigestName()); + DIGEST_ALGORITHM_LENGTH_MAP.put(aliasName, messageDigestType.getDigestLen()); + } + } + } + + // get the kae digest algorithm name + static String getKAEDigestName(String digestName) { + return DIGEST_ALGORITHM_NAME_MAP.get(digestName); + } + + static int getDigestLength(String digestName) { + return DIGEST_ALGORITHM_LENGTH_MAP.get(digestName); + } + + static class ConstructKeys { + /** + * Construct a public key from its encoding. + * + * @param encodedKey the encoding of a public key. + * @param encodedKeyAlgorithm the algorithm the encodedKey is for. + * @return a public key constructed from the encodedKey. + */ + private static PublicKey constructPublicKey(byte[] encodedKey, + String encodedKeyAlgorithm) + throws InvalidKeyException, NoSuchAlgorithmException { + try { + KeyFactory keyFactory = + KeyFactory.getInstance(encodedKeyAlgorithm); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); + return keyFactory.generatePublic(keySpec); + } catch (NoSuchAlgorithmException nsae) { + throw new NoSuchAlgorithmException("No installed providers " + + "can create keys for the " + + encodedKeyAlgorithm + + "algorithm", nsae); + } catch (InvalidKeySpecException ike) { + throw new InvalidKeyException("Cannot construct public key", ike); + } + } + + /** + * Construct a private key from its encoding. + * + * @param encodedKey the encoding of a private key. + * @param encodedKeyAlgorithm the algorithm the wrapped key is for. + * @return a private key constructed from the encodedKey. + */ + private static PrivateKey constructPrivateKey(byte[] encodedKey, + String encodedKeyAlgorithm) throws InvalidKeyException, + NoSuchAlgorithmException { + try { + KeyFactory keyFactory = + KeyFactory.getInstance(encodedKeyAlgorithm); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); + return keyFactory.generatePrivate(keySpec); + } catch (NoSuchAlgorithmException nsae) { + throw new NoSuchAlgorithmException("No installed providers " + + "can create keys for the " + + encodedKeyAlgorithm + + "algorithm", nsae); + } catch (InvalidKeySpecException ike) { + throw new InvalidKeyException("Cannot construct private key", ike); + } + } + + /** + * Construct a secret key from its encoding. + * + * @param encodedKey the encoding of a secret key. + * @param encodedKeyAlgorithm the algorithm the secret key is for. + * @return a secret key constructed from the encodedKey. + */ + private static SecretKey constructSecretKey(byte[] encodedKey, + String encodedKeyAlgorithm) { + return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); + } + + static Key constructKey(byte[] encoding, String keyAlgorithm, + int keyType) throws InvalidKeyException, NoSuchAlgorithmException { + switch (keyType) { + case Cipher.SECRET_KEY: + return constructSecretKey(encoding, keyAlgorithm); + case Cipher.PRIVATE_KEY: + return constructPrivateKey(encoding, keyAlgorithm); + case Cipher.PUBLIC_KEY: + return constructPublicKey(encoding, keyAlgorithm); + default: + throw new InvalidKeyException("Unknown keytype " + keyType); + } + } + } +} diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_aes.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_aes.c new file mode 100644 index 00000000..8a9526a2 --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_aes.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +#include <openssl/evp.h> +#include <openssl/err.h> +#include <string.h> +#include "kae_log.h" +#include "kae_exception.h" +#include "org_openeuler_security_openssl_KAEAESCipher.h" + +static const EVP_CIPHER* EVPGetCipherByName(JNIEnv* env, const char* algo) +{ + static const EVP_CIPHER* aes128Ecb = NULL; + static const EVP_CIPHER* aes128Cbc = NULL; + static const EVP_CIPHER* aes128Ctr = NULL; + static const EVP_CIPHER* aes192Ecb = NULL; + static const EVP_CIPHER* aes192Cbc = NULL; + static const EVP_CIPHER* aes192Ctr = NULL; + static const EVP_CIPHER* aes256Ecb = NULL; + static const EVP_CIPHER* aes256Cbc = NULL; + static const EVP_CIPHER* aes256Ctr = NULL; + + if (strcasecmp(algo, "aes-128-ecb") == 0) { + return aes128Ecb == NULL ? aes128Ecb = EVP_get_cipherbyname(algo) : aes128Ecb; + } else if (strcasecmp(algo, "aes-128-cbc") == 0) { + return aes128Cbc == NULL ? aes128Cbc = EVP_get_cipherbyname(algo) : aes128Cbc; + } else if (strcasecmp(algo, "aes-128-ctr") == 0) { + return aes128Ctr == NULL ? aes128Ctr = EVP_get_cipherbyname(algo) : aes128Ctr; + } else if (strcasecmp(algo, "aes-192-ecb") == 0) { + return aes192Ecb == NULL ? aes192Ecb = EVP_get_cipherbyname(algo) : aes192Ecb; + } else if (strcasecmp(algo, "aes-192-cbc") == 0) { + return aes192Cbc == NULL ? aes192Cbc = EVP_get_cipherbyname(algo) : aes192Cbc; + } else if (strcasecmp(algo, "aes-192-ctr") == 0) { + return aes192Ctr == NULL ? aes192Ctr = EVP_get_cipherbyname(algo) : aes192Ctr; + } else if (strcasecmp(algo, "aes-256-ecb") == 0) { + return aes256Ecb == NULL ? aes256Ecb = EVP_get_cipherbyname(algo) : aes256Ecb; + } else if (strcasecmp(algo, "aes-256-cbc") == 0) { + return aes256Cbc == NULL ? aes256Cbc = EVP_get_cipherbyname(algo) : aes256Cbc; + } else if (strcasecmp(algo, "aes-256-ctr") == 0) { + return aes256Ctr == NULL ? aes256Ctr = EVP_get_cipherbyname(algo) : aes256Ctr; + } else { + KAE_ThrowRuntimeException(env, "EVPGetCipherByName error"); + return 0; + } +} + +/* + * Class: org_openeuler_security_openssl_KAEAESCipher + * Method: nativeInit + * Signature: (Ljava/lang/String;Z[B[B)J + */ +JNIEXPORT jlong JNICALL +Java_org_openeuler_security_openssl_KAEAESCipher_nativeInit(JNIEnv* env, jclass cls, + jstring cipherType, jboolean encrypt, jbyteArray key, jbyteArray iv, jboolean padding) +{ + EVP_CIPHER_CTX* ctx = NULL; + jbyte* keyBytes = NULL; + jbyte* ivBytes = NULL; + const EVP_CIPHER* cipher = NULL; + + const char* algo = (*env)->GetStringUTFChars(env, cipherType, 0); + cipher = EVPGetCipherByName(env, algo); + (*env)->ReleaseStringUTFChars(env, cipherType, algo); + if (cipher == NULL) { + KAE_ThrowOOMException(env, "create EVP_CIPHER fail"); + goto err; + } + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + KAE_ThrowOOMException(env, "create EVP_CIPHER_CTX fail"); + goto err; + } + + if (iv != NULL) { + ivBytes = (*env)->GetByteArrayElements(env, iv, NULL); + } + const unsigned char* i = (const unsigned char*) ivBytes; + + if (key != NULL) { + keyBytes = (*env)->GetByteArrayElements(env, key, NULL); + } + const unsigned char* k = (const unsigned char*) keyBytes; + + if (!EVP_CipherInit_ex(ctx, cipher, NULL, k, i, encrypt ? 1 : 0)) { + KAE_ThrowFromOpenssl(env, "EVP_CipherInit_ex failed", KAE_ThrowRuntimeException); + goto err; + } + KAE_TRACE("KAEAESCipher_nativeInit EVP_CipherInit_ex(ctx = %p, cipher = %p, key = %p, iv = %p, encrypt = %d) " + "success", ctx, cipher, key, iv, encrypt ? 1 : 0); + + EVP_CIPHER_CTX_set_padding(ctx, padding ? 1 : 0); + + if (iv != NULL) { + (*env)->ReleaseByteArrayElements(env, iv, ivBytes, 0); + } + (*env)->ReleaseByteArrayElements(env, key, keyBytes, 0); + return (jlong) ctx; +err: + if (ctx != NULL) { + EVP_CIPHER_CTX_free(ctx); + } + if (ivBytes != NULL) { + (*env)->ReleaseByteArrayElements(env, iv, ivBytes, 0); + } + if (keyBytes != NULL) { + (*env)->ReleaseByteArrayElements(env, key, keyBytes, 0); + } + return 0; +} + +/* + * Class: org_openeuler_security_openssl_KAEAESCipher + * Method: nativeUpdate + * Signature: (JZ[BII[BI)I + */ +JNIEXPORT jint JNICALL +Java_org_openeuler_security_openssl_KAEAESCipher_nativeUpdate(JNIEnv* env, jclass cls, + jlong ctxAddress, jbyteArray inArr, jint inOfs, jint inLen, jbyteArray outArr, jint outOfs) +{ + jbyte* in = NULL; + unsigned char* out = NULL; + + EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*) ctxAddress; + if (ctx == NULL) { + goto err; + } + + if (inArr == NULL || outArr == NULL) { + goto err; + } + int inputLen = (*env)->GetArrayLength(env, inArr); + if ((inOfs < 0) || (inOfs > inputLen) || (inLen < 0) || (inLen > inputLen - inOfs)) { + KAE_ThrowArrayIndexOutOfBoundsException(env, "inArr"); + goto err; + } + in = malloc(sizeof(jbyte) * inputLen); + if (in == NULL) { + KAE_ThrowOOMException(env, "malloc error"); + goto err; + } + (*env)->GetByteArrayRegion(env, inArr, 0, inputLen, in); + + int outputLen = (*env)->GetArrayLength(env, outArr); + if ((outOfs < 0) || (outOfs > outputLen) || (inLen < 0) || (inLen > outputLen - outOfs)) { + KAE_ThrowArrayIndexOutOfBoundsException(env, "outArr"); + goto err; + } + out = malloc(outputLen - outOfs); + if (out == NULL) { + KAE_ThrowOOMException(env, "malloc error"); + goto err; + } + + unsigned int bytesWritten = 0; + if (EVP_CipherUpdate(ctx, out, &bytesWritten, in + inOfs, inLen) == 0) { + KAE_ThrowFromOpenssl(env, "EVP_CipherUpdate failed", KAE_ThrowRuntimeException); + goto err; + } + KAE_TRACE("KAEAESCipher_nativeUpdate EVP_CipherUpdate success, bytesWritten = %d", bytesWritten); + (*env)->SetByteArrayRegion(env, outArr, outOfs, bytesWritten, (jbyte*) out); + + free(in); + free(out); + return bytesWritten; +err: + if (in != NULL) { + free(in); + } + if (out != NULL) { + free(out); + } + return 0; +} + +/* + * Class: org_openeuler_security_openssl_KAEAESCipher + * Method: nativeFinal + * Signature: (JZ[BI)I + */ +JNIEXPORT jint JNICALL +Java_org_openeuler_security_openssl_KAEAESCipher_nativeFinal(JNIEnv* env, jclass cls, + jlong ctxAddress, jbyteArray outArr, jint outOfs) +{ + unsigned char* out; + EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*) ctxAddress; + KAE_TRACE("KAEAESCipher_nativeFinal(ctxAddress = %p, outArr = %p, outOfs = %d)", + ctx, outArr, outOfs); + if (ctx == NULL) { + goto err; + } + if (outArr == NULL) { + goto err; + } + int outputLen = (*env)->GetArrayLength(env, outArr); + out = malloc(outputLen - outOfs); + if (out == NULL) { + KAE_ThrowOOMException(env, "malloc error"); + goto err; + } + unsigned int bytesWritten = 0; + int result_code = EVP_CipherFinal_ex(ctx, out, &bytesWritten); + if (result_code == 0) { + KAE_ThrowFromOpenssl(env, "EVP_CipherFinal_ex failed", KAE_ThrowBadPaddingException); + goto err; + } + KAE_TRACE("KAEAESCipher_nativeFinal EVP_CipherFinal_ex success, bytesWritten = %d", bytesWritten); + (*env)->SetByteArrayRegion(env, outArr, outOfs, bytesWritten, (jbyte*) out); + free(out); + KAE_TRACE("KAEAESCipher_nativeFinal: finished"); + return bytesWritten; + +err: + if (out != NULL) { + free(out); + } + return 0; +} + +/* + * Class: org_openeuler_security_openssl_KAEAESCipher + * Method: nativeFree + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_org_openeuler_security_openssl_KAEAESCipher_nativeFree(JNIEnv* env, jclass cls, jlong ctxAddress) +{ + EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*) ctxAddress; + KAE_TRACE("KAEAESCipher_nativeFree(ctx = %p)", ctx); + if (ctx != NULL) { + EVP_CIPHER_CTX_free(ctx); + } + + KAE_TRACE("KAEAESCipher_nativeFree: finished"); +} diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c new file mode 100644 index 00000000..ed645698 --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +#include <openssl/rsa.h> +#include <openssl/evp.h> +#include "kae_util.h" +#include "kae_exception.h" +#include "org_openeuler_security_openssl_KAERSACipher.h" + +#define SUCCESS 1 +#define FAILED -1 + +typedef int RSACryptOperation(int, const unsigned char*, unsigned char*, RSA*, int); + +typedef int EvpPkeyCryptOperation(EVP_PKEY_CTX*, unsigned char*, size_t*, const unsigned char*, size_t); + +typedef int EvpPkeyCryptInitOperation(EVP_PKEY_CTX*); + +/* + * RSA encrypt or decrypt for NoPadding or PKCS1Padding , follow the steps below + * + */ +static int RSACryptNotOAEPPadding(JNIEnv* env, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, + jint paddingType, RSACryptOperation rsaCryptOperation, char* cryptName) { + jbyte* inBytes = NULL; + jbyte* outBytes = NULL; + int resultSize = 0; + + // get RSA + EVP_PKEY* pkey = (EVP_PKEY*)keyAddress; + + // rsa = pkey->rsa + RSA* rsa = EVP_PKEY_get1_RSA(pkey); + if (rsa == NULL) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_get1_RSA", KAE_ThrowRuntimeException); + return 0; + } + + // do encrypt or decrypt + inBytes = (*env)->GetByteArrayElements(env, in, NULL); + if (inBytes == NULL) { + KAE_ThrowNullPointerException(env, "GetByteArrayElements failed"); + goto cleanup; + } + outBytes = (*env)->GetByteArrayElements(env, out, NULL); + if (outBytes == NULL) { + KAE_ThrowNullPointerException(env, "GetByteArrayElements failed"); + goto cleanup; + } + resultSize = rsaCryptOperation(inLen, (unsigned char*)inBytes, (unsigned char*)outBytes, rsa, paddingType); + if (resultSize <= 0) { + KAE_ThrowFromOpenssl(env, cryptName, KAE_ThrowBadPaddingException); + goto cleanup; + } + jsize outLen = (*env)->GetArrayLength(env, out); + (*env)->SetByteArrayRegion(env, out, 0, outLen, outBytes); + +cleanup: + if (outBytes != NULL) { + (*env)->ReleaseByteArrayElements(env, out, outBytes, 0); + } + if (inBytes != NULL) { + (*env)->ReleaseByteArrayElements(env, in, inBytes, 0); + } + return resultSize; +} + +/* + * set rsa padding + */ +static int SetRSAPadding(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, int paddingType) { + if (EVP_PKEY_CTX_set_rsa_padding(pkeyCtx, paddingType) <= 0) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_padding", KAE_ThrowInvalidAlgorithmParameterException); + return FAILED; + } + return SUCCESS; +} + +/* + * set rsa mgf1 md + */ +static int SetRSAMgf1Md(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, const char* mgf1MdAlgoUTF) { + EVP_MD* mgf1MD = (EVP_MD*)EVP_get_digestbyname(mgf1MdAlgoUTF); + if (mgf1MD == NULL) { + KAE_ThrowFromOpenssl(env, "EVP_get_digestbyname", KAE_ThrowInvalidAlgorithmParameterException); + return FAILED; + } + if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkeyCtx, mgf1MD) <= 0) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_mgf1_md", KAE_ThrowInvalidAlgorithmParameterException); + return FAILED; + } + return SUCCESS; +} + +/* + * set rsa oaep md + */ +static int SetRSAOaepMd(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, const char* oaepMdAlgoUTF) { + EVP_MD* oaepMD = (EVP_MD*)EVP_get_digestbyname(oaepMdAlgoUTF); + if (oaepMD == NULL) { + KAE_ThrowFromOpenssl(env, "EVP_get_digestbyname", KAE_ThrowInvalidAlgorithmParameterException); + return FAILED; + } + if (EVP_PKEY_CTX_set_rsa_oaep_md(pkeyCtx, oaepMD) <= 0) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_oaep_md", KAE_ThrowInvalidAlgorithmParameterException); + return FAILED; + } + return SUCCESS; +} + +/* + * set rsa oaep label + */ +static int SetRSAOaepLabel(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, jbyte* labelBytes, jsize labelSize) { + if (EVP_PKEY_CTX_set0_rsa_oaep_label(pkeyCtx, labelBytes, labelSize) <= 0) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set0_rsa_oaep_label", KAE_ThrowInvalidAlgorithmParameterException); + return FAILED; + } + return SUCCESS; +} + +/* + * release rsa oaep temp resource + */ +static void ReleaseRSACryptOAEPResource(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, + jstring mgf1MdAlgo, const char* mgf1MdAlgoUTF, jstring oaepMdAlgo, const char* oaepMdAlgoUTF, + jbyteArray in, jbyte* inBytes, jbyteArray out, jbyte* outBytes) { + if (mgf1MdAlgoUTF != NULL) { + (*env)->ReleaseStringUTFChars(env, mgf1MdAlgo, mgf1MdAlgoUTF); + } + if (oaepMdAlgoUTF != NULL) { + (*env)->ReleaseStringUTFChars(env, oaepMdAlgo, oaepMdAlgoUTF); + } + if (outBytes != NULL) { + (*env)->ReleaseByteArrayElements(env, out, outBytes, 0); + } + if (inBytes != NULL) { + (*env)->ReleaseByteArrayElements(env, in, inBytes, 0); + } + EVP_PKEY_CTX_free(pkeyCtx); +} + +static int RSACryptOAEPPadding(JNIEnv* env, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, + jint paddingType, jstring oaepMdAlgo, jstring mgf1MdAlgo, jbyteArray label, + EvpPkeyCryptInitOperation cryptInitOperation, char* cryptInitName, + EvpPkeyCryptOperation cryptOperation, char* cryptName) { + EVP_PKEY_CTX* pkeyCtx = NULL; + const char* mgf1MdAlgoUTF = NULL; + const char* oaepMdAlgoUTF = NULL; + jbyte* labelBytes = NULL; + jbyte* outBytes = NULL; + jbyte* inBytes = NULL; + // outLen type should be size_t + // EVP_PKEY_encrypt takes the outLen address as a parameter, and the parameter type is size_t* + size_t outLen = 0; + + EVP_PKEY* pkey = (EVP_PKEY*) keyAddress; + + // new ctx + // rsa encrypt/decrypt init + if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL || cryptInitOperation(pkeyCtx) <= 0) { + KAE_ThrowFromOpenssl(env, pkeyCtx == NULL ? "EVP_PKEY_CTX_new" : cryptInitName, KAE_ThrowInvalidKeyException); + goto cleanup; + } + + if ((mgf1MdAlgoUTF = (*env)->GetStringUTFChars(env, mgf1MdAlgo, 0)) == NULL || + (oaepMdAlgoUTF = (*env)->GetStringUTFChars(env, oaepMdAlgo, 0)) == NULL) { + KAE_ThrowOOMException(env, "GetStringUTFChars failed"); + goto cleanup; + } + + /* + * set padding type + * set rsa mgf1 md + * set rsa oaep md + */ + if(SetRSAPadding(env, pkeyCtx, paddingType) == FAILED || + SetRSAMgf1Md(env, pkeyCtx, mgf1MdAlgoUTF) == FAILED || + SetRSAOaepMd(env, pkeyCtx, oaepMdAlgoUTF) == FAILED) { + goto cleanup; + } + + // set rsa oaep label + jsize labelSize = (*env)->GetArrayLength(env, label); + if (labelSize > 0) { + // EVP_PKEY_CTX_free will free the labelBytes, so we can not free labelBytes when cleanup. + // Only SetRSAOaepLabel failed , free labelBytes. + if ((labelBytes = malloc(labelSize)) == NULL) { + KAE_ThrowNullPointerException(env, "malloc failed"); + goto cleanup; + } + (*env)->GetByteArrayRegion(env, label, 0, labelSize, labelBytes); + if(SetRSAOaepLabel(env, pkeyCtx, labelBytes, labelSize) == FAILED) { + free(labelBytes); + goto cleanup; + } + } + + // do encrypt/decrypt + outLen = (size_t)(*env)->GetArrayLength(env, out); + if ((outBytes = (*env)->GetByteArrayElements(env, out, NULL)) == NULL || + (inBytes = (*env)->GetByteArrayElements(env, in, NULL)) == NULL) { + KAE_ThrowNullPointerException(env, "GetByteArrayElements failed"); + goto cleanup; + } + if (cryptOperation(pkeyCtx, (unsigned char*)outBytes, &outLen, (unsigned char*)inBytes, inLen) <= 0) { + KAE_ThrowFromOpenssl(env, cryptName, KAE_ThrowBadPaddingException); + goto cleanup; + } + (*env)->SetByteArrayRegion(env, out, 0, outLen, outBytes); + +cleanup: + ReleaseRSACryptOAEPResource(env, pkeyCtx, mgf1MdAlgo, mgf1MdAlgoUTF, oaepMdAlgo, oaepMdAlgoUTF, + in, inBytes, out, outBytes); + return outLen; +} + +/* + * Release rsa param n,e,d,p,q,dmp1,dmq1,iqmp + */ +void ReleaseRSAParams(BIGNUM* bnN, BIGNUM* bnE, BIGNUM* bnD, BIGNUM* bnP, BIGNUM* bnQ, + BIGNUM* bnDMP1, BIGNUM* bnDMQ1, BIGNUM* bnIQMP) { + KAE_ReleaseBigNumFromByteArray(bnN); + KAE_ReleaseBigNumFromByteArray(bnE); + KAE_ReleaseBigNumFromByteArray(bnD); + KAE_ReleaseBigNumFromByteArray(bnP); + KAE_ReleaseBigNumFromByteArray(bnQ); + KAE_ReleaseBigNumFromByteArray(bnDMP1); + KAE_ReleaseBigNumFromByteArray(bnDMQ1); + KAE_ReleaseBigNumFromByteArray(bnIQMP); +} + +/* + * Create rsa private crt key + * Class: org_openeuler_security_openssl_KAERSACipher + * Method: nativeCreateRSAPrivateCrtKey + * Signature: ([B[B[B[B[B[B[B[B)J + */ +JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPrivateCrtKey(JNIEnv* env, + jclass cls, jbyteArray n, jbyteArray e, jbyteArray d, jbyteArray p, jbyteArray q, + jbyteArray dmp1, jbyteArray dmq1, jbyteArray iqmp) { + BIGNUM* bnN = NULL; + BIGNUM* bnE = NULL; + BIGNUM* bnD = NULL; + BIGNUM* bnP = NULL; + BIGNUM* bnQ = NULL; + BIGNUM* bnDMP1 = NULL; + BIGNUM* bnDMQ1 = NULL; + BIGNUM* bnIQMP = NULL; + RSA* rsa = NULL; + EVP_PKEY* pkey = NULL; + + // convert to big num + if ((bnN = KAE_GetBigNumFromByteArray(env, n)) == NULL || + (bnE = KAE_GetBigNumFromByteArray(env, e)) == NULL || + (bnD = KAE_GetBigNumFromByteArray(env, d)) == NULL || + (bnP = KAE_GetBigNumFromByteArray(env, p)) == NULL || + (bnQ = KAE_GetBigNumFromByteArray(env, q)) == NULL || + (bnDMP1 = KAE_GetBigNumFromByteArray(env, dmp1)) == NULL || + (bnDMQ1 = KAE_GetBigNumFromByteArray(env, dmq1)) == NULL || + (bnIQMP = KAE_GetBigNumFromByteArray(env, iqmp)) == NULL) { + goto err; + } + + // new pkey + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowRuntimeException); + goto err; + } + + // new rsa + rsa = RSA_new(); + if (rsa == NULL) { + KAE_ThrowFromOpenssl(env, "RSA_new", KAE_ThrowRuntimeException); + goto err; + } + + // set rsa private crt key params n,e,d,p,q,dmp1,dmp1,iqmp + if (RSA_set0_key(rsa, bnN, bnE, bnD) <= 0 || + RSA_set0_factors(rsa, bnP, bnQ) <= 0 || + RSA_set0_crt_params(rsa, bnDMP1, bnDMQ1, bnIQMP) <= 0) { + KAE_ThrowFromOpenssl(env, "RSA set param", KAE_ThrowRuntimeException); + goto err; + } + + // assign rsa to pkey + int result = EVP_PKEY_assign_RSA(pkey, rsa); + if (result <= 0) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_assign_RSA", KAE_ThrowRuntimeException); + goto err; + } + return (jlong)pkey; +err: + ReleaseRSAParams(bnN, bnE, bnD, bnP, bnQ, bnDMP1, bnDMQ1, bnIQMP); + RSA_free(rsa); + EVP_PKEY_free(pkey); + return 0; +} + +/* + * Create rsa public key + * Class: org_openeuler_security_openssl_KAERSACipher + * Method: nativeCreateRSAPublicKey + * Signature: ([B[B)J + */ +JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPublicKey( + JNIEnv* env, jclass cls, jbyteArray n, jbyteArray e) { + BIGNUM* bnN = NULL; + BIGNUM* bnE = NULL; + RSA* rsa = NULL; + EVP_PKEY* pkey = NULL; + + // get public key param n + bnN = KAE_GetBigNumFromByteArray(env, n); + if (bnN == NULL) { + goto err; + } + + // get public key param e + bnE = KAE_GetBigNumFromByteArray(env, e); + if (bnE == NULL) { + goto err; + } + + // new RSA + rsa = RSA_new(); + if (rsa == NULL) { + KAE_ThrowFromOpenssl(env, "RSA_new", KAE_ThrowRuntimeException); + goto err; + } + + // new EVP_PKEY + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowRuntimeException); + goto err; + } + + // set rsa public key params n and e + if(RSA_set0_key(rsa, bnN, bnE, NULL) <= 0) { + KAE_ThrowFromOpenssl(env, "RSA_set0_key", KAE_ThrowRuntimeException); + goto err; + } + + // assign rsa to pkey + int result = EVP_PKEY_assign_RSA(pkey, rsa); + if (result <= 0) { + KAE_ThrowFromOpenssl(env, "EVP_PKEY_assign_RSA", KAE_ThrowRuntimeException); + goto err; + } + return (jlong)pkey; +err: + KAE_ReleaseBigNumFromByteArray(bnN); + KAE_ReleaseBigNumFromByteArray(bnE); + RSA_free(rsa); + EVP_PKEY_free(pkey); + return 0; +} + +/* + * Class: org_openeuler_security_openssl_KAERSACipher + * Method: nativeRSAPrivateEncrypt + * Signature: (JI[B[BI)I + */ +JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPrivateEncrypt(JNIEnv* env, + jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { + return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_private_encrypt, + "RSA_private_encrypt"); +} + +/* + * Class: org_openeuler_security_openssl_KAERSACipher + * Method: nativeRSAPrivateDecrypt + * Signature: (JI[B[BI)I + */ +JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPrivateDecrypt(JNIEnv* env, + jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { + return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_private_decrypt, + "RSA_private_decrypt"); +} + +/* + * Class: org_openeuler_security_openssl_KAERSACipher + * Method: nativeRSAPublicEncrypt + * Signature: (JI[B[BI)I + */ +JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPublicEncrypt(JNIEnv* env, + jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { + return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_public_encrypt, + "RSA_public_encrypt"); +} + +/* + * Class: org_openeuler_security_openssl_KAERSACipher + * Method: nativeRSAPublicDecrypt + * Signature: (JI[B[BI)I + */ +JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPublicDecrypt(JNIEnv* env, + jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { + return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_public_decrypt, + "RSA_public_decrypt"); +} + +/* + * Class: org_openeuler_security_openssl_KAERSACipher + * Method: nativeRSAEncryptOAEPPading + * Signature: (JI[B[BI[B[B[B)I + */ +JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAEncryptOAEPPadding(JNIEnv* env, + jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, + jint paddingType,jstring oaepMdAlgo, jstring mgf1MdAlgo, jbyteArray label) { + return RSACryptOAEPPadding(env, keyAddress, inLen, in, out, paddingType, oaepMdAlgo, mgf1MdAlgo, label, + EVP_PKEY_encrypt_init, "EVP_PKEY_encrypt_init", + EVP_PKEY_encrypt, "EVP_PKEY_encrypt"); +} + +/* + * Class: org_openeuler_security_openssl_KAERSACipher + * Method: nativeRSADecryptOAEPPadding + * Signature: (JI[B[BILjava/lang/String;Ljava/lang/String;[B)I + */ +JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSADecryptOAEPPadding(JNIEnv* env, + jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType, + jstring oaepMdAlgo, jstring mgf1MdAlgo, jbyteArray label) { + return RSACryptOAEPPadding(env, keyAddress, inLen, in, out, paddingType, oaepMdAlgo, mgf1MdAlgo, label, + EVP_PKEY_decrypt_init, "EVP_PKEY_decrypt_init", + EVP_PKEY_decrypt, "EVP_PKEY_decrypt"); +} + +/* + * Class: org_openeuler_security_openssl_KAERSACipher + * Method: nativeFreeKey + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeFreeKey(JNIEnv* env, + jclass cls, jlong keyAddress) { + EVP_PKEY* pkey = (EVP_PKEY*) keyAddress; + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } +} diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c new file mode 100644 index 00000000..6ae14969 --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +#include <openssl/evp.h> +#include <openssl/md5.h> +#include "kae_log.h" +#include "kae_exception.h" +#include "org_openeuler_security_openssl_KAEDigest.h" + +#define DIGEST_STACK_SIZE 1024 +#define DIGEST_CHUNK_SIZE 64*1024 +#define DIGEST_LENGTH_THRESHOLD 48 + +/* + * Class: org_openeuler_security_openssl_KAEDigest + * Method: nativeInit + * Signature: (Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL +Java_org_openeuler_security_openssl_KAEDigest_nativeInit(JNIEnv *env, jclass cls, jstring algorithmName) +{ + EVP_MD_CTX* ctx = NULL; + + if (algorithmName == NULL) { + KAE_ThrowNullPointerException(env, "algorithm is null"); + return 0; + } + + // EVP_get_digestbyname + const char* algo_utf = (*env)->GetStringUTFChars(env, algorithmName, 0); + EVP_MD* md = (EVP_MD*) EVP_get_digestbyname(algo_utf); + (*env)->ReleaseStringUTFChars(env, algorithmName, algo_utf); + if (md == NULL) { + KAE_TRACE("%s not supported", algo_utf); + return 0; + } + KAE_TRACE("KAEDigest_nativeInit: create md => %p", md); + + ctx = EVP_MD_CTX_create(); + if (ctx == NULL) { + KAE_ThrowOOMException(env, "create EVP_MD_CTX fail"); + return 0; + } + KAE_TRACE("KAEDigest_nativeInit: create ctx => %p", ctx); + + // EVP_DigestInit_ex + int result_code = EVP_DigestInit_ex(ctx, md, NULL); + if (result_code == 0) { + KAE_ThrowFromOpenssl(env, "EVP_DigestInit_ex failed", KAE_ThrowRuntimeException); + goto err; + } + KAE_TRACE("KAEDigest_nativeInit EVP_DigestInit_ex(ctx = %p, md = %p) success", ctx, md); + + KAE_TRACE("KAEDigest_nativeInit: finished"); + return (jlong) ctx; + +err: + EVP_MD_CTX_destroy(ctx); + return 0; +} + +/* + * Class: org_openeuler_security_openssl_KAEDigest + * Method: nativeUpdate + * Signature: (Ljava/lang/String;J[BII)I + */ +JNIEXPORT void JNICALL +Java_org_openeuler_security_openssl_KAEDigest_nativeUpdate(JNIEnv *env, jclass cls, jlong ctxAddress, + jbyteArray input, jint offset, jint inLen) +{ + EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; + KAE_TRACE("KAEDigest_nativeUpdate(ctx = %p, input = %p, offset = %d, inLen = %d", ctx, input, offset, inLen); + if (ctx == NULL) { + return; + } + + jint in_offset = offset; + jint in_size = inLen; + int result_code = 0; + if (in_size <= DIGEST_STACK_SIZE) { // allocation on the stack + jbyte buffer[DIGEST_STACK_SIZE]; + (*env)->GetByteArrayRegion(env, input, offset, inLen, buffer); + result_code = EVP_DigestUpdate(ctx, buffer, inLen); + } else { // data chunk + jint remaining = in_size; + jint buf_size = (remaining >= DIGEST_CHUNK_SIZE) ? DIGEST_CHUNK_SIZE : remaining; + jbyte* buffer = malloc(buf_size); + if (buffer == NULL) { + KAE_ThrowOOMException(env, "malloc error"); + return; + } + while (remaining > 0) { + jint chunk_size = (remaining >= buf_size) ? buf_size : remaining; + (*env)->GetByteArrayRegion(env, input, in_offset, chunk_size, buffer); + result_code = EVP_DigestUpdate(ctx, buffer, chunk_size); + if (!result_code) { + break; + } + in_offset += chunk_size; + remaining -= chunk_size; + } + free(buffer); + } + if (!result_code) { + KAE_ThrowFromOpenssl(env, "EVP_DigestUpdate failed", KAE_ThrowRuntimeException); + return; + } + KAE_TRACE("KAEDigest_nativeUpdate EVP_DigestUpdate success"); + KAE_TRACE("KAEDigest_nativeUpdate: finished"); +} + +/* + * Class: org_openeuler_security_openssl_KAEDigest + * Method: nativeDigest + * Signature: (Ljava/lang/String;J[BII)I + */ +JNIEXPORT jint JNICALL +Java_org_openeuler_security_openssl_KAEDigest_nativeDigest(JNIEnv *env, jclass cls, + jlong ctxAddress, jbyteArray output, jint offset, jint len) +{ + EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; + KAE_TRACE("KAEDigest_nativeDigest(ctx = %p, output = %p, offset = %d, len = %d", ctx, output, offset, len); + unsigned char* md = NULL; + unsigned int bytesWritten = 0; + + if (ctx == NULL) { + return 0; + } + + if (len <= 0 || len > DIGEST_LENGTH_THRESHOLD) { + KAE_ThrowRuntimeException(env, "len out of length"); + return 0; + } + md = malloc(len); + if (md == NULL) { + KAE_ThrowOOMException(env, "malloc error"); + return 0; + } + + // EVP_DigestFinal_ex + int result_code = EVP_DigestFinal_ex(ctx, md, &bytesWritten); + if (result_code == 0) { + KAE_ThrowFromOpenssl(env, "EVP_DigestFinal_ex failed", KAE_ThrowRuntimeException); + goto cleanup; + } + KAE_TRACE("KAEDigest_nativeFinal EVP_DigestFinal_ex success, bytesWritten = %d", bytesWritten); + + (*env)->SetByteArrayRegion(env, output, offset, bytesWritten, (jbyte*) md); + + KAE_TRACE("KAEDigest_nativeFinal: finished"); + +cleanup: + free(md); + return bytesWritten; +} + +/* +* Class: org_openeuler_security_openssl_KAEDigest +* Method: nativeClone +* Signature: (J)J +*/ +JNIEXPORT jlong JNICALL +Java_org_openeuler_security_openssl_KAEDigest_nativeClone(JNIEnv *env, jclass cls, jlong ctxAddress) +{ + EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; + KAE_TRACE("KAEDigest_nativeClone: ctx = %p", ctx); + if (ctx == NULL) { + return 0; + } + + EVP_MD_CTX* ctxCopy = EVP_MD_CTX_create(); + if (ctxCopy == NULL) { + KAE_ThrowOOMException(env, "create EVP_MD_CTX fail"); + return 0; + } + KAE_TRACE("KAEDigest_nativeClone: create ctxCopy => %p", ctxCopy); + + int result_code = EVP_MD_CTX_copy_ex(ctxCopy, ctx); + if (result_code == 0) { + KAE_ThrowFromOpenssl(env, "EVP_MD_CTX_copy_ex failed", KAE_ThrowRuntimeException); + goto err; + } + KAE_TRACE("KAEDigest_nativeClone EVP_MD_CTX_copy_ex(ctxCopy = %p, ctx = %p) success", ctxCopy, ctx); + KAE_TRACE("KAEDigest_nativeClone: finished"); + return (jlong) ctxCopy; + +err: + EVP_MD_CTX_destroy(ctxCopy); + return 0; +} + +/* + * Class: org_openeuler_security_openssl_KAEDigest + * Method: nativeFree + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_org_openeuler_security_openssl_KAEDigest_nativeFree(JNIEnv *env, jclass cls, jlong ctxAddress) +{ + EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; + KAE_TRACE("KAEDigest_nativeFree(ctx = %p)", ctx); + if (ctx != NULL) { + EVP_MD_CTX_destroy(ctx); + } + + KAE_TRACE("KAEDigest_nativeFree: finished"); +} diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.c new file mode 100644 index 00000000..b1a29334 --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +#include <openssl/evp.h> +#include <openssl/err.h> +#include "kae_util.h" +#include "kae_log.h" +#include "kae_exception.h" + +void KAE_ThrowByName(JNIEnv* env, const char* name, const char* msg) { + jclass cls = (*env)->FindClass(env, name); + if (cls != 0) { + (*env)->ThrowNew(env, cls, msg); + (*env)->DeleteLocalRef(env, cls); + } +} + +void KAE_ThrowOOMException(JNIEnv* env, const char* msg) { + KAE_ThrowByName(env, "java/lang/OutOfMemoryError", msg); +} + +void KAE_ThrowNullPointerException(JNIEnv* env, const char* msg) { + KAE_ThrowByName(env, "java/lang/NullPointerException", msg); +} + +void KAE_ThrowArrayIndexOutOfBoundsException(JNIEnv* env, const char* msg) { + KAE_ThrowByName(env, "java/lang/ArrayIndexOutOfBoundsException", msg); +} + +void KAE_ThrowEvpException(JNIEnv* env, int reason, const char* msg, void (* defaultException)(JNIEnv*, const char*)) { + switch (reason) { + case EVP_R_UNSUPPORTED_ALGORITHM: + KAE_ThrowByName(env, "java/security/NoSuchAlgorithmException", msg); + break; + case EVP_R_MISSING_PARAMETERS: + KAE_ThrowByName(env, "java/security/InvalidKeyException", msg); + break; + case EVP_R_BAD_DECRYPT: + KAE_ThrowByName(env, "javax/crypto/BadPaddingException", msg); + break; + default: + defaultException(env, msg); + break; + } +} + +void KAE_ThrowRuntimeException(JNIEnv* env, const char* msg) { + KAE_ThrowByName(env, "java/lang/RuntimeException", msg); +} + +void KAE_ThrowBadPaddingException(JNIEnv* env, const char* msg) { + KAE_ThrowByName(env, "javax/crypto/BadPaddingException", msg); +} + +void KAE_ThrowInvalidKeyException(JNIEnv* env, const char* msg) { + KAE_ThrowByName(env, "java/security/InvalidKeyException", msg); +} + +void KAE_ThrowInvalidAlgorithmParameterException(JNIEnv* env, const char* msg) { + KAE_ThrowByName(env, "java/security/InvalidAlgorithmParameterException", msg); +} + +void KAE_ThrowFromOpenssl(JNIEnv* env, const char* msg, void (* defaultException)(JNIEnv*, const char*)) { + const char* file = NULL; + const char* data = NULL; + int line = 0; + int flags = 0; + unsigned long err; + static const int ESTRING_SIZE = 256; + + err = ERR_get_error_line_data(&file, &line, &data, &flags); + if (err == 0) { + KAE_ThrowRuntimeException(env, "Unknown OpenSSL error"); + return; + } + + if (!(*env)->ExceptionCheck(env)) { + char estring[ESTRING_SIZE]; + ERR_error_string_n(err, estring, ESTRING_SIZE); + int lib = ERR_GET_LIB(err); + int reason = ERR_GET_REASON(err); + KAE_TRACE("OpenSSL error in %s: err=%lx, lib=%x, reason=%x, file=%s, line=%d, estring=%s, data=%s", msg, err, + lib, reason, file, line, estring, (flags & ERR_TXT_STRING) ? data : "(no data)"); + + switch (lib) { + case ERR_LIB_EVP: + KAE_ThrowEvpException(env, reason, estring, defaultException); + break; + default: + defaultException(env, estring); + break; + } + } + + ERR_clear_error(); +} diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.h b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.h new file mode 100644 index 00000000..f528ad4a --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +#ifndef KAE_EXCEPTION_H +#define KAE_EXCEPTION_H + +#include <jni.h> + +/* Throw a Java exception by name */ +void KAE_ThrowByName(JNIEnv* env, const char* name, const char* msg); + +void KAE_ThrowOOMException(JNIEnv* env, const char* msg); + +void KAE_ThrowNullPointerException(JNIEnv* env, const char* msg); + +void KAE_ThrowArrayIndexOutOfBoundsException(JNIEnv* env, const char* msg); + +void KAE_ThrowFromOpenssl(JNIEnv* env, const char* msg, void (* defaultException)(JNIEnv*, const char*)); + +void KAE_ThrowEvpException(JNIEnv* env, int reason, const char* msg, void (* defaultException)(JNIEnv*, const char*)); + +void KAE_ThrowRuntimeException(JNIEnv* env, const char* msg); + +void KAE_ThrowBadPaddingException(JNIEnv* env, const char* msg); + +/* Throw InvalidKeyException */ +void KAE_ThrowInvalidKeyException(JNIEnv* env, const char* msg); + +/* Throw AlgorithmParameterException */ +void KAE_ThrowInvalidAlgorithmParameterException(JNIEnv* env, const char* msg); + +#endif diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c new file mode 100644 index 00000000..01848c0e --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ +#include <openssl/rsa.h> +#include "kae_util.h" +#include "kae_exception.h" +#include "org_openeuler_security_openssl_KAERSAKeyPairGenerator.h" +#define KAE_RSA_PARAM_SIZE 8 +#define SUCCESS 1 +#define FAILED -1 + + +// rsa param index +typedef enum RSAParamIndex { + rsa_n = 0, + rsa_e = 1, + rsa_d = 2, + rsa_p = 3, + rsa_q = 4, + rsa_dmp1 = 5, + rsa_dmq1 = 6, + rsa_iqmp = 7 +} RSAParamIndex; + +// rsa param name array +static const char* RSAParamNames[] = {"n", "e", "d", "p", "q", "dmp1", "dmq1", "iqmp"}; + +// rsa get rsa param function list +static const BIGNUM* (* GetRSAParamFunctionList[])(const RSA*) = { + RSA_get0_n, + RSA_get0_e, + RSA_get0_d, + RSA_get0_p, + RSA_get0_q, + RSA_get0_dmp1, + RSA_get0_dmq1, + RSA_get0_iqmp +}; + +/* + * New RSA and generate rsa key, follow the steps below + * step 1.New RSA + * step 2.Convert publicExponent to BIGNUM + * step 3.Generate rsa key, and all key information is stored in RSA + */ +static RSA* NewRSA(JNIEnv* env, jint keySize, jbyteArray publicExponent) { + // RSA_new + RSA* rsa = RSA_new(); + if (rsa == NULL) { + KAE_ThrowFromOpenssl(env, "RSA_new", KAE_ThrowRuntimeException); + return NULL; + } + + // convert publicExponent to BIGNUM + BIGNUM* exponent = KAE_GetBigNumFromByteArray(env, publicExponent); + if (exponent == NULL) { + return NULL; + } + + // generate rsa key + int result_code = RSA_generate_key_ex(rsa, keySize, exponent, NULL); + KAE_ReleaseBigNumFromByteArray(exponent); + if (result_code <= 0) { + RSA_free(rsa); + KAE_ThrowFromOpenssl(env, "RSA_generate_key_ex", KAE_ThrowRuntimeException); + return NULL; + } + return rsa; +} + +/* + * release RSA + */ +static void ReleaseRSA(RSA* rsa) { + if (rsa != NULL) { + RSA_free(rsa); + } +} + +/* + * Set rsa key param, follow the steps below + * step 1. Get rsa param name + * step 2. Get rsa param value + * step 3. Convert paramValue (BIGNUM) to jbyteArray + * step 4. Set the rsa param to the param array + */ +static int SetRSAKeyParam(JNIEnv* env, RSA* rsa, jobjectArray params, RSAParamIndex rsaParamIndex) { + // get rsa param name + const char* rsaParamName = RSAParamNames[rsaParamIndex]; + + // get rsa param value + const BIGNUM* rsaParamValue = GetRSAParamFunctionList[rsaParamIndex](rsa); + if (rsaParamValue == NULL) { + return FAILED; + } + + // Convert paramValue to jbyteArray + jbyteArray param = KAE_GetByteArrayFromBigNum(env, rsaParamValue, rsaParamName); + if (param == NULL) { + return FAILED; + } + + // Set the rsa param to the param array + (*env)->SetObjectArrayElement(env, params, rsaParamIndex, param); + return SUCCESS; +} + +/* + * New rsa key params, follow the steps below + * step 1. New rsa key param array + * step 2. Set rsa key param + */ +static jobjectArray NewRSAKeyParams(JNIEnv* env, RSA* rsa) { + // new param array + jclass byteArrayClass = (*env)->FindClass(env, "[B"); + jobjectArray params = (*env)->NewObjectArray(env, KAE_RSA_PARAM_SIZE, byteArrayClass, NULL); + if (params == NULL) { + KAE_ThrowOOMException(env, "failed to allocate array"); + return NULL; + } + + // set rsa key param + for (RSAParamIndex paramIndex = rsa_n; paramIndex <= rsa_iqmp; paramIndex++) { + if (SetRSAKeyParam(env, rsa, params, paramIndex) == FAILED) { + return NULL; + } + } + return params; +} + +/* + * Class: org_openeuler_security_openssl_KAERSAKeyPairGenerator + * Method: nativeGenerateKeyPair + * Signature: (I[B)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_openeuler_security_openssl_KAERSAKeyPairGenerator_nativeGenerateKeyPair + (JNIEnv* env, jclass cls, jint keySize, jbyteArray publicExponent) { + if (publicExponent == NULL) { + return NULL; + } + + // new RSA + RSA* rsa = NewRSA(env, keySize, publicExponent); + if (rsa == NULL) { + return NULL; + } + + // new RSA Key Parameters + jobjectArray rsaParm = NewRSAKeyParams(env, rsa); + + // release rsa + ReleaseRSA(rsa); + return rsaParm; +} diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_log.h b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_log.h new file mode 100644 index 00000000..d8d9c7b3 --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_log.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +#ifndef KAE_LOG_H +#define KAE_LOG_H + +#ifdef KAE_DEBUG +#define KAE_TRACE(...) { fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); } +#else +#define KAE_TRACE(...) +#endif + +#endif diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_mac.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_mac.c new file mode 100644 index 00000000..2df2a9cb --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_mac.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +#include <jni.h> +#include <openssl/hmac.h> +#include "kae_exception.h" +#include "kae_log.h" + +static const EVP_MD* EVPGetDigestByName(JNIEnv* env, const char* algo) +{ + static const EVP_MD* md5 = NULL; + static const EVP_MD* sha1 = NULL; + static const EVP_MD* sha224 = NULL; + static const EVP_MD* sha256 = NULL; + static const EVP_MD* sha384 = NULL; + static const EVP_MD* sha512 = NULL; + + if (strcasecmp(algo, "md5") == 0) { + return md5 == NULL ? md5 = EVP_get_digestbyname(algo) : md5; + } else if (strcasecmp(algo, "sha1") == 0) { + return sha1 == NULL ? sha1 = EVP_get_digestbyname(algo) : sha1; + } else if (strcasecmp(algo, "sha224") == 0) { + return sha224 == NULL ? sha224 = EVP_get_digestbyname(algo) : sha224; + } else if (strcasecmp(algo, "sha256") == 0) { + return sha256 == NULL ? sha256 = EVP_get_digestbyname(algo) : sha256; + } else if (strcasecmp(algo, "sha384") == 0) { + return sha384 == NULL ? sha384 = EVP_get_digestbyname(algo) : sha384; + } else if (strcasecmp(algo, "sha512") == 0) { + return sha512 == NULL ? sha512 = EVP_get_digestbyname(algo) : sha512; + } else { + KAE_ThrowRuntimeException(env, "EVPGetDigestByName error"); + return 0; + } +} + +/* + * Class: org_openeuler_security_openssl_KAEMac + * Method: nativeInit + * Signature: ([BILjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAEMac_nativeInit + (JNIEnv* env, jclass cls, jbyteArray key, jint key_len, jstring algoStr) { + if (key == NULL || algoStr == NULL) { + KAE_ThrowNullPointerException(env, "param key or algoStr is null"); + return 0; + } + if (key_len <= 0) { + KAE_ThrowArrayIndexOutOfBoundsException(env, "key"); + return 0; + } + HMAC_CTX* ctx = NULL; + jbyte* key_buffer = NULL; + const EVP_MD* md = NULL; + + const char* algo = (*env)->GetStringUTFChars(env, algoStr, 0); + md = EVPGetDigestByName(env, algo); + (*env)->ReleaseStringUTFChars(env, algoStr, algo); + if (md == NULL) { + KAE_ThrowRuntimeException(env, "algorithm unsupport"); + return 0; + } + + // get secret-key + key_buffer = malloc(key_len); + if (key_buffer == NULL) { + KAE_ThrowOOMException(env, "malloc failed"); + return 0; + } + (*env)->GetByteArrayRegion(env, key, 0, key_len, key_buffer); + + // create a hmac context + ctx = HMAC_CTX_new(); + if (ctx == NULL) { + KAE_ThrowRuntimeException(env, "Hmac_CTX_new invoked failed"); + goto err; + } + + // init hmac context with sc_key and evp_md + int result_code = HMAC_Init_ex(ctx, key_buffer, key_len, md, NULL); + if (result_code == 0) { + KAE_ThrowRuntimeException(env, "Hmac_Init_ex invoked failed"); + goto err; + } + free(key_buffer); + return (jlong) ctx; + +err: + free(key_buffer); + HMAC_CTX_free(ctx); + return 0; +} + +/* + * Class: org_openeuler_security_openssl_KAEMac + * Method: nativeUpdate + * Signature: (J[BII)V + */ +JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEMac_nativeUpdate + (JNIEnv* env, jclass cls, jlong hmac_ctx, jbyteArray input, jint in_offset, jint in_len) { + KAE_TRACE("KAEMac_nativeUpdate(ctx = %p, input = %p, offset = %d, inLen = %d", hmac_ctx, input, in_offset, in_len); + HMAC_CTX* ctx = (HMAC_CTX*) hmac_ctx; + if (ctx == NULL || input == NULL) { + KAE_ThrowNullPointerException(env, "param ctx or input is null"); + return; + } + int input_size = (*env)->GetArrayLength(env, input); + if ((in_offset < 0) || (in_len < 0) || (in_offset > input_size - in_len)) { + KAE_ThrowArrayIndexOutOfBoundsException(env, "input"); + return; + } + // do nothing while in_len is 0 + if (in_len == 0) { + return; + } + + jbyte* buffer = malloc(in_len); + if (buffer == NULL) { + KAE_ThrowOOMException(env, "malloc failed"); + return; + } + (*env)->GetByteArrayRegion(env, input, in_offset, in_len, buffer); + if (!HMAC_Update(ctx, (unsigned char*) buffer, in_len)) { + KAE_ThrowRuntimeException(env, "Hmac_Update invoked failed"); + } + free(buffer); +} + +/* + * Class: org_openeuler_security_openssl_KAEMac + * Method: nativeFinal + * Signature: (J[BII)I + */ +JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAEMac_nativeFinal + (JNIEnv* env, jclass cls, jlong hmac_ctx, jbyteArray output, jint out_offset, jint in_len) { + HMAC_CTX* ctx = (HMAC_CTX*) hmac_ctx; + if (ctx == NULL || output == NULL) { + KAE_ThrowNullPointerException(env, "param ctx or input is null"); + return 0; + } + int output_size = (*env)->GetArrayLength(env, output); + if ((out_offset < 0) || (in_len < 0) || (out_offset > output_size - in_len)) { + KAE_ThrowArrayIndexOutOfBoundsException(env, "output"); + return 0; + } + + jbyte* temp_result = NULL; + + temp_result = malloc(in_len); + if (temp_result == NULL) { + KAE_ThrowOOMException(env, "malloc failed"); + return 0; + } + // do final + unsigned int bytesWritten = 0; + int result_code = HMAC_Final(ctx, (unsigned char*) temp_result, &bytesWritten); + if (result_code == 0) { + KAE_ThrowRuntimeException(env, "Hmac_Final invoked failed"); + goto cleanup; + } + + // write back to output_array + (*env)->SetByteArrayRegion(env, output, out_offset, bytesWritten, (jbyte*) temp_result); + KAE_TRACE("KAEMac_nativeFinal success, output_offset = %d, bytesWritten = %d", out_offset, bytesWritten); + +cleanup: + free(temp_result); + return bytesWritten; +} + +/* + * Class: org_openeuler_security_openssl_KAEMac + * Method: nativeFree + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEMac_nativeFree + (JNIEnv* env, jclass cls, jlong hmac_ctx) { + HMAC_CTX* ctx = (HMAC_CTX*) hmac_ctx; + if (ctx != NULL) { + HMAC_CTX_free(ctx); + } +} diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c new file mode 100644 index 00000000..cfd2480e --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +#include <openssl/bio.h> +#include <openssl/ssl.h> +#include <openssl/engine.h> +#include "kae_exception.h" +#include "org_openeuler_security_openssl_KAEProvider.h" +/* + * Class: org_openeuler_security_openssl_WdProvider + * Method: initOpenssl + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEProvider_initOpenssl + (JNIEnv *env, jclass cls) { + SSL_load_error_strings(); + ERR_load_BIO_strings(); + OpenSSL_add_all_algorithms(); + + // determine whether KAE is loaded successfully + ENGINE *e = ENGINE_by_id("kae"); + if (e == NULL) { + KAE_ThrowRuntimeException(env, "kae engine not found"); + return; + } + ENGINE_free(e); +} diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c new file mode 100644 index 00000000..4e4c31ec --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +#include <openssl/evp.h> +#include "kae_util.h" +#include "kae_exception.h" + + +BIGNUM* KAE_GetBigNumFromByteArray(JNIEnv* env, jbyteArray byteArray) { + if (byteArray == NULL) { + KAE_ThrowNullPointerException(env, "KAE_GetBigNumFromByteArray byteArray is null"); + return NULL; + } + + jsize len = (*env)->GetArrayLength(env, byteArray); + if (len == 0) { + KAE_ThrowRuntimeException(env, "KAE_GetBigNumFromByteArray byteArray is empty"); + return NULL; + } + + BIGNUM* bn = BN_new(); + if (bn == NULL) { + KAE_ThrowFromOpenssl(env, "BN_new", KAE_ThrowRuntimeException); + return NULL; + } + + jbyte* bytes = (*env)->GetByteArrayElements(env, byteArray, NULL); + if (bytes == NULL) { + KAE_ThrowNullPointerException(env,"GetByteArrayElements failed"); + goto error; + } + BIGNUM* result = BN_bin2bn((const unsigned char*) bytes, len, bn); + (*env)->ReleaseByteArrayElements(env, byteArray, bytes, 0); + if (result == NULL) { + KAE_ThrowFromOpenssl(env, "BN_bin2bn", KAE_ThrowRuntimeException); + goto error; + } + return bn; + +error: + BN_free(bn); + return NULL; +} + +void KAE_ReleaseBigNumFromByteArray(BIGNUM* bn) { + if (bn != NULL) { + BN_free(bn); + } +} + +jbyteArray KAE_GetByteArrayFromBigNum(JNIEnv* env, const BIGNUM* bn, const char* sourceName) { + if (bn == NULL) { + return NULL; + } + // bn size need plus 1, for example 65535 , BN_num_bytes return 2 + int bnSize = BN_num_bytes(bn); + if (bnSize <= 0) { + return NULL; + } + bnSize += 1; + jbyteArray javaBytes = (*env)->NewByteArray(env, bnSize); + if (javaBytes == NULL) { + KAE_ThrowOOMException(env, "new byte array failed"); + return NULL; + } + jbyte* bytes = (*env)->GetByteArrayElements(env, javaBytes, NULL); + if (bytes == NULL) { + KAE_ThrowNullPointerException(env,"GetByteArrayElements failed"); + return NULL; + } + unsigned char* tmp = (unsigned char*) bytes; + if (BN_bn2bin(bn, tmp + 1) <= 0) { + KAE_ThrowFromOpenssl(env, "BN_bn2bin", KAE_ThrowRuntimeException); + javaBytes = NULL; + goto cleanup; + } + (*env)->SetByteArrayRegion(env, javaBytes, 0, bnSize, bytes); + +cleanup: + (*env)->ReleaseByteArrayElements(env, javaBytes, bytes, 0); + return javaBytes; +} diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h new file mode 100644 index 00000000..35715e1c --- /dev/null +++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +#ifndef KAE_UTIL_H +#define KAE_UTIL_H + +#include <openssl/bn.h> +#include <jni.h> + +/* jbyteArray convert to BIGNUM */ +BIGNUM* KAE_GetBigNumFromByteArray(JNIEnv* env, jbyteArray byteArray); + +/* release BIGNUM allocat from */ +void KAE_ReleaseBigNumFromByteArray(BIGNUM* bn); + +/* BIGNUM convert to jbyteArray */ +jbyteArray KAE_GetByteArrayFromBigNum(JNIEnv* env, const BIGNUM* bn, const char* sourceName); + +#endif diff --git a/jdk/test/java/net/URLPermission/policy.1 b/jdk/test/java/net/URLPermission/policy.1 index 5816cdbf..40bb7258 100644 --- a/jdk/test/java/net/URLPermission/policy.1 +++ b/jdk/test/java/net/URLPermission/policy.1 @@ -34,6 +34,7 @@ grant { //permission "java.io.FilePermission" "/tmp/-", "read,write"; permission "java.lang.RuntimePermission" "modifyThread"; permission "java.lang.RuntimePermission" "setFactory"; + permission "java.util.PropertyPermission" "kae.disableKaeDispose", "read"; }; // Normal permissions that aren't granted when run under jtreg diff --git a/jdk/test/java/net/URLPermission/policy.2 b/jdk/test/java/net/URLPermission/policy.2 index d1d774f4..21345c53 100644 --- a/jdk/test/java/net/URLPermission/policy.2 +++ b/jdk/test/java/net/URLPermission/policy.2 @@ -34,6 +34,7 @@ grant { //permission "java.io.FilePermission" "/tmp/-", "read,write"; permission "java.lang.RuntimePermission" "modifyThread"; permission "java.lang.RuntimePermission" "setFactory"; + permission "java.util.PropertyPermission" "kae.disableKaeDispose", "read"; }; grant codeBase "file:${{java.ext.dirs}}/*" { diff --git a/jdk/test/java/net/URLPermission/policy.3 b/jdk/test/java/net/URLPermission/policy.3 index 47f213fa..d86617f7 100644 --- a/jdk/test/java/net/URLPermission/policy.3 +++ b/jdk/test/java/net/URLPermission/policy.3 @@ -34,6 +34,7 @@ grant { //permission "java.io.FilePermission" "/tmp/-", "read,write"; permission "java.lang.RuntimePermission" "modifyThread"; permission "java.lang.RuntimePermission" "setFactory"; + permission "java.util.PropertyPermission" "kae.disableKaeDispose", "read"; }; // Normal permissions that aren't granted when run under jtreg diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java new file mode 100644 index 00000000..0034b67c --- /dev/null +++ b/jdk/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ +package org.openeuler.bench.security.openssl; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.Warmup; + +import java.security.InvalidKeyException; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.util.concurrent.TimeUnit; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.SecretKeySpec; + +@Warmup(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS) +public class AESBenchmark extends BenchmarkBase { + + @Param({"AES/ECB/PKCS5Padding", "AES/ECB/NoPadding", "AES/CBC/NoPadding", "AES/CBC/PKCS5Padding", "AES/CTR/NoPadding"}) + private String algorithm; + + @Param({"128", "192", "256"}) + private int keyLength; + + @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) + private int dataSize; + + private byte[][] encryptedData; + private Cipher encryptCipher; + private Cipher decryptCipher; + + @Setup + public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, + InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + setupProvider(); + + byte[] keystring = fillSecureRandom(new byte[keyLength / 8]); + SecretKeySpec ks = new SecretKeySpec(keystring, "AES"); + + encryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); + encryptCipher.init(Cipher.ENCRYPT_MODE, ks); + decryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); + decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); + + data = fillRandom(new byte[SET_SIZE][dataSize]); + encryptedData = fillEncrypted(data, encryptCipher); + } + + @Benchmark + public byte[] encrypt() throws IllegalBlockSizeException, BadPaddingException { + byte[] d = data[index]; + index = (index + 1) % SET_SIZE; + return encryptCipher.doFinal(d); + } + + @Benchmark + @Fork(jvmArgsAppend = {"-Dkae.disableKaeDispose=true"}) + public byte[] encryptDispose() throws IllegalBlockSizeException, BadPaddingException { + byte[] d = data[index]; + index = (index + 1) % SET_SIZE; + return encryptCipher.doFinal(d); + } + + @Benchmark + public byte[] decrypt() throws IllegalBlockSizeException, BadPaddingException { + byte[] e = encryptedData[index]; + index = (index + 1) % SET_SIZE; + return decryptCipher.doFinal(e); + } + + @Benchmark + @Fork(jvmArgsAppend = {"-Dkae.disableKaeDispose=true"}) + public byte[] decryptDispose() throws IllegalBlockSizeException, BadPaddingException { + byte[] e = encryptedData[index]; + index = (index + 1) % SET_SIZE; + return decryptCipher.doFinal(e); + } +} + diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java b/jdk/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java new file mode 100644 index 00000000..41c56e49 --- /dev/null +++ b/jdk/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ +package org.openeuler.bench.security.openssl; + +import org.openeuler.security.openssl.KAEProvider; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 2, timeUnit = TimeUnit.SECONDS) +@Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch"}, value = 1) +@Threads(1) +@State(Scope.Thread) +public class BenchmarkBase { + public static final int SET_SIZE = 128; + + byte[][] data; + int index = 0; + + @Param({"", "KAEProvider"}) + private String provider; + + public Provider prov = null; + + @Setup + public void setupProvider() { + Security.addProvider(new KAEProvider()); + if (provider != null && !provider.isEmpty()) { + prov = Security.getProvider(provider); + if (prov == null) { + throw new RuntimeException("Can't find provider \"" + provider + "\""); + } + } + } + + public static byte[][] fillRandom(byte[][] data) { + Random rnd = new Random(); + for (byte[] d : data) { + rnd.nextBytes(d); + } + return data; + } + + public static byte[] fillSecureRandom(byte[] data) { + SecureRandom rnd = new SecureRandom(); + rnd.nextBytes(data); + return data; + } + + public static byte[][] fillEncrypted(byte[][] data, Cipher encryptCipher) + throws IllegalBlockSizeException, BadPaddingException { + byte[][] encryptedData = new byte[data.length][]; + for (int i = 0; i < encryptedData.length; i++) { + encryptedData[i] = encryptCipher.doFinal(data[i]); + } + return encryptedData; + } + +} diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/DigestBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/DigestBenchmark.java new file mode 100644 index 00000000..96d2a24f --- /dev/null +++ b/jdk/test/micro/org/openeuler/bench/security/openssl/DigestBenchmark.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ +package org.openeuler.bench.security.openssl; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Setup; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.util.concurrent.TimeUnit; + +public class DigestBenchmark extends BenchmarkBase { + + @Param({"MD5", "SHA-256", "SHA-384"}) + private String algorithm; + + @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) + int dataSize; + + MessageDigest md; + + @Setup + public void setup() throws NoSuchAlgorithmException { + setupProvider(); + data = fillRandom(new byte[SET_SIZE][dataSize]); + md = (prov == null) ? MessageDigest.getInstance(algorithm) : MessageDigest.getInstance(algorithm, prov); + } + + @Benchmark + public byte[] digest() { + byte[] d = data[index]; + index = (index + 1) % SET_SIZE; + return md.digest(d); + } + + @Benchmark + @Fork(jvmArgsAppend = {"-Dkae.disableKaeDispose=true"}) + public byte[] digestDispose() { + byte[] d = data[index]; + index = (index + 1) % SET_SIZE; + return md.digest(d); + } +} + diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java new file mode 100644 index 00000000..584484f3 --- /dev/null +++ b/jdk/test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ +package org.openeuler.bench.security.openssl; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Setup; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.util.concurrent.TimeUnit; + +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; + +public class HMacBenchmark extends BenchmarkBase { + + @Param({"HmacMD5", "HmacSHA1", "HmacSHA224", "HmacSHA256", "HmacSHA384", "HmacSHA512"}) + private String algorithm; + + @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) + private int dataSize; + + private Mac mac; + + @Setup + public void setup() throws NoSuchAlgorithmException, InvalidKeyException { + setupProvider(); + mac = (prov == null) ? Mac.getInstance(algorithm) : Mac.getInstance(algorithm, prov); + mac.init(KeyGenerator.getInstance(algorithm).generateKey()); + data = fillRandom(new byte[SET_SIZE][dataSize]); + } + + @Benchmark + public byte[] mac() { + byte[] d = data[index]; + index = (index + 1) % SET_SIZE; + return mac.doFinal(d); + } + + @Benchmark + @Fork(jvmArgsAppend = {"-Dkae.disableKaeDispose=true"}) + public byte[] macDispose() { + byte[] d = data[index]; + index = (index + 1) % SET_SIZE; + return mac.doFinal(d); + } +} + diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/RSACipherBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/RSACipherBenchmark.java new file mode 100644 index 00000000..2a5eb9c7 --- /dev/null +++ b/jdk/test/micro/org/openeuler/bench/security/openssl/RSACipherBenchmark.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +package org.openeuler.bench.security.openssl; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Setup; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; + +public class RSACipherBenchmark extends BenchmarkBase { + @Param({"RSA/ECB/NoPadding", "RSA/ECB/PKCS1Padding", "RSA/ECB/OAEPPadding"}) + private String algorithm; + + @Param({"512", "1024", "2048", "3072", "4096"}) + private int keyLength; + + @Param({"true", "false"}) + private boolean encryptPublicKey; + + private byte[][] data; + private byte[][] encryptedData; + + private Cipher encryptCipher; + private Cipher decryptCipher; + private int index = 0; + + private int getMaxDataSize(int keyLength, String algorithm) { + int dataSize = keyLength / 8; + if ("RSA/ECB/PKCS1Padding".equals(algorithm)) { + return dataSize - 11; + } + + if ("RSA/ECB/OAEPPadding".equals(algorithm)) { + // SHA-1 digestLen is 20 + int digestLen = 20; + return dataSize - 2 - 2 * digestLen; + } + return dataSize; + } + + @Setup() + public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + setupProvider(); + + int dataSize = getMaxDataSize(keyLength, algorithm); + data = fillRandom(new byte[SET_SIZE][dataSize - 1]); + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(keyLength); + KeyPair keyPair = kpg.generateKeyPair(); + + encryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); + decryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); + if (encryptPublicKey || "RSA/ECB/OAEPPadding".equals(algorithm)) { + encryptCipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); + decryptCipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + } else { + encryptCipher.init(Cipher.ENCRYPT_MODE, keyPair.getPrivate()); + decryptCipher.init(Cipher.DECRYPT_MODE, keyPair.getPublic()); + } + encryptedData = fillEncrypted(data, encryptCipher); + } + + @Benchmark + public byte[] encrypt() throws BadPaddingException, IllegalBlockSizeException { + byte[] dataBytes = data[index]; + index = (index + 1) % data.length; + return encryptCipher.doFinal(dataBytes); + } + + @Benchmark + public byte[] decrypt() throws BadPaddingException, IllegalBlockSizeException { + byte[] e = encryptedData[index]; + index = (index + 1) % encryptedData.length; + return decryptCipher.doFinal(e); + } +} diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java new file mode 100644 index 00000000..65bb8bf8 --- /dev/null +++ b/jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + */ + +package org.openeuler.bench.security.openssl; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Setup; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Warmup; + +import java.security.KeyPairGenerator; + +@Warmup(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS) +public class RSAKeyPairGeneratorBenchmark extends BenchmarkBase { + @Param({"RSA"}) + private String algorithm; + + @Param({"512", "1024", "2048", "3072", "4096"}) + private int keySize; + + private KeyPairGenerator keyPairGenerator; + + @Setup + public void setUp() throws Exception { + setupProvider(); + keyPairGenerator = createKeyPairGenerator(); + } + + @Benchmark + public void generateKeyPair() throws Exception { + keyPairGenerator.initialize(keySize); + keyPairGenerator.generateKeyPair(); + } + + private KeyPairGenerator createKeyPairGenerator() throws Exception { + if (prov != null) { + return KeyPairGenerator.getInstance(algorithm, prov); + } + return KeyPairGenerator.getInstance(algorithm); + } +} diff --git a/jdk/test/sun/security/krb5/auto/BasicProc.java b/jdk/test/sun/security/krb5/auto/BasicProc.java index 50f65eab..a388c76a 100644 --- a/jdk/test/sun/security/krb5/auto/BasicProc.java +++ b/jdk/test/sun/security/krb5/auto/BasicProc.java @@ -297,7 +297,9 @@ public class BasicProc { Proc p = Proc.create("BasicProc") .prop("java.security.manager", "") .prop("sun.net.spi.nameservice.provider.1", "ns,mock") - .perm(new javax.security.auth.AuthPermission("doAs")); + .perm(new javax.security.auth.AuthPermission("doAs")) + .perm(new java.util.PropertyPermission( + "kae.disableKaeDispose", "read")); if (lib != null) { p.env("KRB5_CONFIG", CONF) .env("KRB5_TRACE", Platform.isWindows() ? "CON" : "/dev/stderr") -- 2.19.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2