diff --git a/8280872-Reorder-code-cache-segments-to-improv.patch b/8280872-Reorder-code-cache-segments-to-improv.patch index ee70fc1f8cd571b8e31e7b8fc07f7109b7f51d90..78d9df05f0f96ec0f5290e98d04cba6a74665a56 100644 --- a/8280872-Reorder-code-cache-segments-to-improv.patch +++ b/8280872-Reorder-code-cache-segments-to-improv.patch @@ -208,9 +208,9 @@ deleted file mode 100644 index f47331a6d..000000000 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java +++ /dev/null -@@ -1,137 +0,0 @@ +@@ -1,136 +0,0 @@ -/* -- * Copyright (c) 2022, BELLSOFT. All rights reserved. +- * Copyright (c) 2024, BELLSOFT. 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 @@ -300,10 +300,9 @@ index f47331a6d..000000000 - "-Xbatch", - "-XX:+TieredCompilation", - "-XX:+SegmentedCodeCache", -- "-XX:CompileOnly=" + className + "::main", - "-XX:ReservedCodeCacheSize=" + (bigCodeHeap ? "256M" : "200M"), - "-XX:+UnlockDiagnosticVMOptions", -- "-XX:+PrintAssembly", +- "-XX:CompileCommand=option," + className + "::main,bool,PrintAssembly,true", - className}; - - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(procArgs); diff --git a/add-version-txt.patch b/add-version-txt.patch index 077b8807d46763b21e90462d9ecbd5a789e1f8d9..dabf1c16e7dc29daa16c6091a68da0aa7df789f0 100644 --- a/add-version-txt.patch +++ b/add-version-txt.patch @@ -13,7 +13,7 @@ index 000000000..b717bafbe --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ -+17.0.10.0.13 ++17.0.12.0.13 -- 2.19.0 diff --git a/jdk-updates-jdk17u-jdk-17.0.12+7.tar.gz b/jdk-updates-jdk17u-jdk-17.0.12+7.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..47278351786ff9bed1a711afcc5af03c8129c6ea Binary files /dev/null and b/jdk-updates-jdk17u-jdk-17.0.12+7.tar.gz differ diff --git a/jdk17-Add-KAE-provider.patch b/jdk17-Add-KAE-provider.patch new file mode 100644 index 0000000000000000000000000000000000000000..cc4e7ea9a9bb509c24d9c6c1c1f3b002121ffe64 --- /dev/null +++ b/jdk17-Add-KAE-provider.patch @@ -0,0 +1,14478 @@ +From 781562d5e5b70a18d12ea9488be80d6c641f8e72 Mon Sep 17 00:00:00 2001 +Subject: [PATCH] jdk17 Add KAE provider + +--- + make/ZipSecurity.gmk | 1 + + make/autoconf/.spec.gmk.in.swp | Bin 0 -> 16384 bytes + make/autoconf/configure.ac | 1 + + make/autoconf/jdk-options.m4 | 21 + + make/autoconf/spec.gmk.in | 1 + + make/common/Modules.gmk | 13 + + make/conf/module-loader-map.conf | 1 + + .../hotspot/nbproject/configurations.xml | 104 +++ + make/modules/jdk.crypto.kaeprovider/Copy.gmk | 46 + + make/modules/jdk.crypto.kaeprovider/Lib.gmk | 52 ++ + src/java.base/share/classes/module-info.java | 9 +- + .../share/lib/security/default.policy | 5 + + .../share/classes/module-info.java | 6 + + .../linux/classes/module-info.java | 39 + + .../security/openssl/KAEAESCipher.java | 365 ++++++++ + .../openeuler/security/openssl/KAEConfig.java | 393 +++++++++ + .../security/openssl/KAEDHKeyAgreement.java | 289 +++++++ + .../openssl/KAEDHKeyPairGenerator.java | 182 ++++ + .../openeuler/security/openssl/KAEDigest.java | 264 ++++++ + .../security/openssl/KAEECDHKeyAgreement.java | 146 ++++ + .../openssl/KAEECKeyPairGenerator.java | 151 ++++ + .../openeuler/security/openssl/KAEHMac.java | 227 +++++ + .../openeuler/security/openssl/KAELog.java | 188 +++++ + .../openeuler/security/openssl/KAEMGF1.java | 94 +++ + .../security/openssl/KAEProvider.java | 326 +++++++ + .../security/openssl/KAERSACipher.java | 796 ++++++++++++++++++ + .../openssl/KAERSAKeyPairGenerator.java | 164 ++++ + .../security/openssl/KAERSAPSSSignature.java | 683 +++++++++++++++ + .../security/openssl/KAERSAPaddingType.java | 83 ++ + .../security/openssl/KAERSASignature.java | 365 ++++++++ + .../openssl/KAERSASignatureNative.java | 46 + + .../security/openssl/KAESM4Cipher.java | 370 ++++++++ + .../security/openssl/KAESM4KeyGenerator.java | 74 ++ + .../openssl/KAESymmetricCipherBase.java | 791 +++++++++++++++++ + .../openeuler/security/openssl/KAEUtils.java | 220 +++++ + .../linux/conf/security/kaeprovider.conf | 75 ++ + .../security/openssl/kae_cipher_rsa.c | 471 +++++++++++ + .../openeuler/security/openssl/kae_digest.c | 232 +++++ + .../security/openssl/kae_exception.c | 135 +++ + .../security/openssl/kae_exception.h | 57 ++ + .../org/openeuler/security/openssl/kae_hmac.c | 208 +++++ + .../security/openssl/kae_keyagreement_dh.c | 141 ++++ + .../security/openssl/kae_keyagreement_ecdh.c | 121 +++ + .../openssl/kae_keypairgenerator_dh.c | 132 +++ + .../openssl/kae_keypairgenerator_ec.c | 505 +++++++++++ + .../openssl/kae_keypairgenerator_rsa.c | 173 ++++ + .../org/openeuler/security/openssl/kae_log.h | 33 + + .../openeuler/security/openssl/kae_provider.c | 103 +++ + .../security/openssl/kae_signature_rsa.c | 366 ++++++++ + .../security/openssl/kae_symmetric_cipher.c | 415 +++++++++ + .../org/openeuler/security/openssl/kae_util.c | 246 ++++++ + .../org/openeuler/security/openssl/kae_util.h | 94 +++ + .../openeuler/security/openssl/openssl_ad.h | 10 + + test/jdk/TEST.groups | 3 + + .../KeyAgreement/KeyAgreementTest.java | 11 +- + .../Signature/SignatureGetInstance.java | 5 +- + .../openeuler/security/openssl/AESTest.java | 115 +++ + .../openeuler/security/openssl/DHTest.java | 122 +++ + .../security/openssl/DigestTest.java | 61 ++ + .../openeuler/security/openssl/ECDHTest.java | 114 +++ + .../openeuler/security/openssl/HmacTest.java | 89 ++ + .../security/openssl/KAEConfTest.java | 122 +++ + .../openssl/KAEDisabledAlgorithmsTest.java | 165 ++++ + .../security/openssl/KAEEngineIdTest.java | 77 ++ + .../security/openssl/KAELogTest.java | 127 +++ + .../security/openssl/KAETestHelper.java | 209 +++++ + .../security/openssl/KAEUseEngineTest.java | 263 ++++++ + .../security/openssl/KaeDebugLogTest.java | 89 ++ + .../security/openssl/KaeProviderTest.java | 171 ++++ + .../openeuler/security/openssl/RSATest.java | 115 +++ + .../openeuler/security/openssl/SM3Test.java | 55 ++ + .../openeuler/security/openssl/SM4Test.java | 153 ++++ + .../jca/PreferredProviderNegativeTest.java | 7 +- + .../jdk/sun/security/krb5/auto/BasicProc.java | 4 +- + test/jdk/sun/security/pkcs11/Secmod/policy | 1 + + test/jdk/sun/security/pkcs11/policy | 1 + + .../ssl/CipherSuite/DisabledCurve.java | 4 + + .../SSLSocketImpl/NotifyHandshakeTest.policy | 2 + + .../bench/security/openssl/AESBenchmark.java | 108 +++ + .../security/openssl/AESGCMBenchmark.java | 133 +++ + .../bench/security/openssl/BenchmarkBase.java | 106 +++ + .../openssl/DHKeyAgreementBenchMark.java | 139 +++ + .../openssl/DHKeyPairGeneratorBenchmark.java | 64 ++ + .../security/openssl/DigestBenchmark.java | 69 ++ + .../openssl/ECKeyAgreementBenchmark.java | 88 ++ + .../openssl/ECKeyPairGeneratorBenchmark.java | 63 ++ + .../bench/security/openssl/HMacBenchmark.java | 73 ++ + .../security/openssl/RSACipherBenchmark.java | 107 +++ + .../openssl/RSAKeyPairGeneratorBenchmark.java | 64 ++ + .../openssl/RSAPSSSignatureBenchmark.java | 118 +++ + .../openssl/RSASignatureBenchmark.java | 90 ++ + .../bench/security/openssl/SM3Benchmark.java | 98 +++ + .../bench/security/openssl/SM4Benchmark.java | 157 ++++ + 93 files changed, 13590 insertions(+), 5 deletions(-) + create mode 100644 make/autoconf/.spec.gmk.in.swp + create mode 100644 make/modules/jdk.crypto.kaeprovider/Copy.gmk + create mode 100644 make/modules/jdk.crypto.kaeprovider/Lib.gmk + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/module-info.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEAESCipher.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEConfig.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyAgreement.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyPairGenerator.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDigest.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECDHKeyAgreement.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECKeyPairGenerator.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEHMac.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAELog.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEMGF1.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEProvider.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSACipher.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPSSSignature.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPaddingType.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignature.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignatureNative.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4Cipher.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4KeyGenerator.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESymmetricCipherBase.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEUtils.java + create mode 100644 src/jdk.crypto.kaeprovider/linux/conf/security/kaeprovider.conf + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_cipher_rsa.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_digest.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.h + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_hmac.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_dh.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_ecdh.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_dh.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_ec.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_log.h + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_provider.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_signature_rsa.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_symmetric_cipher.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.c + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.h + create mode 100644 src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/openssl_ad.h + create mode 100644 test/jdk/org/openeuler/security/openssl/AESTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/DHTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/DigestTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/ECDHTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/HmacTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAEConfTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAEEngineIdTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAELogTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAETestHelper.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KAEUseEngineTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KaeDebugLogTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/KaeProviderTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/RSATest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/SM3Test.java + create mode 100644 test/jdk/org/openeuler/security/openssl/SM4Test.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/AESGCMBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/DHKeyAgreementBenchMark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/DHKeyPairGeneratorBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/DigestBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/ECKeyAgreementBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/ECKeyPairGeneratorBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/RSACipherBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/RSAPSSSignatureBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/RSASignatureBenchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/SM3Benchmark.java + create mode 100644 test/micro/org/openeuler/bench/security/openssl/SM4Benchmark.java + +diff --git a/make/ZipSecurity.gmk b/make/ZipSecurity.gmk +index f7435f05e..21970928b 100644 +--- a/make/ZipSecurity.gmk ++++ b/make/ZipSecurity.gmk +@@ -42,6 +42,7 @@ $(eval $(call SetupZipArchive,BUILD_SEC_BIN_ZIP, \ + modules/java.base/sun/security/internal/spec \ + modules/java.base/com/sun/crypto/provider \ + modules/jdk.crypto.ec/sun/security/ec \ ++ modules/jdk.crypto.kaeprovider/org/openeuler/security/openssl \ + modules/jdk.crypto.mscapi/sun/security/mscapi \ + modules/jdk.crypto.cryptoki/sun/security/pkcs11 \ + modules/jdk.crypto.cryptoki/sun/security/pkcs11/wrapper \ +diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac +index 52baed8af..71aadc3e5 100644 +--- a/make/autoconf/configure.ac ++++ b/make/autoconf/configure.ac +@@ -243,6 +243,7 @@ HOTSPOT_SETUP_MISC + + LIB_TESTS_ENABLE_DISABLE_FAILURE_HANDLER + ++JDKOPT_DETECT_KAE + JDKOPT_ENABLE_DISABLE_GENERATE_CLASSLIST + JDKOPT_EXCLUDE_TRANSLATIONS + JDKOPT_ENABLE_DISABLE_MANPAGES +diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 +index a5557fe0a..483733814 100644 +--- a/make/autoconf/jdk-options.m4 ++++ b/make/autoconf/jdk-options.m4 +@@ -348,6 +348,27 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS], + AC_SUBST(SHIP_DEBUG_SYMBOLS) + ]) + ++############################################################################### ++# ++# Enable or disable the kae crypto implementation ++# ++AC_DEFUN_ONCE([JDKOPT_DETECT_KAE], ++[ ++ AC_ARG_ENABLE(kae, [AS_HELP_STRING([--enable-kae], ++ [enable KAE support on aarch64 @<:@disabled@:>@])], ++ [ENABLE_KAE="true"], [ENABLE_KAE="false"]) ++ AC_MSG_CHECKING([if kae has been enabled]) ++ if test "x$enable_kae" = "xyes"; then ++ AC_MSG_RESULT([yes]) ++ elif test "x$enable_kae" = "x" || test "x$enable_kae" = "xno"; then ++ AC_MSG_RESULT([no]) ++ else ++ AC_MSG_ERROR([Invalid value for --enable-kae: $enable_kae]) ++ fi ++ ++ AC_SUBST(ENABLE_KAE) ++]) ++ + ################################################################################ + # + # Native and Java code coverage +diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in +index 807ba2758..2fdda9655 100644 +--- a/make/autoconf/spec.gmk.in ++++ b/make/autoconf/spec.gmk.in +@@ -775,6 +775,7 @@ TAR_INCLUDE_PARAM:=@TAR_INCLUDE_PARAM@ + TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TRANSFORM@ + + # Build setup ++ENABLE_KAE:=@ENABLE_KAE@ + USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@ + USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@ + USE_EXTERNAL_LIBZ:=@USE_EXTERNAL_LIBZ@ +diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk +index 0eb0fb2dd..c3c6a1bf4 100644 +--- a/make/common/Modules.gmk ++++ b/make/common/Modules.gmk +@@ -312,6 +312,19 @@ define ReadImportMetaData + $$(eval $$(call ReadSingleImportMetaData, $$m))) + endef + ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ PLATFORM_MODULES += jdk.crypto.kaeprovider ++ endif ++endif ++ ++################################################################################ ++# Filter out kae specific modules if kae is disabled or cpu is not aarch64 ++ ++ifneq ($(ENABLE_KAE)-$(OPENJDK_TARGET_CPU_ARCH), true-aarch64) ++ MODULES_FILTER += jdk.crypto.kaeprovider ++endif ++ + ################################################################################ + + endif # _MODULES_GMK +diff --git a/make/conf/module-loader-map.conf b/make/conf/module-loader-map.conf +index c86ebf954..f72d96123 100644 +--- a/make/conf/module-loader-map.conf ++++ b/make/conf/module-loader-map.conf +@@ -78,6 +78,7 @@ PLATFORM_MODULES= \ + jdk.accessibility \ + jdk.charsets \ + jdk.crypto.cryptoki \ ++ jdk.crypto.kaeprovide \ + jdk.crypto.ec \ + jdk.dynalink \ + jdk.httpserver \ +diff --git a/make/ide/netbeans/hotspot/nbproject/configurations.xml b/make/ide/netbeans/hotspot/nbproject/configurations.xml +index 4f64db4ec..29c5e668b 100644 +--- a/make/ide/netbeans/hotspot/nbproject/configurations.xml ++++ b/make/ide/netbeans/hotspot/nbproject/configurations.xml +@@ -3,6 +3,110 @@ + + + ++ ++ ++ ++ ++ kae_cipher_rsa.c ++ kae_digest.c ++ kae_exception.c ++ kae_exception.h ++ kae_hmac.c ++ kae_keyagreement_dh.c ++ kae_keyagreement_ecdh.c ++ kae_keypairgenerator_dh.c ++ kae_keypairgenerator_ec.c ++ kae_keypairgenerator_rsa.c ++ kae_provider.c ++ kae_signature_rsa.c ++ kae_symmetric_cipher.c ++ kae_util.c ++ kae_util.h ++ kae_log.h ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + nopadding in sunjce ++ if (mode == Mode.GCM) { ++ this.padding = Padding.NOPADDING; ++ } else 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 " + paddingStr); ++ } ++ } ++ ++ protected void checkIvBytes(byte[] ivBytes) throws InvalidAlgorithmParameterException { ++ if ((ivBytes == null) || (ivBytes.length != blockSize)) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: must be " + blockSize + " bytes long."); ++ } ++ } ++} ++ +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEConfig.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEConfig.java +new file mode 100644 +index 000000000..a4eb57770 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEConfig.java +@@ -0,0 +1,393 @@ ++/* ++ * Copyright (c) 2023, 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 sun.security.util.Debug; ++ ++import java.io.BufferedInputStream; ++import java.io.File; ++import java.io.FileInputStream; ++import java.io.IOException; ++import java.io.InputStream; ++import java.security.AccessController; ++import java.security.PrivilegedAction; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.Map; ++import java.util.Properties; ++ ++public class KAEConfig { ++ private static final Debug kaeDebug = Debug.getInstance("kae"); ++ ++ // these property names indicates whether each algorithm uses KAEProvider ++ private static final String[] useKaeProviderPropertyNames = new String[]{ ++ "kae.md5", ++ "kae.sha256", ++ "kae.sha384", ++ "kae.sm3", ++ "kae.aes", ++ "kae.sm4", ++ "kae.hmac", ++ "kae.rsa", ++ "kae.dh", ++ "kae.ec" ++ }; ++ ++ // these property names indicate whether KAE hardware acceleration is enabled for each algorithm ++ private static final String[] useKaeEnginePropertyNames = new String[]{ ++ "kae.digest.useKaeEngine", ++ "kae.aes.useKaeEngine", ++ "kae.sm4.useKaeEngine", ++ "kae.hmac.useKaeEngine", ++ "kae.rsa.useKaeEngine", ++ "kae.dh.useKaeEngine", ++ "kae.ec.useKaeEngine" ++ }; ++ ++ // algorithm names ++ private static final String[] algorithmNames = new String[]{ ++ "md5", ++ "sha256", ++ "sha384", ++ "sm3", ++ "aes-128-ecb", ++ "aes-128-cbc", ++ "aes-128-ctr", ++ "aes-128-gcm", ++ "aes-192-ecb", ++ "aes-192-cbc", ++ "aes-192-ctr", ++ "aes-192-gcm", ++ "aes-256-ecb", ++ "aes-256-cbc", ++ "aes-256-ctr", ++ "aes-256-gcm", ++ "sm4-ecb", ++ "sm4-cbc", ++ "sm4-ctr", ++ "sm4-ofb", ++ "hmac-md5", ++ "hmac-sha1", ++ "hmac-sha224", ++ "hmac-sha256", ++ "hmac-sha384", ++ "hmac-sha512", ++ "rsa", ++ "dh", ++ "ec" ++ }; ++ ++ // algorithm name and algorithm index mapping ++ private static final Map algorithmNameIndexMap = new HashMap<>(); ++ ++ // algorithm name and algorithm category index mapping ++ private static final Map algorithmNameCategoryMap = new HashMap<>(); ++ ++ // whether use KAEProvider for each algorithm ++ private static final boolean[] useKaeProviderFlags = new boolean[algorithmNames.length]; ++ ++ // whether use KAEProvider for each category algorithm ++ private static final Map useKaeProviderCategoryMap = new HashMap<>(); ++ ++ // whether enable the Kunpeng acceleration engine for each algorithm ++ private static final boolean[] useKaeEngineFlags = new boolean[algorithmNames.length]; ++ ++ // The kaeprovider.cnf properties ++ private static Properties props; ++ ++ private KAEConfig() { ++ ++ } ++ ++ static { ++ kaeConfigInit(); ++ } ++ ++ @SuppressWarnings("removal") ++ private static void kaeConfigInit() { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ public Void run() { ++ initialize(); ++ return null; ++ } ++ }); ++ } ++ ++ private static File kaePropFile(String filename) { ++ String sep = File.separator; ++ String defaultKaeConf = System.getProperty("java.home") + sep + "conf" + sep + filename; ++ String kaeConf = System.getProperty("kae.conf", defaultKaeConf); ++ return new File(kaeConf); ++ } ++ ++ private static void initialize() { ++ initProperties(); ++ initAlgorithmNameMap(); ++ initUseKaeProviderFlags(); ++ initUseKaeEngineFlags(); ++ } ++ ++ private static void initProperties() { ++ props = new Properties(); ++ File propFile = kaePropFile("kaeprovider.conf"); ++ if (propFile.exists()) { ++ InputStream is = null; ++ try { ++ FileInputStream fis = new FileInputStream(propFile); ++ is = new BufferedInputStream(fis); ++ props.load(is); ++ ++ if (kaeDebug != null) { ++ kaeDebug.println("reading kae properties file: " + ++ propFile); ++ } ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("unable to load kae properties from " + ++ propFile); ++ e.printStackTrace(); ++ } ++ } finally { ++ if (is != null) { ++ try { ++ is.close(); ++ } catch (IOException ioe) { ++ if (kaeDebug != null) { ++ kaeDebug.println("unable to close input stream"); ++ } ++ } ++ } ++ } ++ } else { ++ if (kaeDebug != null) { ++ kaeDebug.println("not found kae properties file: " + ++ propFile); ++ } ++ } ++ } ++ ++ public static Boolean useKaeProvider(String key) { ++ return useKaeProviderCategoryMap.getOrDefault(key, Boolean.TRUE); ++ } ++ ++ private static void initUseKaeProviderFlags() { ++ boolean[] categoryFlagsForProvider = new boolean[useKaeProviderPropertyNames.length]; ++ Arrays.fill(categoryFlagsForProvider, true); ++ for (int i = 0; i < useKaeProviderPropertyNames.length; i++) { ++ String configValue = privilegedGetOverridable(useKaeProviderPropertyNames[i]); ++ if (configValue != null) { ++ categoryFlagsForProvider[i] = Boolean.parseBoolean(configValue); ++ } ++ useKaeProviderCategoryMap.put(useKaeProviderPropertyNames[i], categoryFlagsForProvider[i]); ++ } ++ int offset = useKaeProviderPropertyNames.length - useKaeEnginePropertyNames.length; ++ int digestAlgorithmLen = offset + 1; ++ // digest ++ System.arraycopy(categoryFlagsForProvider, 0, useKaeProviderFlags, 0, digestAlgorithmLen); ++ ++ // non-digest ++ for (int i = digestAlgorithmLen; i < useKaeProviderFlags.length; i++) { ++ Integer algorithmCategoryIndex = algorithmNameCategoryMap.get(algorithmNames[i]); ++ if (categoryFlagsForProvider[algorithmCategoryIndex + offset]) { ++ useKaeProviderFlags[i] = true; ++ } ++ } ++ ++ if (kaeDebug != null) { ++ kaeDebug.println("useKaeProviderPropertyNames: "); ++ for (int i = 0; i < categoryFlagsForProvider.length; i++) { ++ kaeDebug.println(useKaeProviderPropertyNames[i] + "=" + categoryFlagsForProvider[i]); ++ } ++ ++ kaeDebug.println("useKaeProviderFlags: "); ++ for (int i = 0; i < useKaeProviderFlags.length; i++) { ++ kaeDebug.println(algorithmNames[i] + "=" + useKaeProviderFlags[i]); ++ } ++ } ++ } ++ ++ public static boolean[] getUseKaeProviderFlags() { ++ return useKaeProviderFlags; ++ } ++ ++ private static void initUseKaeEngineFlags() { ++ boolean[] categoryFlagsForEngine = new boolean[]{ ++ true, // digest ++ false, // aes ++ true, // sm4 ++ false, // hmac ++ true, // rsa ++ true, // dh ++ false // ec ++ }; ++ for (int i = 0; i < useKaeEnginePropertyNames.length; i++) { ++ String configValue = privilegedGetOverridable(useKaeEnginePropertyNames[i]); ++ if (configValue != null) { ++ categoryFlagsForEngine[i] = Boolean.parseBoolean(configValue); ++ } ++ } ++ ++ // EC algorithm currently does not support KAE hardware acceleration, temporarily use openssl soft calculation. ++ categoryFlagsForEngine[useKaeEnginePropertyNames.length - 1] = false; ++ ++ for (int i = 0; i < useKaeEngineFlags.length; i++) { ++ Integer algorithmCategoryIndex = algorithmNameCategoryMap.get(algorithmNames[i]); ++ if (categoryFlagsForEngine[algorithmCategoryIndex]) { ++ useKaeEngineFlags[i] = true; ++ } ++ } ++ ++ String[] disabledAlgorithms = getDisabledAlgorithms(); ++ for (String disabledAlgorithm : disabledAlgorithms) { ++ Integer algorithmIndex = algorithmNameIndexMap.get(disabledAlgorithm); ++ if (algorithmIndex != null) { ++ useKaeEngineFlags[algorithmIndex] = false; ++ } ++ } ++ if (kaeDebug != null) { ++ kaeDebug.println("useKaeEnginePropertyNames: "); ++ for (int i = 0; i < categoryFlagsForEngine.length; i++) { ++ kaeDebug.println(useKaeEnginePropertyNames[i] + "=" + categoryFlagsForEngine[i]); ++ } ++ ++ kaeDebug.println("disabledAlgorithms: "); ++ for (int i = 0; i < disabledAlgorithms.length; i++) { ++ kaeDebug.println(disabledAlgorithms[i]); ++ } ++ ++ kaeDebug.println("useKaeEngineFlags: "); ++ for (int i = 0; i < useKaeEngineFlags.length; i++) { ++ kaeDebug.println(algorithmNames[i] + "=" + useKaeEngineFlags[i]); ++ } ++ } ++ } ++ ++ public static boolean[] getUseKaeEngineFlags() { ++ return useKaeEngineFlags; ++ } ++ ++ private static void initAlgorithmNameIndexMap() { ++ for (int i = 0; i < algorithmNames.length; i++) { ++ algorithmNameIndexMap.put(algorithmNames[i], i); ++ } ++ } ++ ++ /* ++ * 0 : digest ++ * 1 : aes ++ * 2 : sm4 ++ * 3 : hmac ++ * 4 : rsa ++ * 5 : dh ++ * 6 : ec ++ */ ++ private static void initAlgorithmNameCategoryMap() { ++ algorithmNameCategoryMap.put("md5", 0); ++ algorithmNameCategoryMap.put("sha256", 0); ++ algorithmNameCategoryMap.put("sha384", 0); ++ algorithmNameCategoryMap.put("sm3", 0); ++ algorithmNameCategoryMap.put("aes-128-ecb", 1); ++ algorithmNameCategoryMap.put("aes-128-cbc", 1); ++ algorithmNameCategoryMap.put("aes-128-ctr", 1); ++ algorithmNameCategoryMap.put("aes-128-gcm", 1); ++ algorithmNameCategoryMap.put("aes-192-ecb", 1); ++ algorithmNameCategoryMap.put("aes-192-cbc", 1); ++ algorithmNameCategoryMap.put("aes-192-ctr", 1); ++ algorithmNameCategoryMap.put("aes-192-gcm", 1); ++ algorithmNameCategoryMap.put("aes-256-ecb", 1); ++ algorithmNameCategoryMap.put("aes-256-cbc", 1); ++ algorithmNameCategoryMap.put("aes-256-ctr", 1); ++ algorithmNameCategoryMap.put("aes-256-gcm", 1); ++ algorithmNameCategoryMap.put("sm4-ecb", 2); ++ algorithmNameCategoryMap.put("sm4-cbc", 2); ++ algorithmNameCategoryMap.put("sm4-ctr", 2); ++ algorithmNameCategoryMap.put("sm4-ofb", 2); ++ algorithmNameCategoryMap.put("hmac-md5", 3); ++ algorithmNameCategoryMap.put("hmac-sha1", 3); ++ algorithmNameCategoryMap.put("hmac-sha224", 3); ++ algorithmNameCategoryMap.put("hmac-sha256", 3); ++ algorithmNameCategoryMap.put("hmac-sha384", 3); ++ algorithmNameCategoryMap.put("hmac-sha512", 3); ++ algorithmNameCategoryMap.put("rsa", 4); ++ algorithmNameCategoryMap.put("dh", 5); ++ algorithmNameCategoryMap.put("ec", 6); ++ } ++ ++ private static void initAlgorithmNameMap() { ++ initAlgorithmNameIndexMap(); ++ initAlgorithmNameCategoryMap(); ++ } ++ ++ private static String[] getDisabledAlgorithms() { ++ String disabledAlgorithms = privilegedGetOverridable("kae.engine.disabledAlgorithms", ++ "sha256,sha384"); ++ return disabledAlgorithms.replaceAll(" ", "").split("\\,"); ++ } ++ ++ @SuppressWarnings("removal") ++ public static String privilegedGetProperty(String key) { ++ if (System.getSecurityManager() == null) { ++ return getProperty(key); ++ } else { ++ return AccessController.doPrivileged((PrivilegedAction) () -> getOverridableProperty(key)); ++ } ++ } ++ ++ @SuppressWarnings("removal") ++ public static String privilegedGetOverridable(String key) { ++ if (System.getSecurityManager() == null) { ++ return getOverridableProperty(key); ++ } else { ++ return AccessController.doPrivileged((PrivilegedAction) () -> getOverridableProperty(key)); ++ } ++ } ++ ++ public static String privilegedGetOverridable(String key, String defaultValue) { ++ String val = privilegedGetOverridable(key); ++ return (val == null) ? defaultValue : val; ++ } ++ ++ private static String getProperty(String key) { ++ String val = props.getProperty(key); ++ if (val != null) ++ val = val.trim(); ++ return val; ++ } ++ ++ private static String getOverridableProperty(String key) { ++ String val = System.getProperty(key); ++ if (val == null) { ++ return getProperty(key); ++ } else { ++ return val; ++ } ++ } ++ ++ public static String getAlgorithmName(int index) { ++ if (index < 0 || index >= algorithmNames.length) { ++ throw new IndexOutOfBoundsException(); ++ } ++ return algorithmNames[index]; ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyAgreement.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyAgreement.java +new file mode 100644 +index 000000000..541df07d6 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyAgreement.java +@@ -0,0 +1,289 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.util.KeyUtil; ++import java.math.BigInteger; ++import java.security.KeyFactory; ++import java.security.InvalidKeyException; ++import java.security.SecureRandom; ++import java.security.Key; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.NoSuchAlgorithmException; ++import java.security.AccessController; ++import java.security.ProviderException; ++import java.security.PrivilegedAction; ++import java.security.spec.InvalidKeySpecException; ++import java.security.spec.AlgorithmParameterSpec; ++import javax.crypto.KeyAgreementSpi; ++import javax.crypto.SecretKey; ++import javax.crypto.ShortBufferException; ++import javax.crypto.interfaces.DHPrivateKey; ++import javax.crypto.interfaces.DHPublicKey; ++import javax.crypto.spec.DHParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++import javax.crypto.spec.DHPublicKeySpec; ++import javax.crypto.SecretKeyFactory; ++import javax.crypto.spec.DESedeKeySpec; ++import javax.crypto.spec.DESKeySpec; ++ ++public class KAEDHKeyAgreement extends KeyAgreementSpi { ++ private boolean generateSecret = false; ++ private BigInteger p; ++ private BigInteger g; ++ private BigInteger x; ++ private BigInteger y; ++ static final int[] AES_KEYSIZES = {16, 24, 32}; ++ static final int BLOWFISH_MAX_KEYSIZE = 56; ++ ++ private static class AllowKDF { ++ private static final boolean VALUE = getValue(); ++ ++ @SuppressWarnings("removal") ++ private static boolean getValue() { ++ return AccessController.doPrivileged( ++ (PrivilegedAction) ++ () -> Boolean.getBoolean("jdk.crypto.KeyAgreement.legacyKDF")); ++ } ++ } ++ ++ public KAEDHKeyAgreement() { ++ } ++ ++ @Override ++ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException { ++ try { ++ engineInit(key, null, random); ++ } catch (InvalidAlgorithmParameterException e) { ++ // never happens, because we did not pass any parameters ++ } ++ } ++ ++ @Override ++ protected void engineInit(Key key, AlgorithmParameterSpec params, ++ SecureRandom random) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ ++ // ignore "random" parameter, because our implementation does not ++ // require any source of randomness ++ generateSecret = false; ++ p = null; ++ g = null; ++ ++ if ((params != null) && !(params instanceof DHParameterSpec)) { ++ throw new InvalidAlgorithmParameterException("Diffie-Hellman parameters expected"); ++ } ++ ++ if (!(key instanceof DHPrivateKey)) { ++ throw new InvalidKeyException("Diffie-Hellman private key expected"); ++ } ++ ++ DHPrivateKey privateKey = (DHPrivateKey) key; ++ ++ // check if private key parameters are compatible with ++ // initialized ones ++ if (params != null) { ++ p = ((DHParameterSpec) params).getP(); ++ g = ((DHParameterSpec) params).getG(); ++ } ++ ++ BigInteger priv_p = privateKey.getParams().getP(); ++ BigInteger priv_g = privateKey.getParams().getG(); ++ if (p != null && priv_p != null && !(p.equals(priv_p))) { ++ throw new InvalidKeyException("Incompatible parameters"); ++ } ++ if (g != null && priv_g != null && !(g.equals(priv_g))) { ++ throw new InvalidKeyException("Incompatible parameters"); ++ } ++ if ((p == null && priv_p == null) || ++ (g == null) && priv_g == null) { ++ throw new InvalidKeyException("Missing parameters"); ++ } ++ p = priv_p; ++ g = priv_g; ++ ++ // store the x value ++ x = privateKey.getX(); ++ } ++ ++ @Override ++ protected Key engineDoPhase(Key key, boolean lastPhase) ++ throws InvalidKeyException, IllegalStateException { ++ if (!(key instanceof DHPublicKey)) { ++ throw new InvalidKeyException("Diffie-Hellman public " ++ + "expected"); ++ } ++ DHPublicKey publicKey = (DHPublicKey) key; ++ if (p == null || g == null) { ++ throw new IllegalStateException("Not initialized"); ++ } ++ BigInteger pub_p = publicKey.getParams().getP(); ++ BigInteger pub_g = publicKey.getParams().getG(); ++ if (pub_p != null && !(p.equals(pub_p))) { ++ throw new InvalidKeyException("Incompatible parameters"); ++ } ++ if (pub_g != null && !(g.equals(pub_g))) { ++ throw new InvalidKeyException("Incompatible parameters"); ++ } ++ KeyUtil.validate(publicKey); ++ y = publicKey.getY(); ++ generateSecret = true; ++ if (lastPhase == false) { ++ byte[] intermediate = engineGenerateSecret(); ++ try { ++ KeyFactory fk = KeyFactory.getInstance("DH"); ++ DHPublicKey newPublicKey = (DHPublicKey) fk.generatePublic( ++ new DHPublicKeySpec(new BigInteger(1, intermediate), p, g)); ++ return newPublicKey; ++ } catch (NoSuchAlgorithmException noalg) { ++ throw new ProviderException(noalg); ++ } catch (InvalidKeySpecException ikse) { ++ throw new ProviderException(ikse); ++ } ++ } else { ++ return null; ++ } ++ } ++ ++ @Override ++ protected byte[] engineGenerateSecret() ++ throws IllegalStateException { ++ int expectedLen = (p.bitLength() + 7) >>> 3; ++ byte[] result = new byte[expectedLen]; ++ try { ++ engineGenerateSecret(result, 0); ++ } catch (ShortBufferException shortBufferException) { ++ // should never happen since length are identical ++ } ++ return result; ++ } ++ ++ @Override ++ protected int engineGenerateSecret(byte[] sharedSecret, int offset) ++ throws IllegalStateException, ShortBufferException { ++ if (!generateSecret) { ++ throw new IllegalStateException("Key agreement has not bee complated yet"); ++ } ++ if (sharedSecret == null) { ++ throw new ShortBufferException("No buffer provided for shared secret"); ++ } ++ BigInteger modulus = p; ++ int expectedLen = (modulus.bitLength() + 7) >>> 3; ++ if ((sharedSecret.length - offset) < expectedLen) { ++ throw new ShortBufferException("Buffer too short for shared secret"); ++ } ++ generateSecret = false; ++ byte[] secret = nativeComputeKey(y.toByteArray(), x.toByteArray(), ++ p.toByteArray(), g.toByteArray(), modulus.bitLength()); ++ ++ if (secret.length == expectedLen) { ++ System.arraycopy(secret, 0, sharedSecret, offset, ++ secret.length); ++ } else { ++ // Array too short, pad it w/ leading 0s ++ if (secret.length < expectedLen) { ++ System.arraycopy(secret, 0, sharedSecret, ++ offset + (expectedLen - secret.length), ++ secret.length); ++ } else { ++ // Array too long, check and trim off the excess ++ if ((secret.length == (expectedLen + 1)) && secret[0] == 0) { ++ // ignore the leading sign byte ++ System.arraycopy(secret, 1, sharedSecret, offset, expectedLen); ++ } else { ++ throw new ProviderException("Generated secret is out-of-range"); ++ } ++ } ++ } ++ ++ return expectedLen; ++ } ++ ++ @Override ++ protected SecretKey engineGenerateSecret(String algorithm) ++ throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException { ++ if (algorithm == null) { ++ throw new NoSuchAlgorithmException("null algorithm"); ++ } ++ ++ if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") && ++ !AllowKDF.VALUE) { ++ ++ throw new NoSuchAlgorithmException("Unsupported secret key " ++ + "algorithm: " + algorithm); ++ } ++ ++ byte[] secret = engineGenerateSecret(); ++ if (algorithm.equalsIgnoreCase("DES")) { ++ // DES ++ try { ++ SecretKeyFactory factory = SecretKeyFactory.getInstance("DES"); ++ return factory.generateSecret(new DESKeySpec(secret)); ++ } catch (InvalidKeySpecException e) { ++ throw new ProviderException("Generate DES Secret failed.", e); ++ } ++ } else if (algorithm.equalsIgnoreCase("DESede") ++ || algorithm.equalsIgnoreCase("TripleDES")) { ++ // Triple DES ++ try { ++ SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede"); ++ return factory.generateSecret(new DESedeKeySpec(secret)); ++ } catch (InvalidKeySpecException e) { ++ throw new ProviderException("Generate DESede Secret failed.", e); ++ } ++ } else if (algorithm.equalsIgnoreCase("Blowfish")) { ++ // Blowfish ++ int keysize = secret.length; ++ if (keysize >= BLOWFISH_MAX_KEYSIZE) ++ keysize = BLOWFISH_MAX_KEYSIZE; ++ return new SecretKeySpec(secret, 0, keysize, "Blowfish"); ++ } else if (algorithm.equalsIgnoreCase("AES")) { ++ int idx = AES_KEYSIZES.length - 1; ++ int keysize = secret.length; ++ SecretKeySpec secretKey = null; ++ while (secretKey == null && idx >= 0) { ++ if (keysize >= AES_KEYSIZES[idx]) { ++ keysize = AES_KEYSIZES[idx]; ++ secretKey = new SecretKeySpec(secret, 0, keysize, "AES"); ++ } ++ idx--; ++ } ++ if (secretKey == null) { ++ throw new InvalidKeyException("Key material is too short"); ++ } ++ return secretKey; ++ } else if (algorithm.equals("TlsPremasterSecret")) { ++ // remove leading zero bytes per RFC 5246 Section 8.1.2 ++ return new SecretKeySpec( ++ KeyUtil.trimZeroes(secret), "TlsPremasterSecret"); ++ } else { ++ throw new NoSuchAlgorithmException("Unsupported secret key " ++ + "algorithm: " + algorithm); ++ } ++ } ++ protected native byte[] nativeComputeKey(byte[] y, byte[] x, byte[] p, byte[] g, int pSize); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyPairGenerator.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyPairGenerator.java +new file mode 100644 +index 000000000..74134eef5 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyPairGenerator.java +@@ -0,0 +1,182 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.math.BigInteger; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.KeyPairGeneratorSpi; ++import java.security.SecureRandom; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.KeyPair; ++import java.security.NoSuchAlgorithmException; ++import java.security.InvalidParameterException; ++import java.security.GeneralSecurityException; ++import java.security.ProviderException; ++import java.security.KeyFactory; ++import java.security.spec.InvalidKeySpecException; ++import sun.security.jca.JCAUtil; ++import sun.security.provider.ParameterCache; ++import javax.crypto.spec.DHPublicKeySpec; ++import javax.crypto.spec.DHPrivateKeySpec; ++import javax.crypto.spec.DHParameterSpec; ++import javax.crypto.interfaces.DHPublicKey; ++import javax.crypto.interfaces.DHPrivateKey; ++ ++import static sun.security.util.SecurityProviderConstants.DEF_DH_KEY_SIZE; ++ ++public class KAEDHKeyPairGenerator ++ extends KeyPairGeneratorSpi { ++ private DHParameterSpec parameterSpec; ++ // The size in bits of the random exponent (private value) ++ private int pSize; ++ // The size in bits of the random exponent (private value) ++ private int lSize; ++ private SecureRandom random; ++ ++ public KAEDHKeyPairGenerator() { ++ super(); ++ initialize(DEF_DH_KEY_SIZE, null); ++ } ++ ++ private static void checkKeySize(int keySize) { ++ if ((keySize < 512) || (keySize > 8192) || ((keySize & 0x3F) != 0)) { ++ throw new InvalidParameterException( ++ "DH key size must be multiple of 64, and can only range " + ++ "from 512 to 8192(inclusize). " + ++ "The specific key size " + keySize + " is not supported"); ++ } ++ } ++ @Override ++ public void initialize(AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidAlgorithmParameterException { ++ ++ if (!(params instanceof DHParameterSpec)){ ++ throw new InvalidAlgorithmParameterException ++ ("Inappropriate parameter type"); ++ } ++ ++ parameterSpec = (DHParameterSpec) params; ++ pSize = parameterSpec.getP().bitLength(); ++ ++ try { ++ checkKeySize(pSize); ++ } catch (InvalidParameterException e) { ++ throw new InvalidAlgorithmParameterException(e.getMessage()); ++ } ++ ++ // exponent size is optional, could be 0 ++ lSize = parameterSpec.getL(); ++ ++ // Require exponentSize < primeSize ++ if ((lSize != 0) && (lSize > pSize)) { ++ throw new InvalidAlgorithmParameterException ++ ("Exponent size must not be larger than modulus size"); ++ } ++ ++ this.random = random; ++ } ++ ++ @Override ++ public void initialize(int keysize, SecureRandom random) { ++ checkKeySize(keysize); ++ this.parameterSpec = ParameterCache.getCachedDHParameterSpec(keysize); ++ if ((this.parameterSpec == null) && (keysize > 1024)) { ++ throw new InvalidParameterException("Unsupported " + keysize + "-bit DH parameter generation."); ++ } ++ this.pSize = keysize; ++ this.lSize = 0; ++ this.random = random; ++ } ++ ++ @Override ++ public KeyPair generateKeyPair() { ++ ++ if (random == null) { ++ random = JCAUtil.getSecureRandom(); ++ } ++ ++ if (parameterSpec == null) { ++ try { ++ parameterSpec = ParameterCache.getDHParameterSpec(pSize, random); ++ } catch (GeneralSecurityException e) { ++ // should never happen ++ throw new ProviderException(e); ++ } ++ } ++ ++ BigInteger p = parameterSpec.getP(); ++ BigInteger g = parameterSpec.getG(); ++ ++ if (lSize <= 0) { ++ lSize = pSize >> 1; ++ // use an exponent size of (pSize / 2) but at least 384 bits ++ if (lSize < 384) { ++ lSize = 384; ++ } ++ } ++ byte[][] keys; ++ try { ++ keys = nativeGenerateKeyPair(p.toByteArray(), g.toByteArray(), lSize); ++ } catch (Exception e){ ++ throw new ProviderException("Invoke nativeGenerateKeyPair failed.", e); ++ } ++ ++ // check keys ++ checkKeys(keys); ++ ++ BigInteger pubKey = new BigInteger(keys[0]); ++ BigInteger priKey = new BigInteger(keys[1]); ++ ++ try{ ++ KeyFactory fk = KeyFactory.getInstance("DH"); ++ DHPublicKey publicKey = (DHPublicKey)fk.generatePublic(new DHPublicKeySpec(pubKey, p , g)); ++ DHPrivateKey privateKey = (DHPrivateKey)fk.generatePrivate(new DHPrivateKeySpec(priKey, p, g)); ++ return new KeyPair(publicKey, privateKey); ++ } catch (NoSuchAlgorithmException noalg) { ++ throw new ProviderException(noalg); ++ } catch (InvalidKeySpecException ikse) { ++ throw new ProviderException(ikse); ++ } ++ } ++ ++ private void checkKeys(byte[][] keys) { ++ if (keys == null) { ++ throw new ProviderException("Invalid keys, keys is null."); ++ } ++ // The keys needs to contain at least 2 byte arrays, which are public and private keys. ++ if (keys.length < 2) { ++ throw new ProviderException("Invalid keys, keys length is less than 2."); ++ } ++ for (int i = 0; i < keys.length; i++) { ++ if (keys[i] == null) { ++ throw new ProviderException("Invalid keys, keys[" + i + "]" + "is null."); ++ } ++ } ++ } ++ ++ protected native static byte[][] nativeGenerateKeyPair(byte[] p, byte[] g, int lSize); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDigest.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDigest.java +new file mode 100644 +index 000000000..aca5f4b29 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/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) 2023, 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 ++ implements Comparable { ++ ++ private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); ++ private static Set 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/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECDHKeyAgreement.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECDHKeyAgreement.java +new file mode 100644 +index 000000000..29dc09889 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECDHKeyAgreement.java +@@ -0,0 +1,146 @@ ++/* ++ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.ec.ECKeyFactory; ++ ++import java.math.BigInteger; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidParameterException; ++import java.security.InvalidKeyException; ++import java.security.Key; ++import java.security.NoSuchAlgorithmException; ++import java.security.PrivateKey; ++import java.security.SecureRandom; ++import java.security.interfaces.ECPrivateKey; ++import java.security.interfaces.ECPublicKey; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.ECParameterSpec; ++import java.security.spec.ECPoint; ++import javax.crypto.KeyAgreementSpi; ++import javax.crypto.SecretKey; ++import javax.crypto.ShortBufferException; ++import javax.crypto.spec.SecretKeySpec; ++ ++public class KAEECDHKeyAgreement extends KeyAgreementSpi { ++ private ECPrivateKey privateKey; ++ private ECPublicKey publicKey; ++ ++ // Length of the secret to be derived. ++ private int expectedSecretLen; ++ private String curveName; ++ ++ @Override ++ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException { ++ if (!(key instanceof PrivateKey)) { ++ throw new InvalidKeyException("Key must be instance of PrivateKey"); ++ } ++ privateKey = (ECPrivateKey) ECKeyFactory.toECKey(key); ++ publicKey = null; ++ } ++ ++ @Override ++ protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ if (params != null) { ++ throw new InvalidAlgorithmParameterException("Parameters not supported"); ++ } ++ engineInit(key, random); ++ } ++ ++ @Override ++ protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException { ++ if (privateKey == null) { ++ throw new IllegalStateException("Not initialized"); ++ } ++ if (publicKey != null) { ++ throw new IllegalStateException("Phase already executed"); ++ } ++ if (!lastPhase) { ++ throw new IllegalStateException ++ ("Only two party agreement supported, lastPhase must be true"); ++ } ++ if (!(key instanceof ECPublicKey)) { ++ throw new InvalidKeyException ++ ("Key must be a PublicKey with algorithm EC"); ++ } ++ ++ publicKey = (ECPublicKey) key; ++ ECParameterSpec params = publicKey.getParams(); ++ int keyLenBits = params.getCurve().getField().getFieldSize(); ++ // Bits to bytes. ++ expectedSecretLen = (keyLenBits + 7) >> 3; ++ ++ curveName = KAEUtils.getCurveBySize(keyLenBits); ++ if (curveName == null) { ++ throw new InvalidParameterException("unknown keyLenBits " + keyLenBits); ++ } ++ if (KAEUtils.getCurveByAlias(curveName) != null) { ++ curveName = KAEUtils.getCurveByAlias(curveName); ++ } ++ return null; ++ } ++ ++ @Override ++ protected byte[] engineGenerateSecret() throws IllegalStateException { ++ if ((privateKey == null) || (publicKey == null)) { ++ throw new IllegalStateException("Not initialized correctly"); ++ } ++ ECPoint w = publicKey.getW(); ++ BigInteger wX = w.getAffineX(); ++ BigInteger wY = w.getAffineY(); ++ ++ BigInteger s = privateKey.getS(); ++ byte[] secret = nativeGenerateSecret(curveName, wX.toByteArray(), wY.toByteArray(), s.toByteArray()); ++ if (secret == null || secret.length != expectedSecretLen) { ++ throw new RuntimeException("nativeGenerateSecret error. Expected: " + expectedSecretLen + ", actual: " + (secret == null ? "null" : secret.length)); ++ } ++ return secret; ++ } ++ ++ @Override ++ protected int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException { ++ if (offset + expectedSecretLen > sharedSecret.length) { ++ throw new ShortBufferException("Need " + expectedSecretLen + ++ " bytes, only " + (sharedSecret.length - offset) + "available"); ++ } ++ byte[] secret = engineGenerateSecret(); ++ System.arraycopy(secret, 0, sharedSecret, offset, secret.length); ++ return secret.length; ++ } ++ ++ @Override ++ protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, ++ NoSuchAlgorithmException, InvalidKeyException { ++ if (algorithm == null) { ++ throw new NoSuchAlgorithmException("Algorithm must not be null"); ++ } ++ return new SecretKeySpec(engineGenerateSecret(), algorithm); ++ } ++ ++ protected static native byte[] nativeGenerateSecret(String curveName, byte[] wX, byte[] wY, byte[] s); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECKeyPairGenerator.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECKeyPairGenerator.java +new file mode 100644 +index 000000000..73d8551b1 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECKeyPairGenerator.java +@@ -0,0 +1,151 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.ec.ECPrivateKeyImpl; ++import sun.security.ec.ECPublicKeyImpl; ++ ++import java.math.BigInteger; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidParameterException; ++import java.security.KeyPair; ++import java.security.KeyPairGeneratorSpi; ++import java.security.ProviderException; ++import java.security.SecureRandom; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.ECFieldFp; ++import java.security.spec.ECField; ++import java.security.spec.ECGenParameterSpec; ++import java.security.spec.ECParameterSpec; ++import java.security.spec.ECPoint; ++import java.security.spec.EllipticCurve; ++ ++import java.lang.reflect.Constructor; ++import java.lang.reflect.InvocationTargetException; ++ ++public class KAEECKeyPairGenerator extends KeyPairGeneratorSpi { ++ private ECParameterSpec param = null; ++ private final int defaultKeySize = 256; ++ ++ @Override ++ public void initialize(int keysize, SecureRandom random) { ++ String curveName = KAEUtils.getCurveBySize(keysize); ++ if (curveName == null) { ++ throw new InvalidParameterException("unknown key size " + keysize); ++ } ++ if (KAEUtils.getCurveByAlias(curveName) != null) { ++ curveName = KAEUtils.getCurveByAlias(curveName); ++ } ++ this.param = getParamsByCurve(curveName); ++ } ++ ++ private ECParameterSpec getParamsByCurve(String curveName) { ++ byte[][] params = nativeGenerateParam(curveName); ++ if (params == null) { ++ throw new InvalidParameterException("unknown curve " + curveName); ++ } ++ BigInteger p = new BigInteger(params[0]); ++ BigInteger a = new BigInteger(params[1]); ++ BigInteger b = new BigInteger(params[2]); ++ BigInteger x = new BigInteger(params[3]); ++ BigInteger y = new BigInteger(params[4]); ++ BigInteger order = new BigInteger(params[5]); ++ BigInteger cofactor = new BigInteger(params[6]); ++ ECField field = new ECFieldFp(p); ++ EllipticCurve curve = new EllipticCurve(field, a, b); ++ ECPoint g = new ECPoint(x, y); ++ ECParameterSpec spec = new ECParameterSpec(curve, g, order, cofactor.intValue()); ++ return spec; ++ } ++ ++ @Override ++ public void initialize(AlgorithmParameterSpec param, SecureRandom random) throws InvalidAlgorithmParameterException { ++ if (param instanceof ECParameterSpec) { ++ this.param = (ECParameterSpec) param; ++ } else if (param instanceof ECGenParameterSpec) { ++ ECGenParameterSpec ecParam = (ECGenParameterSpec)param; ++ String curveName = ecParam.getName(); ++ if (KAEUtils.getCurveByAlias(curveName) != null) { ++ curveName = KAEUtils.getCurveByAlias(curveName); ++ } ++ this.param = getParamsByCurve(curveName); ++ } else { ++ throw new InvalidAlgorithmParameterException("ECParameterSpec or ECGenParameterSpec for EC"); ++ } ++ } ++ ++ @Override ++ public KeyPair generateKeyPair() { ++ if (param == null) { ++ String curveName = KAEUtils.getCurveBySize(defaultKeySize); ++ param = getParamsByCurve(curveName); ++ } ++ EllipticCurve curve = param.getCurve(); ++ ECFieldFp field = (ECFieldFp) curve.getField(); ++ BigInteger p = field.getP(); ++ BigInteger a = curve.getA(); ++ BigInteger b = curve.getB(); ++ ECPoint generator = param.getGenerator(); ++ BigInteger x = generator.getAffineX(); ++ BigInteger y = generator.getAffineY(); ++ BigInteger order = param.getOrder(); ++ int cofactor = param.getCofactor(); ++ ++ byte[][] keys = nativeGenerateKeyPair(p.toByteArray(), a.toByteArray(), ++ b.toByteArray(), x.toByteArray(), y.toByteArray(), order.toByteArray(), cofactor); ++ if (keys == null) { ++ throw new RuntimeException("nativeGenerateKeyPair failed"); ++ } ++ BigInteger wX = new BigInteger(keys[0]); ++ BigInteger wY = new BigInteger(keys[1]); ++ BigInteger s = new BigInteger(keys[2]); ++ ECPoint w = new ECPoint(wX, wY); ++ ++ ECPrivateKeyImpl privateKey = null; ++ ECPublicKeyImpl publicKey = null; ++ try { ++ Class pubKeyImpl = Class.forName("sun.security.ec.ECPublicKeyImpl"); ++ Constructor conPubKeyImpl = pubKeyImpl.getDeclaredConstructor(ECPoint.class, ECParameterSpec.class); ++ conPubKeyImpl.setAccessible(true); ++ publicKey = (ECPublicKeyImpl) conPubKeyImpl.newInstance(w, param); ++ ++ Class priKeyImpl = Class.forName("sun.security.ec.ECPrivateKeyImpl"); ++ Constructor conPriKeyImpl = priKeyImpl.getDeclaredConstructor(BigInteger.class, ECParameterSpec.class); ++ conPriKeyImpl.setAccessible(true); ++ privateKey = (ECPrivateKeyImpl) conPriKeyImpl.newInstance(s, param); ++ } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | ++ IllegalAccessException | InvocationTargetException e) { ++ throw new ProviderException(e); ++ } ++ return new KeyPair(publicKey, privateKey); ++ } ++ ++ protected static native byte[][] nativeGenerateParam(String curveName); ++ ++ protected static native byte[][] nativeGenerateKeyPair(byte[] p, byte[] a, byte[] b, byte[] x, byte[] y, ++ byte[] order, int cofactor); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEHMac.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEHMac.java +new file mode 100644 +index 000000000..3ca909aa1 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEHMac.java +@@ -0,0 +1,227 @@ ++/* ++ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.security.*; ++import java.security.spec.AlgorithmParameterSpec; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++public abstract class KAEHMac extends MacSpi { ++ ++ private final String algorithm; ++ ++ /** ++ * The secret key used in this keyed HMAC. ++ */ ++ 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 KAEHMac(String algo, int size) { ++ this.algorithm = algo; ++ this.digestSize = size; ++ } ++ ++ private static class HmacContextRef extends PhantomReference ++ implements Comparable { ++ ++ private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); ++ private static Set referenceList = new ConcurrentSkipListSet<>(); ++ private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); ++ ++ private final long address; ++ ++ HmacContextRef(KAEHMac kaeHMac, long address) { ++ super(kaeHMac, 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 KAEHMac { ++ public HmacMD5() { ++ super("MD5", 16); ++ } ++ } ++ public static final class HmacSHA1 extends KAEHMac { ++ public HmacSHA1() { ++ super("SHA1", 20); ++ } ++ } ++ public static final class HmacSHA224 extends KAEHMac { ++ public HmacSHA224() throws NoSuchAlgorithmException { ++ super("SHA224", 28); ++ } ++ } ++ public static final class HmacSHA256 extends KAEHMac { ++ public HmacSHA256() throws NoSuchAlgorithmException { ++ super("SHA256", 32); ++ } ++ } ++ public static final class HmacSHA384 extends KAEHMac { ++ public HmacSHA384() throws NoSuchAlgorithmException { ++ super("SHA384", 48); ++ } ++ } ++ public static final class HmacSHA512 extends KAEHMac { ++ 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/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAELog.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAELog.java +new file mode 100644 +index 000000000..33c1c430f +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAELog.java +@@ -0,0 +1,188 @@ ++/* ++ * Copyright (c) 2023, 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 sun.security.util.Debug; ++ ++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.StandardOpenOption; ++import java.security.AccessController; ++import java.security.PrivilegedAction; ++import java.text.SimpleDateFormat; ++import java.util.Arrays; ++import java.util.Date; ++ ++public class KAELog { ++ private static final Debug kaeDebug = Debug.getInstance("kae"); ++ private static File logFile; ++ private static boolean exist; ++ ++ private KAELog() { ++ ++ } ++ ++ static { ++ kaeLogInit(); ++ } ++ ++ @SuppressWarnings("removal") ++ private static void kaeLogInit() { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ public Void run() { ++ initialize(); ++ return null; ++ } ++ }); ++ } ++ ++ private static void initialize() { ++ if (!enableKaeLog()) { ++ if (kaeDebug != null) { ++ kaeDebug.println("kae logging is not enabled"); ++ } ++ return; ++ } ++ ++ logFile = kaeLogFile("kae.log"); ++ File parentFile = logFile.getParentFile(); ++ if (!parentFile.exists()) { ++ try { ++ Files.createDirectories(parentFile.toPath()); ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("failed to create directory :" + parentFile); ++ e.printStackTrace(); ++ } ++ return; ++ } ++ } ++ ++ if (logFile.exists()) { ++ if (kaeDebug != null) { ++ kaeDebug.println("found kae log file :" + logFile); ++ } ++ exist = true; ++ } else { ++ if (kaeDebug != null) { ++ kaeDebug.println("not found kae log file :" + logFile); ++ } ++ try { ++ Path path = Files.createFile(logFile.toPath()); ++ if (path != null) { ++ exist = true; ++ } ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("unable to create new kae log file :" + logFile); ++ e.printStackTrace(); ++ } ++ } ++ ++ if (exist) { ++ if (kaeDebug != null) { ++ kaeDebug.println("create new kae log file :" + logFile); ++ } ++ } ++ } ++ } ++ ++ public static boolean enableKaeLog() { ++ String debug = KAEConfig.privilegedGetOverridable("kae.log"); ++ return Boolean.parseBoolean(debug); ++ } ++ ++ private static File kaeLogFile(String filename) { ++ String sep = File.separator; ++ String defaultKaeLog = System.getProperty("user.dir") + sep + filename; ++ String kaeLog = KAEConfig.privilegedGetOverridable("kae.log.file", defaultKaeLog); ++ return new File(kaeLog); ++ } ++ ++ private static String getLogTime() { ++ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ++ return simpleDateFormat.format(new Date()); ++ } ++ ++ public static void log(String engineId, Throwable throwable, boolean[] engineFlags, boolean[] kaeProviderFlags) { ++ if (engineFlags.length != kaeProviderFlags.length) { ++ if (kaeDebug != null) { ++ kaeDebug.println("The length of engineFlags is not equal to the length of kaeProviderFlags."); ++ kaeDebug.println(String.format("engineFlags : %s", Arrays.toString(engineFlags))); ++ kaeDebug.println(String.format("kaeProviderFlags : %s", Arrays.toString(kaeProviderFlags))); ++ } ++ return; ++ } ++ if (!exist) { ++ return; ++ } ++ ++ try (BufferedWriter writer = Files.newBufferedWriter(logFile.toPath(), ++ StandardOpenOption.APPEND)) { ++ logEngine(writer, engineId, throwable); ++ writer.newLine(); ++ logAlgorithmStrategy(writer, engineFlags, kaeProviderFlags); ++ writer.newLine(); ++ } catch (IOException e) { ++ if (kaeDebug != null) { ++ kaeDebug.println("write kae log failed"); ++ e.printStackTrace(); ++ } ++ } ++ } ++ ++ // log engine ++ private static void logEngine(BufferedWriter writer, String engineId, Throwable throwable) throws IOException { ++ writer.write(String.format("[%s] ", getLogTime())); ++ if (throwable == null) { ++ writer.write(String.format("%s engine was found.", engineId)); ++ } else if (throwable instanceof RuntimeException) { ++ writer.write(String.format("%s engine was not found. %s", engineId, throwable.getMessage())); ++ } else { ++ writer.write(throwable.getMessage()); ++ } ++ } ++ ++ // log algorithm strategy ++ private static void logAlgorithmStrategy(BufferedWriter writer, boolean[] engineFlags, boolean[] kaeProviderFlags) ++ throws IOException { ++ writer.write(String.format("[%s] ", getLogTime())); ++ writer.write("The implementation strategy of each algorithm is as follows : "); ++ for (int i = 0; i < engineFlags.length; i++) { ++ writer.newLine(); ++ String algorithmName = KAEConfig.getAlgorithmName(i); ++ String message; ++ if (kaeProviderFlags[i]) { ++ String detail = engineFlags[i] ? "enable KAE hardware acceleration" : "Use openssl soft calculation"; ++ message = String.format(" %-11s => %s: %s", algorithmName, "KAEProvider", detail); ++ } else { ++ message = String.format(" %-11s => %s", algorithmName, "Non-KAEProvider"); ++ } ++ writer.write(message); ++ } ++ } ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEMGF1.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEMGF1.java +new file mode 100644 +index 000000000..dc79a3f62 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEMGF1.java +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.security.openssl; ++ ++import java.security.*; ++ ++/** ++ * This class implements the MGF1 mask generation function defined in PKCS#1 ++ * v2.2 B.2.1 (https://tools.ietf.org/html/rfc8017#appendix-B.2.1). A mask ++ * generation function takes an octet string of variable length and a ++ * desired output length as input and outputs an octet string of the ++ * desired length. MGF1 is a mask generation function based on a hash ++ * function, i.e. message digest algorithm. ++ * ++ * @since 11 ++ */ ++final class KAEMGF1 { ++ ++ private final MessageDigest md; ++ ++ /** ++ * Construct an instance of MGF1 based on the specified digest algorithm. ++ */ ++ KAEMGF1(String mdAlgo) throws NoSuchAlgorithmException { ++ this.md = MessageDigest.getInstance(mdAlgo); ++ } ++ ++ /** ++ * Using the specified seed bytes, generate the mask, xor the mask ++ * with the specified output buffer and store the result into the ++ * output buffer (essentially replaced in place). ++ * ++ * @param seed the buffer holding the seed bytes ++ * @param seedOfs the index of the seed bytes ++ * @param seedLen the length of the seed bytes to be used by MGF1 ++ * @param maskLen the intended length of the generated mask ++ * @param out the output buffer holding the mask ++ * @param outOfs the index of the output buffer for the mask ++ */ ++ void generateAndXor(byte[] seed, int seedOfs, int seedLen, int maskLen, ++ byte[] out, int outOfs) throws RuntimeException { ++ byte[] C = new byte[4]; // 32 bit counter ++ byte[] digest = new byte[md.getDigestLength()]; ++ while (maskLen > 0) { ++ md.update(seed, seedOfs, seedLen); ++ md.update(C); ++ try { ++ md.digest(digest, 0, digest.length); ++ } catch (DigestException e) { ++ // should never happen ++ throw new RuntimeException(e.toString()); ++ } ++ for (int i = 0; (i < digest.length) && (maskLen > 0); maskLen--) { ++ out[outOfs++] ^= digest[i++]; ++ } ++ if (maskLen > 0) { ++ // increment counter ++ for (int i = C.length - 1; (++C[i] == 0) && (i > 0); i--) { ++ // empty ++ } ++ } ++ } ++ } ++ ++ /** ++ * Returns the name of this MGF1 instance, i.e. "MGF1" followed by the ++ * digest algorithm it based on. ++ */ ++ String getName() { ++ return "KAEMGF1" + md.getAlgorithm(); ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEProvider.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEProvider.java +new file mode 100644 +index 000000000..b3c1fb022 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEProvider.java +@@ -0,0 +1,326 @@ ++/* ++ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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 sun.security.util.Debug; ++ ++import java.security.AccessController; ++import java.security.PrivilegedAction; ++import java.security.Provider; ++import static sun.security.util.SecurityConstants.PROVIDER_VER; ++ ++/** ++ * KAE Provider ++ */ ++@SuppressWarnings("serial") ++public class KAEProvider extends Provider { ++ private static final Debug kaeDebug = Debug.getInstance("kae"); ++ ++ // default engine id ++ private static final String DEFAULT_ENGINE_ID = "kae"; ++ ++ static { ++ initialize(); ++ } ++ ++ private static void initialize() { ++ loadLibrary(); ++ initOpenssl(); ++ } ++ ++ // load kae.so ++ @SuppressWarnings("removal") ++ private static void loadLibrary() { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ @Override ++ public Object run() { ++ System.loadLibrary("j2kae"); ++ return null; ++ } ++ }); ++ } ++ ++ // init openssl ++ private static void initOpenssl() { ++ boolean useGlobalMode = useGlobalMode(); ++ String engineId = getEngineId(); ++ boolean[] algorithmKaeFlags = KAEConfig.getUseKaeEngineFlags(); ++ Throwable throwable = null; ++ try { ++ initOpenssl(useGlobalMode, engineId, algorithmKaeFlags); ++ } catch (Throwable t) { ++ throwable = t; ++ if (kaeDebug != null) { ++ kaeDebug.println("initOpenssl failed : " + throwable.getMessage()); ++ } ++ } ++ boolean[] engineFlags = getEngineFlags(); ++ boolean[] kaeProviderFlags = KAEConfig.getUseKaeProviderFlags(); ++ KAELog.log(engineId, throwable, engineFlags, kaeProviderFlags); ++ } ++ ++ // get engine id ++ private static String getEngineId() { ++ return KAEConfig.privilegedGetOverridable("kae.engine.id", DEFAULT_ENGINE_ID); ++ } ++ ++ // whether to set libcrypto.so to GLOBAL mode, by default libcrypto.so is LOCAL mode ++ private static boolean useGlobalMode() { ++ String explicitLoad = KAEConfig.privilegedGetOverridable( ++ "kae.libcrypto.useGlobalMode", "false"); ++ return Boolean.parseBoolean(explicitLoad); ++ } ++ ++ @SuppressWarnings("deprecation") ++ public KAEProvider() { ++ super("KAEProvider", PROVIDER_VER, "KAE provider"); ++ if (KAEConfig.useKaeProvider("kae.md5")) { ++ putMD5(); ++ } ++ if (KAEConfig.useKaeProvider("kae.sha256")) { ++ putSHA256(); ++ } ++ if (KAEConfig.useKaeProvider("kae.sha384")) { ++ putSHA384(); ++ } ++ if (KAEConfig.useKaeProvider("kae.sm3")) { ++ putSM3(); ++ } ++ if (KAEConfig.useKaeProvider("kae.aes")) { ++ putAES(); ++ } ++ if (KAEConfig.useKaeProvider("kae.sm4")) { ++ putSM4(); ++ } ++ if (KAEConfig.useKaeProvider("kae.hmac")) { ++ putHMAC(); ++ } ++ if (KAEConfig.useKaeProvider("kae.rsa")) { ++ putRSA(); ++ putSignatureRSA(); ++ } ++ if (KAEConfig.useKaeProvider("kae.dh")) { ++ putDH(); ++ } ++ if (KAEConfig.useKaeProvider("kae.ec")) { ++ putEC(); ++ } ++ } ++ ++ private void putAES() { ++ final String blockModes = "ECB|CBC|CTR|GCM"; ++ 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/GCM/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Gcm$NoPadding"); ++ put("Alg.Alias.Cipher.AES/GCM/PKCS5Padding", "AES/GCM/NoPadding"); // PKCS5Padding -> 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_128/GCM/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Gcm$NoPadding"); ++ put("Alg.Alias.Cipher.AES_128/GCM/PKCS5Padding", "AES/GCM/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_192/GCM/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Gcm$NoPadding"); ++ put("Alg.Alias.Cipher.AES_192/GCM/PKCS5Padding", "AES/GCM/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"); ++ put("Cipher.AES_256/GCM/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Gcm$NoPadding"); ++ put("Alg.Alias.Cipher.AES_256/GCM/PKCS5Padding", "AES/GCM/NoPadding"); ++ } ++ ++ private void putMD5() { ++ put("MessageDigest.MD5", "org.openeuler.security.openssl.KAEDigest$MD5"); ++ } ++ ++ private void putSHA256() { ++ put("MessageDigest.SHA-256", "org.openeuler.security.openssl.KAEDigest$SHA256"); ++ } ++ ++ private void putSHA384() { ++ put("MessageDigest.SHA-384", "org.openeuler.security.openssl.KAEDigest$SHA384"); ++ } ++ ++ private void putSM3() { ++ put("MessageDigest.SM3", "org.openeuler.security.openssl.KAEDigest$SM3"); ++ } ++ ++ private void putSM4() { ++ final String blockModes = "ECB|CBC|CTR|OFB"; ++ final String blockPads = "NOPADDING|PKCS5PADDING"; ++ ++ put("Cipher.SM4 SupportedModes", blockModes); ++ put("Cipher.SM4 SupportedPaddings", blockPads); ++ put("Cipher.SM4", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ecb$PKCS5Padding"); ++ ++ put("Cipher.SM4/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Cbc$PKCS5Padding"); ++ put("Cipher.SM4/CBC/NoPadding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Cbc$NoPadding"); ++ put("Alg.Alias.Cipher.SM4/CBC/PKCS7Padding", "SM4/CBC/PKCS5Padding"); ++ put("Cipher.SM4/ECB/NoPadding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ecb$NoPadding"); ++ put("Cipher.SM4/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ecb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.SM4/ECB/PKCS7Padding", "SM4/ECB/PKCS5Padding"); ++ put("Cipher.SM4/CTR/NoPadding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ctr$NoPadding"); ++ put("Cipher.SM4/OFB/NoPadding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ofb$NoPadding"); ++ put("Cipher.SM4/OFB/PKCS5Padding", "org.openeuler.security.openssl.KAESM4Cipher$Sm4$Ofb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.SM4/OFB/PKCS7Padding", "SM4/OFB/PKCS5Padding"); ++ ++ put("KeyGenerator.SM4", "org.openeuler.security.openssl.KAESM4KeyGenerator"); ++ put("AlgorithmParameters.SM4", "com.sun.crypto.provider.AESParameters"); ++ } ++ ++ private void putRSA() { ++ // 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 putHMAC() { ++ put("MAC.HmacMD5", "org.openeuler.security.openssl.KAEHMac$HmacMD5"); ++ put("MAC.HmacSHA1", "org.openeuler.security.openssl.KAEHMac$HmacSHA1"); ++ put("MAC.HmacSHA224", "org.openeuler.security.openssl.KAEHMac$HmacSHA224"); ++ put("MAC.HmacSHA256", "org.openeuler.security.openssl.KAEHMac$HmacSHA256"); ++ put("MAC.HmacSHA384", "org.openeuler.security.openssl.KAEHMac$HmacSHA384"); ++ put("MAC.HmacSHA512", "org.openeuler.security.openssl.KAEHMac$HmacSHA512"); ++ } ++ ++ private void putDH() { ++ put("KeyPairGenerator.DiffieHellman", "org.openeuler.security.openssl.KAEDHKeyPairGenerator"); ++ put("Alg.Alias.KeyPairGenerator.DH", "DiffieHellman"); ++ put("KeyAgreement.DiffieHellman", "org.openeuler.security.openssl.KAEDHKeyAgreement"); ++ put("Alg.Alias.KeyAgreement.DH", "DiffieHellman"); ++ } ++ ++ private void putSignatureRSA() { ++ put("Signature.MD5withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$MD5withRSA"); ++ put("Signature.SHA1withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$SHA1withRSA"); ++ put("Signature.SHA224withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$SHA224withRSA"); ++ put("Signature.SHA256withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$SHA256withRSA"); ++ put("Signature.SHA384withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$SHA384withRSA"); ++ put("Signature.SHA512withRSA", ++ "org.openeuler.security.openssl.KAERSASignature$SHA512withRSA"); ++ ++ // alias ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA"); ++ put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.14", "SHA224withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.14", "SHA224withRSA"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA"); ++ ++ put("Signature.RSASSA-PSS", "org.openeuler.security.openssl.KAERSAPSSSignature"); ++ ++ put("Alg.Alias.Signature.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ ++ // attributes for supported key classes ++ String rsaKeyClasses = "java.security.interfaces.RSAPublicKey" + ++ "|java.security.interfaces.RSAPrivateKey"; ++ put("Signature.MD5withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.SHA1withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.SHA224withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.SHA256withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.SHA384withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.SHA512withRSA SupportedKeyClasses", rsaKeyClasses); ++ put("Signature.RSASSA-PSS SupportedKeyClasses", rsaKeyClasses); ++ } ++ ++ private void putEC() { ++ put("KeyPairGenerator.EC", "org.openeuler.security.openssl.KAEECKeyPairGenerator"); ++ put("Alg.Alias.KeyPairGenerator.EllipticCurve", "EC"); ++ put("KeyAgreement.ECDH", "org.openeuler.security.openssl.KAEECDHKeyAgreement"); ++ } ++ ++ // init openssl ++ static native void initOpenssl(boolean useGlobalMode, String engineId, boolean[] algorithmKaeFlags) ++ throws RuntimeException; ++ ++ static native boolean[] getEngineFlags(); ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSACipher.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSACipher.java +new file mode 100644 +index 000000000..a45fb0dac +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/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) 2023, 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. ++ *

++ * 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/OAEPwithandMGF1Padding" (or "RSA/ECB/OAEPPadding") for ++ * PKCS#1 v2.2 padding. ++ * . "RSA/ECB/NoPadding" for rsa RSA. ++ *

++ * 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. ++ *

++ * 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 ++ @SuppressWarnings("deprecation") ++ 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 ++ @SuppressWarnings("deprecation") ++ 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 ++ implements Comparable { ++ private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); ++ private static Set 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); ++ try { ++ return 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()); ++ } catch (Exception e) { ++ throw new InvalidKeyException(e); ++ } ++ } ++ ++ private long getKeyAddress(RSAPublicKey key) throws InvalidKeyException { ++ checkKey(key); ++ try { ++ return nativeCreateRSAPublicKey( ++ key.getModulus().toByteArray(), ++ key.getPublicExponent().toByteArray() ++ ); ++ } catch (Exception e) { ++ throw new InvalidKeyException(e); ++ } ++ } ++ ++ private void checkKey(RSAPrivateCrtKey key) throws InvalidKeyException { ++ boolean isInValidKey = key.getModulus() == null ++ || key.getPublicExponent() == null ++ || key.getPrivateExponent() == null ++ || key.getPrimeP() == null ++ || key.getPrimeQ() == null ++ || key.getPrimeExponentP() == null ++ || key.getPrimeExponentQ() == null ++ || key.getCrtCoefficient() == null; ++ if (isInValidKey) { ++ 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/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java +new file mode 100644 +index 000000000..88bd30574 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/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) 2023, 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/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPSSSignature.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPSSSignature.java +new file mode 100644 +index 000000000..065317148 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPSSSignature.java +@@ -0,0 +1,683 @@ ++/* ++ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.io.IOException; ++import java.nio.ByteBuffer; ++ ++import java.security.*; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.PSSParameterSpec; ++import java.security.spec.MGF1ParameterSpec; ++import java.security.interfaces.*; ++ ++import java.util.Arrays; ++import java.util.HashSet; ++import java.util.Locale; ++import java.util.Set; ++ ++import sun.security.rsa.PSSParameters; ++import sun.security.rsa.RSACore; ++import sun.security.jca.JCAUtil; ++ ++import javax.crypto.BadPaddingException; ++ ++/** ++ * PKCS#1 v2.2 RSASSA-PSS signatures with various message digest algorithms. ++ * RSASSA-PSS implementation takes the message digest algorithm, MGF algorithm, ++ * and salt length values through the required signature PSS parameters. ++ * We support SHA-1, SHA-224, SHA-256, SHA-384, SHA-512. ++ * The Openssl does not support rsa signatures with SHA-512/224 and SHA-512/256 as the digest algorithm, ++ * so we have not implemented them. ++ * The Openssl does not support non-CRT private key , when signing with a non-CRT private key, we use the sun sign. ++ */ ++@SuppressWarnings({"deprecation", "removal"}) ++public class KAERSAPSSSignature extends SignatureSpi { ++ // openssl unsupport rsa sign with digest algorithm ++ private static final Set UNSUPPORTED_DIGEST_ALGORITHM = new HashSet<>( ++ Arrays.asList("SHA-512/224", "SHA-512/256")); ++ ++ private static final byte[] EIGHT_BYTES_OF_ZEROS = new byte[8]; ++ ++ // message digest implementation we use for hashing the data ++ private MessageDigest md; ++ ++ // flag indicating whether the digest is reset ++ private boolean digestReset = true; ++ ++ // private key, if initialized for signing ++ private RSAPrivateKey privKey = null; ++ ++ // public key, if initialized for verifying ++ private RSAPublicKey pubKey = null; ++ ++ // PSS parameters from signatures and keys respectively ++ private PSSParameterSpec sigParams = null; ++ ++ // PRNG used to generate salt bytes if none given ++ private SecureRandom random; ++ ++ /** ++ * Construct a new RSAPSSSignatur with arbitrary digest algorithm ++ */ ++ public KAERSAPSSSignature() { ++ this.md = null; ++ } ++ ++ // initialize for verification. See JCA doc ++ @Override ++ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { ++ if (!(publicKey instanceof RSAPublicKey)) { ++ throw new InvalidKeyException("key must be RSAPublicKey"); ++ } ++ this.pubKey = (RSAPublicKey) isValid((RSAKey) publicKey); ++ this.privKey = null; ++ resetDigest(); ++ } ++ ++ // initialize for signing. See JCA doc ++ @Override ++ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { ++ engineInitSign(privateKey, null); ++ } ++ ++ // initialize for signing. See JCA doc ++ @Override ++ protected void engineInitSign(PrivateKey privateKey, SecureRandom random) throws InvalidKeyException { ++ if (!(privateKey instanceof RSAPrivateKey)) { ++ throw new InvalidKeyException("key must be RSAPrivateKey"); ++ } ++ this.privKey = (RSAPrivateKey) isValid((RSAKey) privateKey); ++ this.pubKey = null; ++ this.random = ++ (random == null ? JCAUtil.getSecureRandom() : random); ++ resetDigest(); ++ } ++ ++ /** ++ * Utility method for checking the key PSS parameters against signature ++ * PSS parameters. ++ * Returns false if any of the digest/MGF algorithms and trailerField ++ * values does not match or if the salt length in key parameters is ++ * larger than the value in signature parameters. ++ */ ++ private static boolean isCompatible(AlgorithmParameterSpec keyParams, PSSParameterSpec sigParams) { ++ if (keyParams == null) { ++ // key with null PSS parameters means no restriction ++ return true; ++ } ++ if (!(keyParams instanceof PSSParameterSpec)) { ++ return false; ++ } ++ // nothing to compare yet, defer the check to when sigParams is set ++ if (sigParams == null) { ++ return true; ++ } ++ PSSParameterSpec pssKeyParams = (PSSParameterSpec) keyParams; ++ // first check the salt length requirement ++ if (pssKeyParams.getSaltLength() > sigParams.getSaltLength()) { ++ return false; ++ } ++ ++ // compare equality of the rest of fields based on DER encoding ++ PSSParameterSpec keyParams2 = ++ new PSSParameterSpec(pssKeyParams.getDigestAlgorithm(), ++ pssKeyParams.getMGFAlgorithm(), ++ pssKeyParams.getMGFParameters(), ++ sigParams.getSaltLength(), ++ pssKeyParams.getTrailerField()); ++ ++ // skip the JCA overhead ++ try { ++ byte[] encoded = PSSParameters.getEncoded(keyParams2); ++ byte[] encoded2 = PSSParameters.getEncoded(sigParams); ++ return Arrays.equals(encoded, encoded2); ++ } catch (IOException e) { ++ return false; ++ } ++ } ++ ++ /** ++ * Validate the specified RSAKey and its associated parameters against ++ * internal signature parameters. ++ */ ++ private RSAKey isValid(RSAKey rsaKey) throws InvalidKeyException { ++ try { ++ AlgorithmParameterSpec keyParams = rsaKey.getParams(); ++ // validate key parameters ++ if (!isCompatible(rsaKey.getParams(), this.sigParams)) { ++ throw new InvalidKeyException ++ ("Key contains incompatible PSS parameter values"); ++ } ++ // validate key length ++ if (this.sigParams != null) { ++ Integer hLen = ++ KAEUtils.getDigestLength(this.sigParams.getDigestAlgorithm()); ++ if (hLen == null) { ++ throw new ProviderException("Unsupported digest algo: " + ++ this.sigParams.getDigestAlgorithm()); ++ } ++ checkKeyLength(rsaKey, hLen, this.sigParams.getSaltLength()); ++ } ++ return rsaKey; ++ } catch (SignatureException e) { ++ throw new InvalidKeyException(e); ++ } ++ } ++ ++ /** ++ * Validate the specified Signature PSS parameters. ++ */ ++ private PSSParameterSpec validateSigParams(AlgorithmParameterSpec p) throws InvalidAlgorithmParameterException { ++ if (p == null) { ++ throw new InvalidAlgorithmParameterException ++ ("Parameters cannot be null"); ++ } ++ if (!(p instanceof PSSParameterSpec)) { ++ throw new InvalidAlgorithmParameterException ++ ("parameters must be type PSSParameterSpec"); ++ } ++ // no need to validate again if same as current signature parameters ++ PSSParameterSpec params = (PSSParameterSpec) p; ++ if (params == this.sigParams) { ++ return params; ++ } ++ ++ RSAKey key = (this.privKey == null ? this.pubKey : this.privKey); ++ // check against keyParams if set ++ if (key != null) { ++ if (!isCompatible(key.getParams(), params)) { ++ throw new InvalidAlgorithmParameterException ++ ("Signature parameters does not match key parameters"); ++ } ++ } ++ // now sanity check the parameter values ++ if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) { ++ throw new InvalidAlgorithmParameterException("Only supports MGF1"); ++ } ++ if (params.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) { ++ throw new InvalidAlgorithmParameterException("Only supports TrailerFieldBC(1)"); ++ } ++ String digestAlgo = params.getDigestAlgorithm(); ++ // check key length again ++ if (key != null) { ++ try { ++ int hLen = KAEUtils.getDigestLength(digestAlgo); ++ checkKeyLength(key, hLen, params.getSaltLength()); ++ } catch (SignatureException e) { ++ throw new InvalidAlgorithmParameterException(e); ++ } ++ } ++ return params; ++ } ++ ++ /** ++ * Ensure the object is initialized with key and parameters and ++ * reset digest ++ */ ++ private void ensureInit() throws SignatureException { ++ RSAKey key = (this.privKey == null ? this.pubKey : this.privKey); ++ if (key == null) { ++ throw new SignatureException("Missing key"); ++ } ++ if (this.sigParams == null) { ++ // Parameters are required for signature verification ++ throw new SignatureException ++ ("Parameters required for RSASSA-PSS signatures"); ++ } ++ } ++ ++ /** ++ * Utility method for checking key length against digest length and ++ * salt length ++ */ ++ private static void checkKeyLength(RSAKey key, int digestLen, int saltLen) throws SignatureException { ++ if (key != null) { ++ int keyLength = getKeyLengthInBits(key) >> 3; ++ int minLength = Math.addExact(Math.addExact(digestLen, saltLen), 2); ++ if (keyLength < minLength) { ++ throw new SignatureException ++ ("Key is too short, need min " + minLength); ++ } ++ } ++ } ++ ++ /** ++ * Reset the message digest if it is not already reset. ++ */ ++ private void resetDigest() { ++ if (digestReset == false) { ++ this.md.reset(); ++ digestReset = true; ++ } ++ } ++ ++ /** ++ * Return the message digest value. ++ */ ++ private byte[] getDigestValue() { ++ digestReset = true; ++ return this.md.digest(); ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(byte b) throws SignatureException { ++ ensureInit(); ++ this.md.update(b); ++ digestReset = false; ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { ++ ensureInit(); ++ this.md.update(b, off, len); ++ digestReset = false; ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(ByteBuffer b) { ++ try { ++ ensureInit(); ++ } catch (SignatureException se) { ++ // hack for working around API bug ++ throw new RuntimeException(se.getMessage()); ++ } ++ this.md.update(b); ++ digestReset = false; ++ } ++ ++ // determine whether the digest is valid ++ private boolean isValidDigest() { ++ String digestName = this.md.getAlgorithm(); ++ if (UNSUPPORTED_DIGEST_ALGORITHM.contains(digestName.toUpperCase(Locale.ROOT))) { ++ return false; ++ } ++ AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); ++ String mgfDigestName = ""; ++ if (mgfParams != null) { ++ mgfDigestName = ++ ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); ++ } ++ return !UNSUPPORTED_DIGEST_ALGORITHM.contains(mgfDigestName.toUpperCase(Locale.ROOT)); ++ } ++ ++ // determine whether use kae sign ++ private boolean useKaeSign() { ++ return (privKey instanceof RSAPrivateCrtKey) && isValidDigest(); ++ } ++ ++ // sun sign ++ private byte[] sunSign(byte[] mHash) throws SignatureException { ++ try { ++ byte[] encoded = encodeSignature(mHash); ++ return RSACore.rsa(encoded, privKey, true); ++ } catch (GeneralSecurityException e) { ++ throw new SignatureException("Could not sign data", e); ++ } catch (IOException e) { ++ throw new SignatureException("Could not encode data", e); ++ } ++ } ++ ++ // kae sign ++ private byte[] kaeSign(byte[] mHash) throws SignatureException { ++ String kaeDigestName = KAEUtils.getKAEDigestName(this.sigParams.getDigestAlgorithm()); ++ String mgfDigestName = kaeDigestName; ++ AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); ++ if (mgfParams != null) { ++ mgfDigestName = ++ ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); ++ } ++ String mgf1DigestName = KAEUtils.getKAEDigestName(mgfDigestName); ++ ++ RSAPrivateCrtKey privateCrtKey = (RSAPrivateCrtKey) privKey; ++ long keyAddress = KAERSACipher.nativeCreateRSAPrivateCrtKey( ++ privateCrtKey.getModulus().toByteArray(), ++ privateCrtKey.getPublicExponent().toByteArray(), ++ privateCrtKey.getPrivateExponent().toByteArray(), ++ privateCrtKey.getPrimeP().toByteArray(), ++ privateCrtKey.getPrimeQ().toByteArray(), ++ privateCrtKey.getPrimeExponentP().toByteArray(), ++ privateCrtKey.getPrimeExponentQ().toByteArray(), ++ privateCrtKey.getCrtCoefficient().toByteArray()); ++ byte[] bytes; ++ try { ++ bytes = KAERSASignatureNative.pssSign(keyAddress, kaeDigestName, mHash, ++ KAERSAPaddingType.PKCS1PssPadding.getId(), ++ mgf1DigestName, this.sigParams.getSaltLength()); ++ } catch (SignatureException e) { ++ throw e; ++ } finally { ++ KAERSACipher.nativeFreeKey(keyAddress); ++ } ++ return bytes; ++ } ++ ++ // sign the data and return the signature. See JCA doc ++ @Override ++ protected byte[] engineSign() throws SignatureException { ++ ensureInit(); ++ byte[] mHash = getDigestValue(); ++ if (useKaeSign()) { ++ return kaeSign(mHash); ++ } ++ return sunSign(mHash); ++ } ++ ++ // determine whether use kae verify ++ private boolean useKaeVerify() { ++ return isValidDigest(); ++ } ++ ++ // sun verify ++ private boolean sunVerify(byte[] mHash, byte[] sigBytes) throws SignatureException { ++ try { ++ byte[] decrypted = RSACore.rsa(sigBytes, this.pubKey); ++ return decodeSignature(mHash, decrypted); ++ } catch (javax.crypto.BadPaddingException e) { ++ // occurs if the app has used the wrong RSA public key ++ // or if sigBytes is invalid ++ // return false rather than propagating the exception for ++ // compatibility/ease of use ++ return false; ++ } catch (IOException e) { ++ throw new SignatureException("Signature encoding error", e); ++ } finally { ++ resetDigest(); ++ } ++ } ++ ++ // kae verify ++ private boolean kaeVerify(byte[] mHash, byte[] sigBytes) throws SignatureException { ++ String kaeDigestName = KAEUtils.getKAEDigestName(this.sigParams.getDigestAlgorithm()); ++ String mgfDigestName = kaeDigestName; ++ AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); ++ if (mgfParams != null) { ++ mgfDigestName = ++ ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); ++ } ++ String mgf1KaeDigestName = KAEUtils.getKAEDigestName(mgfDigestName); ++ ++ long keyAddress = KAERSACipher.nativeCreateRSAPublicKey(this.pubKey.getModulus().toByteArray(), ++ this.pubKey.getPublicExponent().toByteArray()); ++ boolean verify; ++ try { ++ verify = KAERSASignatureNative.pssVerify(keyAddress, kaeDigestName, mHash, ++ KAERSAPaddingType.PKCS1PssPadding.getId(), mgf1KaeDigestName, ++ this.sigParams.getSaltLength(), sigBytes); ++ } catch (SignatureException e) { ++ throw e; ++ } catch (BadPaddingException e) { ++ // occurs if the app has used the wrong RSA public key ++ // or if sigBytes is invalid or sourceBytes is invalid ++ // return false rather than propagating the exception for ++ // compatibility/ease of use ++ return false; ++ } finally { ++ resetDigest(); ++ KAERSACipher.nativeFreeKey(keyAddress); ++ } ++ return verify; ++ } ++ ++ // verify the data and return the result. See JCA doc ++ // should be reset to the state after engineInitVerify call. ++ @Override ++ protected boolean engineVerify(byte[] sigBytes) throws SignatureException { ++ ensureInit(); ++ if (sigBytes.length != RSACore.getByteLength(this.pubKey)) { ++ throw new SignatureException("Signature length not correct: got " + ++ sigBytes.length + " but was expecting " + ++ RSACore.getByteLength(this.pubKey)); ++ } ++ byte[] mHash = getDigestValue(); ++ if (useKaeVerify()) { ++ return kaeVerify(mHash, sigBytes); ++ } ++ return sunVerify(mHash, sigBytes); ++ } ++ ++ // return the modulus length in bits ++ private static int getKeyLengthInBits(RSAKey k) { ++ if (k != null) { ++ return k.getModulus().bitLength(); ++ } ++ return -1; ++ } ++ ++ /** ++ * Encode the digest 'mHash', return the to-be-signed data. ++ * Also used by the PKCS#11 provider. ++ */ ++ private byte[] encodeSignature(byte[] mHash) throws IOException, DigestException { ++ AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); ++ String mgfDigestAlgo; ++ if (mgfParams != null) { ++ mgfDigestAlgo = ++ ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); ++ } else { ++ mgfDigestAlgo = this.md.getAlgorithm(); ++ } ++ try { ++ int emBits = getKeyLengthInBits(this.privKey) - 1; ++ int emLen = (emBits + 7) >> 3; ++ int hLen = this.md.getDigestLength(); ++ int dbLen = emLen - hLen - 1; ++ int sLen = this.sigParams.getSaltLength(); ++ ++ // maps DB into the corresponding region of EM and ++ // stores its bytes directly into EM ++ byte[] em = new byte[emLen]; ++ ++ // step7 and some of step8 ++ em[dbLen - sLen - 1] = (byte) 1; // set DB's padding2 into EM ++ em[em.length - 1] = (byte) 0xBC; // set trailer field of EM ++ ++ if (!digestReset) { ++ throw new ProviderException("Digest should be reset"); ++ } ++ // step5: generates M' using padding1, mHash, and salt ++ this.md.update(EIGHT_BYTES_OF_ZEROS); ++ digestReset = false; // mark digest as it now has data ++ this.md.update(mHash); ++ if (sLen != 0) { ++ // step4: generate random salt ++ byte[] salt = new byte[sLen]; ++ this.random.nextBytes(salt); ++ this.md.update(salt); ++ ++ // step8: set DB's salt into EM ++ System.arraycopy(salt, 0, em, dbLen - sLen, sLen); ++ } ++ // step6: generate H using M' ++ this.md.digest(em, dbLen, hLen); // set H field of EM ++ digestReset = true; ++ ++ // step7 and 8 are already covered by the code which setting up ++ // EM as above ++ ++ // step9 and 10: feed H into MGF and xor with DB in EM ++ KAEMGF1 mgf1 = new KAEMGF1(mgfDigestAlgo); ++ mgf1.generateAndXor(em, dbLen, hLen, dbLen, em, 0); ++ // step11: set the leftmost (8emLen - emBits) bits of the leftmost ++ // octet to 0 ++ int numZeroBits = (emLen << 3) - emBits; ++ if (numZeroBits != 0) { ++ byte mask = (byte) (0xff >>> numZeroBits); ++ em[0] = (byte) (em[0] & mask); ++ } ++ ++ // step12: em should now holds maskedDB || hash h || 0xBC ++ return em; ++ } catch (NoSuchAlgorithmException | RuntimeException e) { ++ e.printStackTrace(); ++ throw new IOException(e.toString()); ++ } ++ } ++ ++ private String getMgfDigestAlgo() { ++ String mgfDigestAlgo; ++ AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters(); ++ if (mgfParams != null) { ++ mgfDigestAlgo = ++ ((MGF1ParameterSpec) mgfParams).getDigestAlgorithm(); ++ } else { ++ mgfDigestAlgo = this.md.getAlgorithm(); ++ } ++ return mgfDigestAlgo; ++ } ++ ++ private void generateAndXor(String mgfDigestAlgo, byte[] em, int dbLen, int hLen) throws IOException { ++ try { ++ KAEMGF1 mgf1 = new KAEMGF1(mgfDigestAlgo); ++ mgf1.generateAndXor(em, dbLen, hLen, dbLen, em, 0); ++ } catch (NoSuchAlgorithmException | RuntimeException e) { ++ e.printStackTrace(); ++ throw new IOException(e.toString()); ++ } ++ } ++ ++ /** ++ * Decode the signature data. Verify that the object identifier matches ++ * and return the message digest. ++ */ ++ private boolean decodeSignature(byte[] mHash, byte[] em) throws IOException { ++ int hLen = mHash.length; ++ int sLen = this.sigParams.getSaltLength(); ++ int emLen = em.length; ++ int emBits = getKeyLengthInBits(this.pubKey) - 1; ++ ++ // step3 ++ if (emLen < (hLen + sLen + 2)) { ++ return false; ++ } ++ ++ // step4 ++ if (em[emLen - 1] != (byte) 0xBC) { ++ return false; ++ } ++ ++ // step6: check if the leftmost (8emLen - emBits) bits of the leftmost ++ // octet are 0 ++ int numZeroBits = (emLen << 3) - emBits; ++ if (numZeroBits != 0) { ++ byte mask = (byte) (0xff << (8 - numZeroBits)); ++ if ((em[0] & mask) != 0) { ++ return false; ++ } ++ } ++ ++ // step 7 and 8 ++ int dbLen = emLen - hLen - 1; ++ ++ // generateAndXor ++ String mgfDigestAlgo = getMgfDigestAlgo(); ++ generateAndXor(mgfDigestAlgo, em, dbLen, hLen); ++ ++ // step9: set the leftmost (8emLen - emBits) bits of the leftmost ++ // octet to 0 ++ if (numZeroBits != 0) { ++ byte mask = (byte) (0xff >>> numZeroBits); ++ em[0] = (byte) (em[0] & mask); ++ } ++ ++ // step10 ++ int index = 0; ++ for (; index < dbLen - sLen - 1; index++) { ++ if (em[index] != 0) { ++ return false; ++ } ++ } ++ if (em[index] != 0x01) { ++ return false; ++ } ++ // step12 and 13 ++ this.md.update(EIGHT_BYTES_OF_ZEROS); ++ digestReset = false; ++ this.md.update(mHash); ++ if (sLen > 0) { ++ this.md.update(em, (dbLen - sLen), sLen); ++ } ++ byte[] digest2 = this.md.digest(); ++ digestReset = true; ++ ++ // step14 ++ byte[] digestInEM = Arrays.copyOfRange(em, dbLen, emLen - 1); ++ return MessageDigest.isEqual(digest2, digestInEM); ++ } ++ ++ // set parameter, not supported. See JCA doc ++ @Deprecated ++ @Override ++ protected void engineSetParameter(String param, Object value) throws InvalidParameterException { ++ throw new UnsupportedOperationException("setParameter() not supported"); ++ } ++ ++ @Override ++ protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { ++ this.sigParams = validateSigParams(params); ++ // disallow changing parameters when digest has been used ++ if (!digestReset) { ++ throw new ProviderException ++ ("Cannot set parameters during operations"); ++ } ++ String newHashAlg = this.sigParams.getDigestAlgorithm(); ++ // re-allocate md if not yet assigned or algorithm changed ++ if ((this.md == null) || ++ !(this.md.getAlgorithm().equalsIgnoreCase(newHashAlg))) { ++ try { ++ this.md = MessageDigest.getInstance(newHashAlg); ++ } catch (NoSuchAlgorithmException nsae) { ++ // should not happen as we pick default digest algorithm ++ throw new InvalidAlgorithmParameterException("Unsupported digest algorithm " + newHashAlg, nsae); ++ } ++ } ++ } ++ ++ // get parameter, not supported. See JCA doc ++ @Deprecated ++ @Override ++ protected Object engineGetParameter(String param) throws InvalidParameterException { ++ throw new UnsupportedOperationException("getParameter() not supported"); ++ } ++ ++ @Override ++ protected AlgorithmParameters engineGetParameters() { ++ AlgorithmParameters ap = null; ++ if (this.sigParams != null) { ++ try { ++ ap = AlgorithmParameters.getInstance("RSASSA-PSS"); ++ ap.init(this.sigParams); ++ } catch (GeneralSecurityException gse) { ++ throw new ProviderException(gse.getMessage()); ++ } ++ } ++ return ap; ++ } ++} ++ +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPaddingType.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPaddingType.java +new file mode 100644 +index 000000000..35e7f2f67 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPaddingType.java +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (c) 2023, 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")) ++ ), ++ ++ // PSS ++ PKCS1PssPadding(6, "RSA_PKCS1_PSS_PADDING"); ++ ++ private final int id; ++ private final String name; ++ private final Set 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 supportPaddings) { ++ this.id = id; ++ this.name = name; ++ this.supportPaddings = supportPaddings; ++ } ++ ++ public Set getSupportPaddings() { ++ return supportPaddings; ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignature.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignature.java +new file mode 100644 +index 000000000..b91a8cdaa +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignature.java +@@ -0,0 +1,365 @@ ++/* ++ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.io.IOException; ++import java.nio.ByteBuffer; ++ ++import java.security.*; ++import java.security.interfaces.*; ++import java.security.spec.AlgorithmParameterSpec; ++ ++import sun.security.rsa.RSACore; ++import sun.security.rsa.RSAKeyFactory; ++import sun.security.rsa.RSAPadding; ++import sun.security.rsa.RSAUtil; ++import sun.security.rsa.RSAUtil.KeyType; ++import sun.security.util.*; ++import sun.security.x509.AlgorithmId; ++ ++import javax.crypto.BadPaddingException; ++ ++/** ++ * We support support rsa signatures with MD2, MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512 as the digest algorithm. ++ * The Openssl does not support rsa signatures with SHA-512/224 and SHA-512/256 as the digest algorithm, ++ * so we have not implemented them. ++ * The Openssl does not support non-CRT private key , when signing with a non-CRT private key, we use the sun sign. ++ */ ++public abstract class KAERSASignature extends SignatureSpi { ++ // we sign an ASN.1 SEQUENCE of AlgorithmId and digest ++ // it has the form 30:xx:30:xx:[digestOID]:05:00:04:xx:[digest] ++ // this means the encoded length is (8 + digestOID.length + digest.length) ++ private static final int BASE_LENGTH = 8; ++ ++ private String digestAlgorithm; ++ ++ // object identifier for the message digest algorithm used ++ private final ObjectIdentifier digestOID; ++ ++ // length of the encoded signature blob ++ private final int encodedLength; ++ ++ // message digest implementation we use ++ private final MessageDigest md; ++ ++ // flag indicating whether the digest is reset ++ private boolean digestReset; ++ ++ // private key, if initialized for signing ++ private RSAPrivateKey privateKey; ++ ++ // public key, if initialized for verifying ++ private RSAPublicKey publicKey; ++ ++ // padding to use, set when the initSign/initVerify is called ++ private RSAPadding padding; ++ ++ /** ++ * Construct a new RSASignature. Used by subclasses. ++ */ ++ KAERSASignature(String algorithm, ObjectIdentifier digestOID, int oidLength) { ++ this.digestAlgorithm = algorithm; ++ this.digestOID = digestOID; ++ try { ++ md = MessageDigest.getInstance(algorithm); ++ } catch (NoSuchAlgorithmException e) { ++ throw new ProviderException(e); ++ } ++ digestReset = true; ++ encodedLength = BASE_LENGTH + oidLength + md.getDigestLength(); ++ } ++ ++ // initialize for verification. See JCA doc ++ @Override ++ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { ++ RSAPublicKey rsaKey = (RSAPublicKey) RSAKeyFactory.toRSAKey(publicKey); ++ this.privateKey = null; ++ this.publicKey = rsaKey; ++ initCommon(rsaKey, null); ++ } ++ ++ // initialize for signing. See JCA doc ++ @Override ++ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { ++ engineInitSign(privateKey, null); ++ } ++ ++ // initialize for signing. See JCA doc ++ @Override ++ protected void engineInitSign(PrivateKey privateKey, SecureRandom random) throws InvalidKeyException { ++ RSAPrivateKey rsaKey = ++ (RSAPrivateKey) RSAKeyFactory.toRSAKey(privateKey); ++ this.privateKey = rsaKey; ++ this.publicKey = null; ++ initCommon(rsaKey, random); ++ } ++ ++ /** ++ * Init code common to sign and verify. ++ */ ++ private void initCommon(RSAKey rsaKey, SecureRandom random) throws InvalidKeyException { ++ try { ++ RSAUtil.checkParamsAgainstType(KeyType.RSA, rsaKey.getParams()); ++ } catch (ProviderException e) { ++ throw new InvalidKeyException("Invalid key for RSA signatures", e); ++ } ++ resetDigest(); ++ int keySize = RSACore.getByteLength(rsaKey); ++ try { ++ padding = RSAPadding.getInstance ++ (RSAPadding.PAD_BLOCKTYPE_1, keySize, random); ++ } catch (InvalidAlgorithmParameterException iape) { ++ throw new InvalidKeyException(iape.getMessage()); ++ } ++ int maxDataSize = padding.getMaxDataSize(); ++ if (encodedLength > maxDataSize) { ++ throw new InvalidKeyException ++ ("Key is too short for this signature algorithm"); ++ } ++ } ++ ++ /** ++ * Reset the message digest if it is not already reset. ++ */ ++ private void resetDigest() { ++ if (digestReset == false) { ++ md.reset(); ++ digestReset = true; ++ } ++ } ++ ++ /** ++ * Return the message digest value. ++ */ ++ private byte[] getDigestValue() { ++ digestReset = true; ++ return md.digest(); ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(byte b) throws SignatureException { ++ md.update(b); ++ digestReset = false; ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { ++ md.update(b, off, len); ++ digestReset = false; ++ } ++ ++ // update the signature with the plaintext data. See JCA doc ++ @Override ++ protected void engineUpdate(ByteBuffer b) { ++ md.update(b); ++ digestReset = false; ++ } ++ ++ // sign the data and return the signature. See JCA doc ++ @Override ++ protected byte[] engineSign() throws SignatureException { ++ if (privateKey == null) { ++ throw new SignatureException("Missing private key"); ++ } ++ ++ byte[] digest = getDigestValue(); ++ if (useKaeSign()) { ++ return kaeSign(digest); ++ } ++ return sunSign(digest); ++ } ++ ++ // determine if use kae sign , openssl do not support non-CRT private key ++ private boolean useKaeSign() { ++ return privateKey instanceof RSAPrivateCrtKey; ++ } ++ ++ // sun sign ++ private byte[] sunSign(byte[] digest) throws SignatureException { ++ try { ++ byte[] encoded = encodeSignature(digestOID, digest); ++ byte[] padded = padding.pad(encoded); ++ return RSACore.rsa(padded, privateKey, true); ++ } catch (GeneralSecurityException e) { ++ throw new SignatureException("Could not sign data", e); ++ } catch (IOException e) { ++ throw new SignatureException("Could not encode data", e); ++ } ++ } ++ ++ // kae sign ++ private byte[] kaeSign(byte[] digest) throws SignatureException { ++ String kaeDigestName = KAEUtils.getKAEDigestName(this.digestAlgorithm); ++ RSAPrivateCrtKey privateCrtKey = (RSAPrivateCrtKey) privateKey; ++ long keyAddress = KAERSACipher.nativeCreateRSAPrivateCrtKey( ++ privateCrtKey.getModulus().toByteArray(), ++ privateCrtKey.getPublicExponent().toByteArray(), ++ privateCrtKey.getPrivateExponent().toByteArray(), ++ privateCrtKey.getPrimeP().toByteArray(), ++ privateCrtKey.getPrimeQ().toByteArray(), ++ privateCrtKey.getPrimeExponentP().toByteArray(), ++ privateCrtKey.getPrimeExponentQ().toByteArray(), ++ privateCrtKey.getCrtCoefficient().toByteArray()); ++ byte[] sigBytes; ++ try { ++ sigBytes = KAERSASignatureNative.rsaSign(keyAddress, ++ kaeDigestName, digest, KAERSAPaddingType.PKCS1Padding.getId()); ++ } catch (SignatureException e) { ++ throw e; ++ } finally { ++ // free keyAddress ++ KAERSACipher.nativeFreeKey(keyAddress); ++ } ++ return sigBytes; ++ } ++ ++ // verify the data and return the result. See JCA doc ++ @Override ++ protected boolean engineVerify(byte[] sigBytes) throws SignatureException { ++ if (publicKey == null) { ++ throw new SignatureException("Missing public key"); ++ } ++ ++ boolean verify; ++ long keyAddress = 0L; ++ try { ++ if (sigBytes.length != RSACore.getByteLength(publicKey)) { ++ throw new SignatureException("Signature length not correct: got " + ++ sigBytes.length + " but was expecting " + ++ RSACore.getByteLength(publicKey)); ++ } ++ ++ String kaeDigestName = KAEUtils.getKAEDigestName(this.digestAlgorithm); ++ byte[] digest = getDigestValue(); ++ keyAddress = KAERSACipher.nativeCreateRSAPublicKey(publicKey.getModulus().toByteArray(), ++ publicKey.getPublicExponent().toByteArray()); ++ verify = KAERSASignatureNative.rsaVerify(keyAddress, ++ kaeDigestName, digest, KAERSAPaddingType.PKCS1Padding.getId(), sigBytes); ++ } catch (SignatureException e) { ++ throw e; ++ } catch (BadPaddingException e) { ++ // occurs if the app has used the wrong RSA public key ++ // or if sigBytes is invalid or sourceBytes is invalid ++ // return false rather than propagating the exception for ++ // compatibility/ease of use ++ return false; ++ } finally { ++ // reset digest ++ resetDigest(); ++ // free keyAddress ++ if (keyAddress != 0L) { ++ KAERSACipher.nativeFreeKey(keyAddress); ++ } ++ } ++ return verify; ++ } ++ ++ /** ++ * Encode the digest, return the to-be-signed data. ++ * Also used by the PKCS#11 provider. ++ */ ++ public static byte[] encodeSignature(ObjectIdentifier oid, byte[] digest) throws IOException { ++ DerOutputStream out = new DerOutputStream(); ++ new AlgorithmId(oid).encode(out); ++ out.putOctetString(digest); ++ DerValue result = ++ new DerValue(DerValue.tag_Sequence, out.toByteArray()); ++ return result.toByteArray(); ++ } ++ ++ // set parameter, not supported. See JCA doc ++ @Deprecated ++ @Override ++ protected void engineSetParameter(String param, Object value) throws InvalidParameterException { ++ throw new UnsupportedOperationException("setParameter() not supported"); ++ } ++ ++ // See JCA doc ++ @Override ++ protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { ++ if (params != null) { ++ throw new InvalidAlgorithmParameterException("No parameters accepted"); ++ } ++ } ++ ++ // get parameter, not supported. See JCA doc ++ @Deprecated ++ @Override ++ protected Object engineGetParameter(String param) throws InvalidParameterException { ++ throw new UnsupportedOperationException("getParameter() not supported"); ++ } ++ ++ // See JCA doc ++ @Override ++ protected AlgorithmParameters engineGetParameters() { ++ return null; ++ } ++ ++ // Nested class for MD5withRSA signatures ++ public static final class MD5withRSA extends KAERSASignature { ++ public MD5withRSA() { ++ super("MD5", AlgorithmId.MD5_oid, 10); ++ } ++ } ++ ++ // Nested class for SHA1withRSA signatures ++ public static final class SHA1withRSA extends KAERSASignature { ++ public SHA1withRSA() { ++ super("SHA-1", AlgorithmId.SHA_oid, 7); ++ } ++ } ++ ++ // Nested class for SHA224withRSA signatures ++ public static final class SHA224withRSA extends KAERSASignature { ++ public SHA224withRSA() { ++ super("SHA-224", AlgorithmId.SHA224_oid, 11); ++ } ++ } ++ ++ // Nested class for SHA256withRSA signatures ++ public static final class SHA256withRSA extends KAERSASignature { ++ public SHA256withRSA() { ++ super("SHA-256", AlgorithmId.SHA256_oid, 11); ++ } ++ } ++ ++ // Nested class for SHA384withRSA signatures ++ public static final class SHA384withRSA extends KAERSASignature { ++ public SHA384withRSA() { ++ super("SHA-384", AlgorithmId.SHA384_oid, 11); ++ } ++ } ++ ++ // Nested class for SHA512withRSA signatures ++ public static final class SHA512withRSA extends KAERSASignature { ++ public SHA512withRSA() { ++ super("SHA-512", AlgorithmId.SHA512_oid, 11); ++ } ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignatureNative.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignatureNative.java +new file mode 100644 +index 000000000..dda2f068d +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSASignatureNative.java +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.BadPaddingException; ++import java.security.SignatureException; ++ ++public class KAERSASignatureNative { ++ // rsa sign ++ protected static native byte[] rsaSign(long keyAddress, String digestName, byte[] digestBytes, int paddingType) ++ throws SignatureException; ++ ++ // rsa verify ++ protected static native boolean rsaVerify(long keyAddress, String digestName, byte[] digestBytes, int paddingType, ++ byte[] sigBytes) throws SignatureException, BadPaddingException; ++ ++ // rsa pss sign ++ protected static native byte[] pssSign(long keyAddress, String digestName, byte[] digestBytes, int paddingType, ++ String mgf1DigestName, int saltLen) throws SignatureException; ++ ++ // rsa pss verify ++ protected static native boolean pssVerify(long keyAddress, String digestName, byte[] digestBytes, int paddingType, ++ String mgf1DigestName, int saltLen, byte[] sigBytes) throws SignatureException, BadPaddingException; ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4Cipher.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4Cipher.java +new file mode 100644 +index 000000000..a3e47606d +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4Cipher.java +@@ -0,0 +1,370 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.util.Debug; ++ ++import java.nio.ByteBuffer; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidKeyException; ++import java.security.NoSuchAlgorithmException; ++import java.security.Key; ++import java.security.ProviderException; ++import java.util.Locale; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.IllegalBlockSizeException; ++import javax.crypto.NoSuchPaddingException; ++import javax.crypto.ShortBufferException; ++ ++/* ++ * This class currently supports: ++ * - SM4/ECB/NOPADDING ++ * - SM4/ECB/PKCS5PADDING ++ * - SM4/CBC/NOPADDING ++ * - SM4/CBC/PKCS5PADDING ++ * - SM4/CTR/NOPADDING ++ * - SM4/OFB/NOPADDING ++ * - SM4/OFB/PKCS5PADDING ++ */ ++abstract class KAESM4Cipher extends KAESymmetricCipherBase { ++ ++ private static final Debug debug = Debug.getInstance("kae"); ++ ++ /* ++ * SM4 max chunk size of each encryption or decryption ++ * when input data does not have an accessible byte[] ++ */ ++ private static final int DEFAULT_KAE_SM4_MAX_CHUNK_SIZE = 4096; ++ private static int KAE_SM4_MAX_CHUNK_SIZE; ++ static { ++ initSM4MaxChunkSize(); ++ } ++ ++ private static void initSM4MaxChunkSize() { ++ String maxChunkSize = KAEConfig.privilegedGetOverridable("kae.sm4.maxChunkSize", ++ DEFAULT_KAE_SM4_MAX_CHUNK_SIZE + ""); ++ try { ++ KAE_SM4_MAX_CHUNK_SIZE = Integer.parseInt(maxChunkSize); ++ } catch (NumberFormatException e) { ++ // When parsing string argument to signed decimal integer fails, uses the default chunk size (4096) ++ KAE_SM4_MAX_CHUNK_SIZE = DEFAULT_KAE_SM4_MAX_CHUNK_SIZE; ++ if (debug != null) { ++ debug.println("The configured block size (" + maxChunkSize + ") cannot be converted to an integer, " + ++ "uses the default chunk size (" + DEFAULT_KAE_SM4_MAX_CHUNK_SIZE + ")"); ++ e.printStackTrace(); ++ } ++ return; ++ } ++ // when the configured chunk size is less than or equal to 0, uses the default chunk size (4096) ++ if (KAE_SM4_MAX_CHUNK_SIZE <= 0) { ++ KAE_SM4_MAX_CHUNK_SIZE = DEFAULT_KAE_SM4_MAX_CHUNK_SIZE; ++ if (debug != null) { ++ debug.println("The configured chunk size (" + KAE_SM4_MAX_CHUNK_SIZE + ") is less than " + ++ "or equal to 0, uses the default chunk size (" + DEFAULT_KAE_SM4_MAX_CHUNK_SIZE + ")"); ++ } ++ return; ++ } ++ if (debug != null) { ++ debug.println("The configured chunk size is " + KAE_SM4_MAX_CHUNK_SIZE); ++ } ++ } ++ ++ /** ++ * Used by the engineUpdate(ByteBuffer, ByteBuffer) and ++ * engineDoFinal(ByteBuffer, ByteBuffer) methods. ++ */ ++ private static int getSM4MaxChunkSize(int totalSize) { ++ return Math.min(KAE_SM4_MAX_CHUNK_SIZE, totalSize); ++ } ++ ++ public static class Sm4 extends KAESM4Cipher { ++ public Sm4(Mode mode, Padding padding) { ++ super(mode, padding, 16); ++ } ++ ++ public static class Cbc extends Sm4 { ++ 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 Sm4 { ++ 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 Sm4 { ++ public Ctr(Padding padding) { ++ super(Mode.CTR, padding); ++ } ++ public static class NoPadding extends Ctr { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ } ++ ++ public static class Ofb extends Sm4 { ++ public Ofb(Padding padding) { ++ super(Mode.OFB, padding); ++ } ++ public static class NoPadding extends Ofb { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Ofb { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ } ++ ++ KAESM4Cipher(Mode mode, Padding padding, int fixedKeySize) { ++ super(mode, padding, fixedKeySize, "SM4"); ++ } ++ ++ protected void checkKey(Key key) throws InvalidKeyException { ++ if (key == null || key.getEncoded() == null) { ++ throw new InvalidKeyException("Key cannot be null"); ++ } else { ++ int keyLen = key.getEncoded().length; ++ if (keyLen != fixedKeySize) { ++ throw new InvalidKeyException("Only " + fixedKeySize + "-byte keys are accepted. Got: " + keyLen); ++ } ++ } ++ } ++ ++ protected String getCipherName(int keyLength, Mode mode) { ++ return "sm4" + "-" + mode.toString().toLowerCase(Locale.US); ++ } ++ ++ @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 if (modeStr.equalsIgnoreCase("OFB")) { ++ mode = Mode.OFB; ++ } 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("PKCS7PADDING")) { ++ paddingStr = "PKCS5Padding"; ++ } ++ ++ 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 " + paddingStr); ++ } ++ } ++ ++ @Override ++ protected int engineUpdate(ByteBuffer input, ByteBuffer output) throws ShortBufferException { ++ try { ++ return bufferCrypt(input, output, true); ++ } catch (IllegalBlockSizeException e) { ++ // never thrown for engineUpdate() ++ throw new ProviderException("Internal error in update()"); ++ } catch (BadPaddingException e) { ++ // never thrown for engineUpdate() ++ throw new ProviderException("Internal error in update()"); ++ } ++ } ++ ++ @Override ++ protected int engineDoFinal(ByteBuffer input, ByteBuffer output) ++ throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { ++ return bufferCrypt(input, output, false); ++ } ++ ++ /** ++ * Implementation for encryption using ByteBuffers. Used for both ++ * engineUpdate() and engineDoFinal(). ++ */ ++ private int bufferCrypt(ByteBuffer input, ByteBuffer output, ++ boolean isUpdate) throws ShortBufferException, ++ IllegalBlockSizeException, BadPaddingException { ++ if ((input == null) || (output == null)) { ++ throw new NullPointerException ++ ("Input and output buffers must not be null"); ++ } ++ int inPos = input.position(); ++ int inLimit = input.limit(); ++ int inLen = inLimit - inPos; ++ if (isUpdate && (inLen == 0)) { ++ return 0; ++ } ++ int outLenNeeded = engineGetOutputSize(inLen); ++ ++ if (output.remaining() < outLenNeeded) { ++ throw new ShortBufferException("Need at least " + outLenNeeded ++ + " bytes of space in output buffer"); ++ } ++ ++ // detecting input and output buffer overlap may be tricky ++ // we can only write directly into output buffer when we ++ // are 100% sure it's safe to do so ++ ++ boolean a1 = input.hasArray(); ++ boolean a2 = output.hasArray(); ++ int total = 0; ++ ++ if (a1) { // input has an accessible byte[] ++ byte[] inArray = input.array(); ++ int inOfs = input.arrayOffset() + inPos; ++ ++ byte[] outArray; ++ if (a2) { // output has an accessible byte[] ++ outArray = output.array(); ++ int outPos = output.position(); ++ int outOfs = output.arrayOffset() + outPos; ++ ++ // check array address and offsets and use temp output buffer ++ // if output offset is larger than input offset and ++ // falls within the range of input data ++ boolean useTempOut = false; ++ if (inArray == outArray && ++ ((inOfs < outOfs) && (outOfs < inOfs + inLen))) { ++ useTempOut = true; ++ outArray = new byte[outLenNeeded]; ++ outOfs = 0; ++ } ++ if (isUpdate) { ++ total = engineUpdate(inArray, inOfs, inLen, outArray, outOfs); ++ } else { ++ total = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs); ++ } ++ if (useTempOut) { ++ output.put(outArray, outOfs, total); ++ } else { ++ // adjust output position manually ++ output.position(outPos + total); ++ } ++ } else { // output does not have an accessible byte[] ++ if (isUpdate) { ++ outArray = engineUpdate(inArray, inOfs, inLen); ++ } else { ++ outArray = engineDoFinal(inArray, inOfs, inLen); ++ } ++ if (outArray != null && outArray.length != 0) { ++ output.put(outArray); ++ total = outArray.length; ++ } ++ } ++ // adjust input position manually ++ input.position(inLimit); ++ } else { // input does not have an accessible byte[] ++ // have to assume the worst, since we have no way of determine ++ // if input and output overlaps or not ++ byte[] tempOut = new byte[outLenNeeded]; ++ int outOfs = 0; ++ ++ byte[] tempIn = new byte[getSM4MaxChunkSize(inLen)]; ++ do { ++ int chunk = Math.min(inLen, tempIn.length); ++ if (chunk > 0) { ++ input.get(tempIn, 0, chunk); ++ } ++ int n; ++ if (isUpdate || (inLen > chunk)) { ++ n = engineUpdate(tempIn, 0, chunk, tempOut, outOfs); ++ } else { ++ n = engineDoFinal(tempIn, 0, chunk, tempOut, outOfs); ++ } ++ outOfs += n; ++ total += n; ++ inLen -= chunk; ++ } while (inLen > 0); ++ if (total > 0) { ++ output.put(tempOut, 0, total); ++ } ++ } ++ ++ return total; ++ } ++ ++ protected void checkIvBytes(byte[] ivBytes) throws InvalidAlgorithmParameterException { ++ if (ivBytes == null) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: iv is null "); ++ } ++ if (mode == Mode.CTR) { ++ // For compatibility, SM4 CTR allows 8 < IV < blockSize, the remaining bytes will be filled with 0 in engineInit ++ if (ivBytes.length < 8 || ivBytes.length > blockSize) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: CTR mode requires IV of at least" + ++ "8 bytes, and no greater than " + blockSize + "bytes"); ++ } ++ return; ++ } ++ if (ivBytes.length != blockSize) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: must be " + blockSize + " bytes long."); ++ } ++ } ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4KeyGenerator.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4KeyGenerator.java +new file mode 100644 +index 000000000..3f60e804f +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4KeyGenerator.java +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (c) 2023, 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. Huawei designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Huawei 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 visit https://gitee.com/openeuler/bgmprovider if you need additional ++ * information or have any questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import javax.crypto.KeyGeneratorSpi; ++import javax.crypto.SecretKey; ++import javax.crypto.spec.SecretKeySpec; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidParameterException; ++import java.security.SecureRandom; ++import java.security.spec.AlgorithmParameterSpec; ++ ++public class KAESM4KeyGenerator extends KeyGeneratorSpi { ++ private byte[] key; ++ private int keySize = 16; // default keysize (in number of bytes) ++ private SecureRandom random; ++ ++ @Override ++ protected void engineInit(SecureRandom random) { ++ this.random = random; ++ } ++ ++ @Override ++ protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidAlgorithmParameterException { ++ throw new InvalidAlgorithmParameterException ++ ("SM4 key generation does not take any parameters"); ++ } ++ ++ @Override ++ protected void engineInit(int keysize, SecureRandom random) { ++ if (keysize != 128) { ++ throw new InvalidParameterException("SM4 requires a 128 bit key"); ++ } ++ this.keySize = keysize / 8; ++ engineInit(random); ++ } ++ ++ private static class SecureRandomHolder { ++ static final SecureRandom RANDOM = new SecureRandom(); ++ } ++ ++ @Override ++ protected SecretKey engineGenerateKey() { ++ key = new byte[keySize]; ++ if (random == null) { ++ random = SecureRandomHolder.RANDOM; ++ } ++ random.nextBytes(key); ++ return new SecretKeySpec(key, "SM4"); ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESymmetricCipherBase.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESymmetricCipherBase.java +new file mode 100644 +index 000000000..7b5433b38 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESymmetricCipherBase.java +@@ -0,0 +1,791 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.nio.ByteBuffer; ++import java.security.*; ++import java.security.spec.*; ++import java.util.Arrays; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++import javax.crypto.*; ++import javax.crypto.spec.GCMParameterSpec; ++import javax.crypto.spec.IvParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++ ++/* ++ * Cipher wrapper class utilizing openssl APIs. ++ */ ++abstract class KAESymmetricCipherBase extends CipherSpi { ++ enum Padding { ++ NOPADDING, ++ PKCS5PADDING ++ } ++ ++ enum Mode { ++ ECB, ++ CBC, ++ CTR, ++ OFB, ++ GCM ++ } ++ ++ protected final String keyAlgo; ++ protected final int blockSize = 16; ++ protected Mode mode; ++ protected Padding padding; ++ protected 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; ++ ++ // for gcm ++ private final int defaultGcmTagLen = blockSize; ++ private final int defaultGcmIvLen = 12; ++ private int tagLengthInBytes; ++ private byte[] lastEncKey = null; ++ private byte[] lastEncIv = null; ++ private byte[] aad; ++ ++ private static 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 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 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; ++ } ++ ++ KAESymmetricCipherBase(Mode mode, Padding padding, int fixedKeySize, String keyAlgo) { ++ this.mode = mode; ++ this.padding = padding; ++ this.fixedKeySize = fixedKeySize; ++ this.keyAlgo = keyAlgo; ++ } ++ ++ private static class CipherContextRef extends PhantomReference ++ implements Comparable { ++ private static ReferenceQueue refQueue = new ReferenceQueue<>(); ++ private static Set 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(KAESymmetricCipherBase 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 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; ++ } ++ AlgorithmParameterSpec spec; ++ AlgorithmParameters params; ++ String algName = keyAlgo; ++ if (mode == Mode.GCM) { ++ algName = "GCM"; ++ spec = new GCMParameterSpec(tagLengthInBytes * 8, iv.clone()); ++ } else { ++ spec = new IvParameterSpec(iv.clone()); ++ } ++ try { ++ params = AlgorithmParameters.getInstance(algName); ++ params.init(spec); ++ 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 spec = null; ++ String paramType = null; ++ if (params != null) { ++ try { ++ if (mode == Mode.GCM) { ++ spec = params.getParameterSpec(GCMParameterSpec.class); ++ paramType = "GCM"; ++ } else { ++ spec = params.getParameterSpec(IvParameterSpec.class); ++ paramType = "IV"; ++ } ++ } catch (InvalidParameterSpecException e) { ++ throw new InvalidAlgorithmParameterException("Could not decode " + paramType, e); ++ } ++ } ++ engineInit(opmode, key, spec, 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; ++ int tagLen = -1; ++ if (params != null) { ++ if (mode == Mode.GCM) { ++ if (params instanceof GCMParameterSpec) { ++ tagLen = ((GCMParameterSpec)params).getTLen(); ++ checkTagLen(tagLen); ++ tagLen = tagLen >> 3; ++ ivBytes = ((GCMParameterSpec)params).getIV(); ++ } else { ++ throw new InvalidAlgorithmParameterException("Unsupported parameter: " + params); ++ } ++ } else { ++ if (params instanceof IvParameterSpec) { ++ ivBytes = ((IvParameterSpec) params).getIV(); ++ checkIvBytes(ivBytes); ++ } else { ++ throw new InvalidKeyException("IvParameterSpec required. Received: " + params.getClass().getName()); ++ } ++ } ++ } ++ if (mode == Mode.ECB) { ++ if (params != null) { ++ throw new InvalidAlgorithmParameterException("No Parameters for ECB mode"); ++ } ++ } else if (ivBytes == null) { ++ if (doEncrypt) { ++ if (mode == Mode.GCM) { ++ ivBytes = new byte[defaultGcmIvLen]; ++ } else { ++ ivBytes = new byte[blockSize]; ++ } ++ if (random == null) { ++ random = JCAUtil.getSecureRandom(); ++ } ++ random.nextBytes(ivBytes); ++ } else { ++ throw new InvalidAlgorithmParameterException("Parameters required for decryption"); ++ } ++ } else if (keyAlgo.equalsIgnoreCase("SM4") && ivBytes.length < blockSize) { ++ byte[] temp = new byte[blockSize]; ++ System.arraycopy(ivBytes, 0, temp, 0, ivBytes.length); ++ ivBytes = temp; ++ } ++ implInit(doEncrypt, key.getEncoded(), ivBytes, tagLen); ++ } ++ ++ private void checkTagLen(int tagLen) throws InvalidAlgorithmParameterException { ++ if ((tagLen < 96) || (tagLen > 128) || ((tagLen & 0x07) != 0)) { ++ throw new InvalidAlgorithmParameterException ++ ("Unsupported TLen value; must be one of {128, 120, 112, 104, 96}"); ++ } ++ } ++ ++ protected abstract void checkIvBytes(byte[] ivBytes) throws InvalidAlgorithmParameterException; ++ ++ protected abstract String getCipherName(int keyLength, Mode mode); ++ ++ private void implInit(boolean encrypt, byte[] keyVal, byte[] ivVal, int tagLen) ++ throws InvalidAlgorithmParameterException { ++ reset(true); ++ this.encrypt = encrypt; ++ this.keyValue = keyVal; ++ this.iv = ivVal; ++ this.cipherName = getCipherName(keyValue.length * 8, mode); ++ ++ if (mode == Mode.GCM) { ++ if (tagLen == -1) { ++ tagLen = defaultGcmTagLen; ++ } ++ this.tagLengthInBytes = tagLen; ++ if (encrypt) { ++ // Check key+iv for encryption in GCM mode. ++ boolean requireReinit = Arrays.equals(ivVal, lastEncIv) && MessageDigest.isEqual(keyVal, lastEncKey); ++ if (requireReinit) { ++ throw new InvalidAlgorithmParameterException("Cannot reuse iv for GCM encryption"); ++ } ++ lastEncIv = ivVal; ++ lastEncKey = keyVal; ++ } ++ } ++ ++ // 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; ++ } ++ ++ protected abstract void checkKey(Key key) throws InvalidKeyException; ++ ++ @Override ++ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { ++ byte[] out = new byte[getOutputSizeByOperation(inputLen, false)]; ++ int outLen = implUpdate(input, inputOffset, inputLen, out, 0); ++ if (outLen == 0) { ++ return new byte[0]; ++ } else if (out.length != outLen) { ++ out = Arrays.copyOf(out, outLen); ++ } ++ 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 == null || output.length - outputOffset < min) { ++ throw new ShortBufferException("min " + min + "-byte buffer needed"); ++ } ++ return implUpdate(input, inputOffset, inputLen, output, outputOffset); ++ } ++ ++ private int implUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) { ++ ensureInitialized(); ++ if (inputLen <= 0) { ++ return 0; ++ } ++ int outLen; ++ try { ++ outLen = nativeUpdate(pCtx.ctxAddress, input, inputOffset, inputLen, output, outputOffset, ++ mode == Mode.GCM, aad); ++ aad = null; ++ } catch (ArrayIndexOutOfBoundsException e) { ++ reset(true); ++ throw new ProviderException("Invoke nativeUpdate failed for " + cipherName, e); ++ } ++ bytesBuffered += (inputLen - outLen); ++ ++ calledUpdate = true; ++ return outLen; ++ } ++ ++ protected int getOutputSizeByOperation(int inLen, boolean isDoFinal) { ++ int ret; ++ ++ if (inLen <= 0) { ++ inLen = 0; ++ } ++ if (padding == Padding.NOPADDING) { ++ ret = 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; ++ ret = len - (len % blockSize); ++ } ++ if (mode == Mode.GCM && isDoFinal) { ++ if (encrypt) { ++ ret = ret + tagLengthInBytes; ++ } else { ++ ret = Math.max(0, ret - tagLengthInBytes); ++ } ++ } ++ return ret; ++ } ++ ++ @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 == null || output.length - outputOffset < min) { ++ throw new ShortBufferException("min " + min + "-byte buffer needed"); ++ } ++ ++ int updateLen = inputLen; ++ if (mode == Mode.GCM && !encrypt) { ++ // Remove tagLengthInBytes suffix in GCM decrypt. ++ updateLen = inputLen - tagLengthInBytes; ++ } ++ outLen = implUpdate(input, inputOffset, updateLen, output, outputOffset); ++ outputOffset += outLen; ++ ++ byte[] gcmTag = null; ++ if (mode == Mode.GCM && !encrypt) { ++ if (inputLen - outLen != tagLengthInBytes) { ++ throw new AEADBadTagException("Tag mismatch!"); ++ } ++ // The last tagLengthInBytees in the input arg gcmTag. ++ gcmTag = Arrays.copyOfRange(input, inputOffset + inputLen - tagLengthInBytes, inputOffset + inputLen); ++ } ++ ++ outLen += implDoFinal(output, outputOffset, gcmTag); ++ 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); ++ } ++ ++ @Override ++ protected void engineUpdateAAD(ByteBuffer byteBuffer) { ++ if (aad == null) { ++ aad = new byte[byteBuffer.remaining()]; ++ byteBuffer.get(aad); ++ } else { ++ int newSize = aad.length + byteBuffer.remaining(); ++ byte[] newaad = new byte[newSize]; ++ System.arraycopy(aad, 0, newaad, 0, aad.length); ++ byteBuffer.get(newaad, aad.length, byteBuffer.remaining()); ++ aad = newaad; ++ } ++ } ++ ++ @Override ++ protected void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) { ++ if (aad == null) { ++ aad = Arrays.copyOfRange(input, inputOffset, inputOffset + inputLen); ++ } else { ++ int newSize = aad.length + inputLen; ++ byte[] newaad = new byte[newSize]; ++ System.arraycopy(aad, 0, newaad, 0, aad.length); ++ System.arraycopy(input, inputOffset, newaad, aad.length, inputLen); ++ aad = newaad; ++ } ++ } ++ ++ private int implDoFinal(byte[] out, int outputOffset, byte[] gcmTag) ++ throws BadPaddingException, IllegalBlockSizeException { ++ if (!encrypt && !calledUpdate) { ++ return 0; ++ } ++ ensureInitialized(); ++ ++ int outLen; ++ try { ++ if (mode == Mode.GCM) { ++ outLen = nativeFinalGcm(pCtx.ctxAddress, out, outputOffset, mode == Mode.GCM, tagLengthInBytes, ++ gcmTag, encrypt); ++ } else { ++ outLen = nativeFinal(pCtx.ctxAddress, out, outputOffset); ++ } ++ } catch (ArrayIndexOutOfBoundsException | BadPaddingException e) { ++ if (e instanceof AEADBadTagException) { ++ throw e; // AEADBadTagException is expected for some tests ++ } else if (e instanceof BadPaddingException) { ++ if (padding == Padding.NOPADDING || e.getMessage().contains("wrong final block length")) { ++ throw new IllegalBlockSizeException("Input length not multiple of " + blockSize + " bytes"); ++ } else { ++ throw e; ++ } ++ } else { ++ 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; ++ ++ // for gcm ++ aad = null; ++ ++ if (pCtx != null) { ++ pCtx.dispose(doCancel); ++ pCtx = null; ++ } ++ } ++ ++ protected static native long nativeInit(String cipherType, boolean encrypt, byte[] key, byte[] iv, boolean padding) ++ throws RuntimeException; ++ ++ protected static native int nativeUpdate(long pContext, byte[] in, int inOfs, int inLen, byte[] out, ++ int outOfs, boolean gcm, byte[] aad) throws ArrayIndexOutOfBoundsException; ++ ++ protected static native int nativeFinal(long pContext, byte[] out, ++ int outOfs) throws ArrayIndexOutOfBoundsException, BadPaddingException; ++ ++ protected static native void nativeFree(long pContext); ++ ++ protected static native int nativeFinalGcm(long pContext, byte[] out, int outOfs, boolean gcm, ++ int tagLength, byte[] gcmTag, boolean encrypt) throws ArrayIndexOutOfBoundsException, BadPaddingException; ++ ++ 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"); ++ } ++ } ++ } ++ ++ // copied from sun.security.jca.JCAUtil ++ // will be changed to reference that method once that code has been ++ // integrated and promoted ++ static int getTempArraySize(int totalSize) { ++ return Math.min(4096, totalSize); ++ } ++ ++ /** ++ * Continues a multiple-part encryption or decryption operation ++ * (depending on how this cipher was initialized), processing another data ++ * part. ++ * ++ *

All input.remaining() bytes starting at ++ * input.position() are processed. The result is stored ++ * in the output buffer. ++ * Upon return, the input buffer's position will be equal ++ * to its limit; its limit will not have changed. The output buffer's ++ * position will have advanced by n, where n is the value returned ++ * by this method; the output buffer's limit will not have changed. ++ * ++ *

If output.remaining() bytes are insufficient to ++ * hold the result, a ShortBufferException is thrown. ++ * ++ *

Subclasses should consider overriding this method if they can ++ * process ByteBuffers more efficiently than byte arrays. ++ * ++ * @param input the input ByteBuffer ++ * @param output the output ByteByffer ++ * ++ * @return the number of bytes stored in output ++ * ++ * @exception ShortBufferException if there is insufficient space in the ++ * output buffer ++ * ++ * @throws NullPointerException if either parameter is null ++ * @since 1.5 ++ */ ++ protected int engineUpdate(ByteBuffer input, ByteBuffer output) ++ throws ShortBufferException { ++ try { ++ return bufferCrypt(input, output, true); ++ } catch (IllegalBlockSizeException e) { ++ // never thrown for engineUpdate() ++ throw new ProviderException("Internal error in update()"); ++ } catch (BadPaddingException e) { ++ // never thrown for engineUpdate() ++ throw new ProviderException("Internal error in update()"); ++ } ++ } ++ ++ /** ++ * Finalize crypto operation with ByteBuffers ++ * ++ * @param input the input ByteBuffer ++ * @param output the output ByteBuffer ++ * ++ * @return output length ++ * @throws ShortBufferException ++ * @throws IllegalBlockSizeException ++ * @throws BadPaddingException ++ */ ++ @Override ++ protected int engineDoFinal(ByteBuffer input, ByteBuffer output) ++ throws ShortBufferException, IllegalBlockSizeException, ++ BadPaddingException { ++ return bufferCrypt(input, output, false); ++ } ++ ++ /** ++ * Implementation for encryption using ByteBuffers. Used for both ++ * engineUpdate() and engineDoFinal(). ++ */ ++ private int bufferCrypt(ByteBuffer input, ByteBuffer output, ++ boolean isUpdate) throws ShortBufferException, ++ IllegalBlockSizeException, BadPaddingException { ++ if ((input == null) || (output == null)) { ++ throw new NullPointerException ++ ("Input and output buffers must not be null"); ++ } ++ int inPos = input.position(); ++ int inLimit = input.limit(); ++ int inLen = inLimit - inPos; ++ if (isUpdate && (inLen == 0)) { ++ return 0; ++ } ++ int outLenNeeded = getOutputSizeByOperation(inLen, !isUpdate); ++ ++ if (output.remaining() < outLenNeeded) { ++ throw new ShortBufferException("Need at least " + outLenNeeded ++ + " bytes of space in output buffer"); ++ } ++ ++ // detecting input and output buffer overlap may be tricky ++ // we can only write directly into output buffer when we ++ // are 100% sure it's safe to do so ++ ++ boolean a1 = input.hasArray(); ++ boolean a2 = output.hasArray(); ++ int total = 0; ++ ++ if (a1) { // input has an accessible byte[] ++ byte[] inArray = input.array(); ++ int inOfs = input.arrayOffset() + inPos; ++ ++ if (a2) { // output has an accessible byte[] ++ byte[] outArray = output.array(); ++ int outPos = output.position(); ++ int outOfs = output.arrayOffset() + outPos; ++ ++ // check array address and offsets and use temp output buffer ++ // if output offset is larger than input offset and ++ // falls within the range of input data ++ boolean useTempOut = false; ++ if (inArray == outArray && ++ ((inOfs < outOfs) && (outOfs < inOfs + inLen))) { ++ useTempOut = true; ++ outArray = new byte[outLenNeeded]; ++ outOfs = 0; ++ } ++ if (isUpdate) { ++ total = engineUpdate(inArray, inOfs, inLen, outArray, outOfs); ++ } else { ++ total = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs); ++ } ++ if (useTempOut) { ++ output.put(outArray, outOfs, total); ++ } else { ++ // adjust output position manually ++ output.position(outPos + total); ++ } ++ // adjust input position manually ++ input.position(inLimit); ++ } else { // output does not have an accessible byte[] ++ byte[] outArray = null; ++ if (isUpdate) { ++ outArray = engineUpdate(inArray, inOfs, inLen); ++ } else { ++ outArray = engineDoFinal(inArray, inOfs, inLen); ++ } ++ if (outArray != null && outArray.length != 0) { ++ output.put(outArray); ++ total = outArray.length; ++ } ++ // adjust input position manually ++ input.position(inLimit); ++ } ++ } else { // input does not have an accessible byte[] ++ // have to assume the worst, since we have no way of determine ++ // if input and output overlaps or not ++ byte[] tempOut = new byte[outLenNeeded]; ++ int outOfs = 0; ++ ++ byte[] tempIn = new byte[getTempArraySize(inLen)]; ++ do { ++ int chunk = Math.min(inLen, tempIn.length); ++ if (chunk > 0) { ++ input.get(tempIn, 0, chunk); ++ } ++ int n; ++ if (isUpdate || (inLen > chunk)) { ++ n = engineUpdate(tempIn, 0, chunk, tempOut, outOfs); ++ } else { ++ n = engineDoFinal(tempIn, 0, chunk, tempOut, outOfs); ++ } ++ outOfs += n; ++ total += n; ++ inLen -= chunk; ++ } while (inLen > 0); ++ if (total > 0) { ++ output.put(tempOut, 0, total); ++ } ++ } ++ ++ return total; ++ } ++} ++ +diff --git a/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEUtils.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEUtils.java +new file mode 100644 +index 000000000..a4a005285 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEUtils.java +@@ -0,0 +1,220 @@ ++/* ++ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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 aliasNames; ++ ++ public String getDigestName() { ++ return digestName; ++ } ++ ++ public String getKaeDigestName() { ++ return kaeDigestName; ++ } ++ ++ public int getDigestLen() { ++ return digestLen; ++ } ++ ++ public Set getAliasNames() { ++ return aliasNames; ++ } ++ ++ MessageDigestType(String digestName, String kaeDigestName, int digestLen, Set 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 DIGEST_ALGORITHM_NAME_MAP = new HashMap<>(); ++ private static final Map DIGEST_ALGORITHM_LENGTH_MAP = new HashMap<>(); ++ ++ private static final Map SIZE_TO_CURVE = new HashMap<>(); ++ private static final Map CURVE_ALIAS = new HashMap<>(); ++ ++ static { ++ initDigest(); ++ initECDH(); ++ } ++ ++ 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 digestName == null ? null : DIGEST_ALGORITHM_NAME_MAP.get(digestName.toUpperCase(Locale.ROOT)); ++ } ++ ++ static Integer getDigestLength(String digestName) { ++ return digestName == null ? null : DIGEST_ALGORITHM_LENGTH_MAP.get(digestName.toUpperCase(Locale.ROOT)); ++ } ++ ++ 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); ++ } ++ } ++ } ++ ++ private static void initECDH() { ++ SIZE_TO_CURVE.put(224, "secp224r1"); ++ SIZE_TO_CURVE.put(256, "prime256v1"); ++ SIZE_TO_CURVE.put(384, "secp384r1"); ++ SIZE_TO_CURVE.put(521, "secp521r1"); ++ CURVE_ALIAS.put("secp256r1", "prime256v1"); ++ CURVE_ALIAS.put("1.3.132.0.33", "secp224r1"); ++ CURVE_ALIAS.put("1.3.132.0.34", "secp384r1"); ++ CURVE_ALIAS.put("1.3.132.0.35", "secp521r1"); ++ CURVE_ALIAS.put("1.2.840.10045.3.1.7", "prime256v1"); ++ } ++ ++ static String getCurveBySize(int size) { ++ return SIZE_TO_CURVE.get(size); ++ } ++ ++ static String getCurveByAlias(String alias) { ++ return CURVE_ALIAS.get(alias); ++ } ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/conf/security/kaeprovider.conf b/src/jdk.crypto.kaeprovider/linux/conf/security/kaeprovider.conf +new file mode 100644 +index 000000000..49ff98fd8 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/conf/security/kaeprovider.conf +@@ -0,0 +1,75 @@ ++# ++# This is the config file for KAEProvider. ++# These configuration properties support the use of jdk system properties, ++# and jdk system properties take precedence over file configuration properties. ++# For detailed usage, please refer to the user manual: ++# https://gitee.com/openeuler/bishengjdk-8/wikis/%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3/KAE%20Provider%E7%94%A8%E6%88%B7%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C ++# ++ ++# Algorithms are enabled by default if KAEProvider is used. ++# Delete # if you want to disable certain algorithm. ++# kae.md5=false ++# kae.sha256=false ++# kae.sha384=false ++# kae.sm3=false ++# kae.aes=false ++# kae.sm4=false ++# kae.hmac=false ++# kae.rsa=false ++# kae.dh=false ++# kae.ec=false ++ ++# Configure engine id, the default value is kae. ++# kae.engine.id=kae ++ ++# Configure whether libcrypto.so uses GLOBAL mode, uses LOCAL mode by default. ++# If you use uadk_engine, you need to enable this option. ++# kae.libcrypto.useGlobalMode=false ++ ++# The following configuration will only take effect when using KAEProvider. ++# Configure whether to enable KAE hardware acceleration for each category of algorithm. ++# The configurable value are as follows: ++# true : enable KAE hardware acceleration by default ++# false: use openssl soft calculation by default ++# The digest/sm4/rsa/dh category algorithm enable KAE hardware acceleration by default. ++# The aes/hmac/ec category algorithm use openssl soft calculation by default. ++# The ec category algorithm configuration does not take effect temporarily. and it ++# currently does not support KAE hardware acceleration, temporarily use openssl soft calculation. ++# kae.digest.useKaeEngine=true ++# kae.aes.useKaeEngine=false ++# kae.sm4.useKaeEngine=true ++# kae.hmac.useKaeEngine=false ++# kae.rsa.useKaeEngine=true ++# kae.dh.useKaeEngine=true ++# kae.ec.useKaeEngine=false ++# ++# Some engines do not fully support certain categories of algorithms, for example, the digest ++# algorithm implemented by kae engine only supports md5 and sm3.For more information, please refer to: ++# KAE : https://github.com/kunpengcompute/KAE#:~:text=Digest%20algorithm%3A%20SM3/MD5 ++# UADK: https://gitee.com/openeuler/uadk/wikis/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3/UADK%20quick%20start#11-uadk ++# ++# Users can disable unsupported algorithms through the following property configuration. ++# Disable algorithm to enable KAE hardware acceleration, use openssl soft algorithm instead. ++# The sha256, sha384 algorithms are disabled by default. ++# digest : md5,sha256,sha384,sm3 ++# aes : aes-128-ecb,aes-128-cbc,aes-128-ctr,aes-128-gcm, ++# aes-192-ecb,aes-192-cbc,aes-192-ctr,aes-192-gcm, ++# aes-256-ecb,aes-256-cbc,aes-256-ctr,aes-256-gcm ++# sm4 : sm4-ecb,sm4-cbc,sm4-ctr,sm4-ofb ++# hmac : hmac-md5,hmac-sha1,hmac-sha224,hmac-sha256,hmac-sha384,hmac-sha512 ++# rsa : rsa ++# dh : dh ++# ec : ec ++# kae.engine.disabledAlgorithms=sha256,sha384 ++ ++# SM4 max chunk size of each encryption or decryption. ++# when input data does not have an accessible byte[]. ++# The default value is 4096, when configuring a non-positive Integer type, use the default value of 4096. ++# kae.sm4.maxChunkSize=4096 ++ ++# Enable engine load log. ++# kae.log=true ++# ++# It only takes effect when the property kae.log value is true. ++# Configure log file path, default value is System.getProperty("user.dir") + "/ + "kae.log". ++# kae.log.file=/home/user/kae.log +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_cipher_rsa.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_cipher_rsa.c +new file mode 100644 +index 000000000..557d3965b +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_cipher_rsa.c +@@ -0,0 +1,471 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include "kae_log.h" ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "org_openeuler_security_openssl_KAERSACipher.h" ++ ++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); ++ } ++ if (rsa != NULL) { ++ RSA_free(rsa); ++ } ++ return resultSize; ++} ++ ++/* ++ * set rsa padding ++ */ ++static bool 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 false; ++ } ++ return true; ++} ++ ++/* ++ * set rsa mgf1 md ++ */ ++static bool 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 false; ++ } ++ if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkeyCtx, mgf1MD) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_mgf1_md", KAE_ThrowInvalidAlgorithmParameterException); ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * set rsa oaep md ++ */ ++static bool 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 false; ++ } ++ if (EVP_PKEY_CTX_set_rsa_oaep_md(pkeyCtx, oaepMD) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_oaep_md", KAE_ThrowInvalidAlgorithmParameterException); ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * set rsa oaep label ++ */ ++static bool 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 false; ++ } ++ return true; ++} ++ ++/* ++ * 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* ++ // You can refer to the issue #2774 to see more content ++ size_t outLen = 0; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("RSACryptOAEPPadding: kaeEngine => %p", kaeEngine); ++ ++ ++ EVP_PKEY* pkey = (EVP_PKEY*) keyAddress; ++ ++ // new ctx ++ // rsa encrypt/decrypt init ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == 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) || !SetRSAMgf1Md(env, pkeyCtx, mgf1MdAlgoUTF) || ++ !SetRSAOaepMd(env, pkeyCtx, oaepMdAlgoUTF)) { ++ 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)) { ++ 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; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSACipher_nativeCreateRSAPrivateCrtKey: kaeEngine => %p", kaeEngine); ++ ++ // 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 cleanup; ++ } ++ ++ // new pkey ++ pkey = EVP_PKEY_new(); ++ if (pkey == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // new rsa ++ rsa = RSA_new_method(kaeEngine); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "RSA_new_method", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // 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 cleanup; ++ } ++ ++ // 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 cleanup; ++ } ++ return (jlong)pkey; ++cleanup: ++ 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; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSACipher_nativeCreateRSAPublicKey: kaeEngine => %p", kaeEngine); ++ ++ // get public key param n ++ bnN = KAE_GetBigNumFromByteArray(env, n); ++ if (bnN == NULL) { ++ goto cleanup; ++ } ++ ++ // get public key param e ++ bnE = KAE_GetBigNumFromByteArray(env, e); ++ if (bnE == NULL) { ++ goto cleanup; ++ } ++ ++ // new rsa ++ rsa = RSA_new_method(kaeEngine); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "RSA_new_method", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // new EVP_PKEY ++ pkey = EVP_PKEY_new(); ++ if (pkey == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // 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 cleanup; ++ } ++ ++ // 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 cleanup; ++ } ++ return (jlong)pkey; ++cleanup: ++ 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); ++ } ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_digest.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_digest.c +new file mode 100644 +index 000000000..82bf477da +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_digest.c +@@ -0,0 +1,232 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include "kae_exception.h" ++#include "kae_log.h" ++#include "kae_util.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; ++ ENGINE* kaeEngine = NULL; ++ ++ if (algorithmName == NULL) { ++ KAE_ThrowNullPointerException(env, "algorithm is null"); ++ return 0; ++ } ++ ++ // EVP_get_digestbyname ++ const char* algo_utf = (*env)->GetStringUTFChars(env, algorithmName, 0); ++ kaeEngine = GetDigestEngineByAlgorithmName(algo_utf); ++ KAE_TRACE("KAEDigest_nativeInit: kaeEngine => %p", kaeEngine); ++ 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, kaeEngine); ++ if (result_code == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_DigestInit_ex failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ KAE_TRACE("KAEDigest_nativeInit EVP_DigestInit_ex(ctx = %p, md = %p) success", ctx, md); ++ ++ KAE_TRACE("KAEDigest_nativeInit: finished"); ++ return (jlong) ctx; ++ ++cleanup: ++ 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 cleanup; ++ } ++ KAE_TRACE("KAEDigest_nativeClone EVP_MD_CTX_copy_ex(ctxCopy = %p, ctx = %p) success", ctxCopy, ctx); ++ KAE_TRACE("KAEDigest_nativeClone: finished"); ++ return (jlong) ctxCopy; ++ ++cleanup: ++ 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"); ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.c +new file mode 100644 +index 000000000..c0579ebf4 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.c +@@ -0,0 +1,135 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include "kae_log.h" ++#include "kae_exception.h" ++#include "openssl_ad.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: ++ case EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH: ++ case EVP_F_EVP_PKEY_DECRYPT: ++ case EVP_R_PUBLIC_KEY_NOT_RSA: ++ case EVP_R_CTRL_NOT_IMPLEMENTED: ++ 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) { ++ defaultException(env, msg); ++ return; ++ } ++ ++ if (!(*env)->ExceptionCheck(env)) { ++ char estring[ESTRING_SIZE]; ++ ERR_error_string_n(err, estring, ESTRING_SIZE); ++ int lib = ERR_GET_LIB(err); ++ int func = ERR_GET_FUNC(err); ++ int reason = ERR_GET_REASON(err); ++ KAE_TRACE("OpenSSL error in %s: err=%lx, lib=%x, func=%x, reason=%x, file=%s, line=%d, estring=%s, data=%s", msg, err, ++ lib, func, reason, file, line, estring, (flags & ERR_TXT_STRING) ? data : "(no data)"); ++ // Ignore exceptions in RSA_verify_PKCS1_PSS_mgf1 function ++ if (lib == ERR_LIB_RSA && func == RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1) { ++ return; ++ } ++ ++ if (lib == ERR_LIB_EVP || lib == ERR_LIB_RSA) { ++ KAE_ThrowEvpException(env, reason, estring, defaultException); ++ } else { ++ defaultException(env, estring); ++ } ++ } ++ ++ ERR_clear_error(); ++} ++ ++void KAE_ThrowAEADBadTagException(JNIEnv *env, const char *msg) { ++ KAE_ThrowByName(env, "javax/crypto/AEADBadTagException", msg); ++} ++ ++void KAE_ThrowSignatureException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/security/SignatureException", msg); ++} ++ ++void KAE_ThrowClassNotFoundException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/ClassNotFoundException", msg); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.h b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.h +new file mode 100644 +index 000000000..f33f993e4 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.h +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (c) 2023, 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 ++ ++/* 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); ++ ++void KAE_ThrowAEADBadTagException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowSignatureException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowClassNotFoundException(JNIEnv* env, const char* msg); ++#endif +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_hmac.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_hmac.c +new file mode 100644 +index 000000000..ad7b86ecd +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_hmac.c +@@ -0,0 +1,208 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include "kae_exception.h" ++#include "kae_log.h" ++#include "kae_util.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_KAEHMac ++ * Method: nativeInit ++ * Signature: ([BILjava/lang/String;)J ++ */ ++JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAEHMac_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; ++ ENGINE* kaeEngine = NULL; ++ ++ const char* algo = (*env)->GetStringUTFChars(env, algoStr, 0); ++ md = EVPGetDigestByName(env, algo); ++ ++ kaeEngine = GetHmacEngineByAlgorithmName(algo); ++ KAE_TRACE("KAEHMac_nativeInit: kaeEngine => %p", kaeEngine); ++ ++ (*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 cleanup; ++ } ++ ++ // init hmac context with sc_key and evp_md ++ int result_code = HMAC_Init_ex(ctx, key_buffer, key_len, md, kaeEngine); ++ if (result_code == 0) { ++ KAE_ThrowRuntimeException(env, "Hmac_Init_ex invoked failed"); ++ goto cleanup; ++ } ++ free(key_buffer); ++ return (jlong) ctx; ++ ++cleanup: ++ free(key_buffer); ++ HMAC_CTX_free(ctx); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEHMac ++ * Method: nativeUpdate ++ * Signature: (J[BII)V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEHMac_nativeUpdate ++ (JNIEnv* env, jclass cls, jlong hmac_ctx, jbyteArray input, jint in_offset, jint in_len) { ++ KAE_TRACE("KAEHMac_nativeUpdate(ctx = %p, input = %p, offset = %d, inLen = %d)", (void*) 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_KAEHMac ++ * Method: nativeFinal ++ * Signature: (J[BII)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAEHMac_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("KAEHMac_nativeFinal success, output_offset = %d, bytesWritten = %u", out_offset, bytesWritten); ++ ++cleanup: ++ free(temp_result); ++ return bytesWritten; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEHMac ++ * Method: nativeFree ++ * Signature: (J)V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEHMac_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/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_dh.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_dh.c +new file mode 100644 +index 000000000..e9dfa4094 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_dh.c +@@ -0,0 +1,141 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include ++#include ++#include ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "kae_log.h" ++#include "org_openeuler_security_openssl_KAEDHKeyAgreement.h" ++ ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEDHKeyAgreement ++ * Method: nativeComputeKey ++ */ ++JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAEDHKeyAgreement_nativeComputeKey(JNIEnv* env, ++ jobject obj, jbyteArray y, jbyteArray x, jbyteArray p, jbyteArray g, jint pSize) { ++ ++ KAE_TRACE("Java_org_openeuler_security_openssl_KAEDHKeyAgreement_nativeComputeKey start."); ++ ++ DH* dh = NULL; ++ BIGNUM* y_bn = NULL; ++ BIGNUM* x_bn = NULL; ++ BIGNUM* p_bn = NULL; ++ BIGNUM* g_bn = NULL; ++ BIGNUM* computeKeyRetBn = NULL; ++ int computekeyLength = 0; ++ unsigned char* secret = NULL; ++ jbyteArray retByteArray = NULL; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(DH_INDEX); ++ KAE_TRACE("KAEDHKeyAgreement_nativeComputeKey: kaeEngine => %p", kaeEngine); ++ ++ // bits to Bytes ++ int pSizeInByte = (pSize +7) >> 3; ++ ++ if ((secret = (unsigned char*)malloc(pSizeInByte)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc secret failed."); ++ goto cleanup; ++ } ++ memset(secret, 0, pSizeInByte); ++ ++ if ((dh = DH_new_method(kaeEngine)) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate DH failed in nativeComputeKey."); ++ goto cleanup; ++ } ++ ++ if ((y_bn = KAE_GetBigNumFromByteArray(env, y)) == NULL) { ++ KAE_ThrowOOMException(env, "Convert y to BIGNUM failed."); ++ goto cleanup; ++ } ++ ++ if ((x_bn = KAE_GetBigNumFromByteArray(env, x)) == NULL) { ++ KAE_ThrowOOMException(env, "Convert x to BIGNUM failed."); ++ goto cleanup; ++ } ++ ++ if ((p_bn = KAE_GetBigNumFromByteArray(env, p)) == NULL) { ++ KAE_ThrowOOMException(env, "Convert p to BIGNUM failed."); ++ goto cleanup; ++ } ++ ++ if ((g_bn = KAE_GetBigNumFromByteArray(env, g)) == NULL) { ++ KAE_ThrowOOMException(env, "Convert g to BIGNUM failed."); ++ goto cleanup; ++ } ++ ++ if ((computeKeyRetBn = BN_new()) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate BN failed."); ++ goto cleanup; ++ } ++ ++ if (!DH_set0_pqg(dh, BN_dup(p_bn), NULL, BN_dup(g_bn))) { ++ KAE_ThrowRuntimeException(env, "DH_set0_pqg failed."); ++ goto cleanup; ++ } ++ ++ if (!DH_set0_key(dh, NULL, BN_dup(x_bn))) { ++ KAE_ThrowRuntimeException(env, "DH_set0_key failed."); ++ goto cleanup; ++ } ++ ++ computekeyLength = DH_compute_key(secret, y_bn, dh); ++ ++ if (computekeyLength <= 0 ) { ++ KAE_ThrowRuntimeException(env, "DH_compute_key failed."); ++ goto cleanup; ++ } ++ ++ BN_bin2bn(secret, computekeyLength, computeKeyRetBn); ++ ++ retByteArray = KAE_GetByteArrayFromBigNum(env, computeKeyRetBn); ++ if (retByteArray == NULL) { ++ KAE_ThrowRuntimeException(env, "GetByteArrayFromBigNum failed in nativeComputeKey."); ++ goto cleanup; ++ } ++ KAE_TRACE("Java_org_openeuler_security_openssl_KAEDHKeyAgreement_nativeComputeKey finished!"); ++ ++cleanup: ++ if (dh != NULL) ++ DH_free(dh); ++ if (y_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(y_bn); ++ if (x_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(x_bn); ++ if (p_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(p_bn); ++ if (g_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(g_bn); ++ if (secret != NULL) { ++ memset(secret, 0, pSizeInByte); ++ free(secret); ++ } ++ if (computeKeyRetBn != NULL) ++ BN_free(computeKeyRetBn); ++ ++ return retByteArray; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_ecdh.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_ecdh.c +new file mode 100644 +index 000000000..b0877a25e +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_ecdh.c +@@ -0,0 +1,121 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include "kae_log.h" ++#include "kae_exception.h" ++#include "kae_util.h" ++#include "org_openeuler_security_openssl_KAEECDHKeyAgreement.h" ++ ++static void FreeGenerateSecretParam(BIGNUM* s, BIGNUM* wX, BIGNUM* wY, ++ EC_POINT* pub, EC_KEY* eckey, EC_GROUP* group, unsigned char* shareKey, int shareKeyLen) ++{ ++ KAE_ReleaseBigNumFromByteArray(s); ++ KAE_ReleaseBigNumFromByteArray(wX); ++ KAE_ReleaseBigNumFromByteArray(wY); ++ if (pub != NULL) { ++ EC_POINT_free(pub); ++ } ++ if (eckey != NULL) { ++ EC_KEY_free(eckey); ++ } ++ if (group != NULL) { ++ EC_GROUP_free(group); ++ } ++ if (shareKey != NULL) { ++ memset(shareKey, 0, shareKeyLen); ++ free(shareKey); ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEECDHKeyAgreement ++ * Method: nativeGenerateSecret ++ * Signature: (Ljava/lang/String;[B[B[B)[B ++ */ ++JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAEECDHKeyAgreement_nativeGenerateSecret ++ (JNIEnv* env, jclass cls, jstring curveName, jbyteArray wXArr, jbyteArray wYArr, jbyteArray sArr) ++{ ++ EC_GROUP* group = NULL; ++ EC_KEY* eckey = NULL; ++ BIGNUM* wX = NULL; ++ BIGNUM* wY = NULL; ++ BIGNUM* s = NULL; ++ EC_POINT* pub = NULL; ++ jbyteArray javaBytes = NULL; ++ unsigned char* shareKey = NULL; ++ const char *curve = (*env)->GetStringUTFChars(env, curveName, 0); ++ int nid = OBJ_sn2nid(curve); ++ (*env)->ReleaseStringUTFChars(env, curveName, curve); ++ ++ // Initialization of secret key. ++ int expectSecretLen = 0; ++ ++ if ((nid == NID_undef) || (group = EC_GROUP_new_by_curve_name(nid)) == NULL) { ++ goto cleanup; ++ } ++ if ((s = KAE_GetBigNumFromByteArray(env, sArr)) == NULL || (wX = KAE_GetBigNumFromByteArray(env, wXArr)) == NULL ++ || (wY = KAE_GetBigNumFromByteArray(env, wYArr)) == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate BN_new"); ++ goto cleanup; ++ } ++ if ((eckey = EC_KEY_new()) == NULL || !EC_KEY_set_group(eckey, group)) { ++ goto cleanup; ++ } ++ if ((pub = EC_POINT_new(group)) == NULL) { ++ goto cleanup; ++ } ++ if (!EC_POINT_set_affine_coordinates_GFp(group, pub, wX, wY, NULL)) { ++ goto cleanup; ++ } ++ if (!EC_KEY_set_public_key(eckey, pub) || !EC_KEY_set_private_key(eckey, s)) { ++ goto cleanup; ++ } ++ ++ // Get the length of secret key, in bytes. ++ expectSecretLen = (EC_GROUP_get_degree(group) + 7) / 8; ++ ++ if ((shareKey = malloc(expectSecretLen)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(shareKey, 0, expectSecretLen); ++ ++ // Perform ecdh keyagreement. ++ if (ECDH_compute_key(shareKey, expectSecretLen, pub, eckey, NULL) != expectSecretLen) { ++ goto cleanup; ++ } ++ ++ if ((javaBytes = (*env)->NewByteArray(env, expectSecretLen)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, javaBytes, 0, expectSecretLen, (jbyte*)shareKey); ++ FreeGenerateSecretParam(s, wX, wY, pub, eckey, group, shareKey, expectSecretLen); ++ return javaBytes; ++ ++cleanup: ++ FreeGenerateSecretParam(s, wX, wY, pub, eckey, group, shareKey, expectSecretLen); ++ return NULL; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_dh.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_dh.c +new file mode 100644 +index 000000000..6315cc6ee +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_dh.c +@@ -0,0 +1,132 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include ++#include ++#include "kae_util.h" ++#include "kae_log.h" ++#include "org_openeuler_security_openssl_KAEDHKeyPairGenerator.h" ++#include "kae_exception.h" ++ ++ ++/* ++* Class: org_openeuler_security_openssl_KAEDHKeyPairGenerator ++* Method: nativeGenerateKeyPair ++* Signature: ([B[BI)[[B ++*/ ++ ++JNIEXPORT jobjectArray JNICALL Java_org_openeuler_security_openssl_KAEDHKeyPairGenerator_nativeGenerateKeyPair ++ (JNIEnv* env, jclass cls, jbyteArray p, jbyteArray g, jint lSize) ++{ ++ DH* dh = NULL; ++ BIGNUM* p_bn = NULL; ++ BIGNUM* g_bn = NULL; ++ const BIGNUM* pri_key_bn = NULL; ++ const BIGNUM* pub_key_bn = NULL; ++ jclass byteArrayClass = NULL; ++ jobjectArray keys = NULL; ++ jbyteArray pri_key = NULL; ++ jbyteArray pub_key = NULL; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(DH_INDEX); ++ KAE_TRACE("KAEDHKeyPairGenerator_nativeGenerateKeyPair: kaeEngine => %p", kaeEngine); ++ ++ KAE_TRACE("Java_org_openeuler_security_openssl_KAEDHKeyPairGenerator_nativeGenerateKeyPair start !"); ++ ++ if ((dh = DH_new_method(kaeEngine)) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate DH failed in nativeGenerateKeyPair!"); ++ goto cleanup; ++ } ++ ++ if ((p_bn = KAE_GetBigNumFromByteArray(env, p)) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate p_bn failed in nativeGenerateKeyPair!"); ++ goto cleanup; ++ } ++ ++ if ((g_bn = KAE_GetBigNumFromByteArray(env, g)) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate g_bn failed in nativeGenerateKeyPair!"); ++ goto cleanup; ++ } ++ ++ if (!DH_set0_pqg(dh, BN_dup(p_bn), NULL, BN_dup(g_bn))) { ++ KAE_ThrowRuntimeException(env, "DH_set0_pqg failed in nativeGenerateKeyPair."); ++ goto cleanup; ++ } ++ ++ // Return value is fixed to 1, nothing to check. ++ DH_set_length(dh, lSize); ++ ++ if (!DH_generate_key(dh)) { ++ KAE_ThrowInvalidAlgorithmParameterException(env, "DH generate key failed in nativeGenerateKeyPair."); ++ goto cleanup; ++ } ++ ++ if ((byteArrayClass = (*env)->FindClass(env, "[B")) == NULL) { ++ KAE_ThrowClassNotFoundException(env, "Class byte[] not found."); ++ goto cleanup; ++ } ++ ++ if ((keys = (*env)->NewObjectArray(env, 2, byteArrayClass, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "Allocate ByteArray failed in nativeGenerateKeyPair!"); ++ goto cleanup; ++ } ++ ++ // Return the ptr of private key in dh. ++ pri_key_bn = DH_get0_priv_key(dh); ++ pub_key_bn = DH_get0_pub_key(dh); ++ ++ pub_key = KAE_GetByteArrayFromBigNum(env, pub_key_bn); ++ if (pub_key == NULL) { ++ KAE_ThrowOOMException(env, "PublicKey allocate failed in nativeGenerateKeyPair."); ++ goto cleanup; ++ } ++ ++ pri_key = KAE_GetByteArrayFromBigNum(env, pri_key_bn); ++ if (pri_key == NULL) { ++ KAE_ThrowRuntimeException(env, "GetByteArrayFromBigNum failed in nativeGenerateKeyPair."); ++ goto cleanup; ++ } ++ ++ (*env)->SetObjectArrayElement(env, keys, 0, pub_key); ++ (*env)->SetObjectArrayElement(env, keys, 1, pri_key); ++ ++ KAE_TRACE("Java_org_openeuler_security_openssl_KAEDHKeyPairGenerator_nativeGenerateKeyPair finished !"); ++ ++cleanup: ++ if (dh != NULL) ++ DH_free(dh); ++ if (p_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(p_bn); ++ if (g_bn != NULL) ++ KAE_ReleaseBigNumFromByteArray(g_bn); ++ if (byteArrayClass != NULL) ++ (*env)->DeleteLocalRef(env, byteArrayClass); ++ if (pub_key != NULL) ++ (*env)->DeleteLocalRef(env, pub_key); ++ if (pri_key != NULL) ++ (*env)->DeleteLocalRef(env, pri_key); ++ ++ return keys; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_ec.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_ec.c +new file mode 100644 +index 000000000..0449f8a26 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_ec.c +@@ -0,0 +1,505 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "kae_log.h" ++#include "org_openeuler_security_openssl_KAEECKeyPairGenerator.h" ++ ++#define KAE_EC_PARAM_NUM_SIZE 7 ++#define KAE_EC_KEY_NUM_SIZE 3 ++ ++// ECDH param index. ++typedef enum ECDHParamIndex { ++ ecdhP = 0, ++ ecdhA, ++ ecdhB, ++ ecdhX, ++ ecdhY, ++ ecdhOrder, ++ ecdhCofactor ++} ECDHParamIndex; ++ ++// ECDH Key index. ++typedef enum ECDHKeyIndex { ++ ecdhWX = 0, ++ ecdhWY, ++ ecdhS ++} ECDHKeyIndex; ++ ++static void FreeECDHCurveParam(JNIEnv* env, BIGNUM* p, BIGNUM* a, BIGNUM* b, jbyteArray paramP, ++ jbyteArray paramA, jbyteArray paramB) ++{ ++ if (p != NULL) { ++ BN_free(p); ++ } ++ if (a != NULL) { ++ BN_free(a); ++ } ++ if (b != NULL) { ++ BN_free(b); ++ } ++ if (paramP != NULL) { ++ (*env)->DeleteLocalRef(env, paramP); ++ } ++ if (paramA != NULL) { ++ (*env)->DeleteLocalRef(env, paramA); ++ } ++ if (paramB != NULL) { ++ (*env)->DeleteLocalRef(env, paramB); ++ } ++} ++ ++// Set p, a, b in group to params. ++static bool SetECDHCurve(JNIEnv* env, EC_GROUP* group, jobjectArray params) ++{ ++ BIGNUM* p = NULL; ++ BIGNUM* a = NULL; ++ BIGNUM* b = NULL; ++ jbyteArray paramP = NULL; ++ jbyteArray paramA = NULL; ++ jbyteArray paramB = NULL; ++ if ((p = BN_new()) == NULL || (a = BN_new()) == NULL || (b = BN_new()) == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate BN_new"); ++ goto cleanup; ++ } ++ if (!EC_GROUP_get_curve_GFp(group, p, a, b, NULL)) { ++ goto cleanup; ++ } ++ ++ // Set p. ++ if ((paramP = KAE_GetByteArrayFromBigNum(env, p)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhP, paramP); ++ ++ // Set a. ++ if ((paramA = KAE_GetByteArrayFromBigNum(env, a)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhA, paramA); ++ ++ // Set b. ++ if ((paramB = KAE_GetByteArrayFromBigNum(env, b)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhB, paramB); ++ FreeECDHCurveParam(env, p, a, b, paramP, paramA, paramB); ++ return true; ++ ++cleanup: ++ FreeECDHCurveParam(env, p, a, b, paramP, paramA, paramB); ++ return false; ++} ++ ++// Set generator(x, y) in group to params. ++static bool SetECDHPoint(JNIEnv* env, EC_GROUP* group, jobjectArray params) ++{ ++ BIGNUM* x = NULL; ++ BIGNUM* y = NULL; ++ const EC_POINT* generator = NULL; ++ jbyteArray paramX = NULL; ++ jbyteArray paramY = NULL; ++ if ((x = BN_new()) == NULL || (y = BN_new()) == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate BN_new"); ++ goto cleanup; ++ } ++ if ((generator = EC_GROUP_get0_generator(group)) == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate ec generator"); ++ goto cleanup; ++ } ++ if (!EC_POINT_get_affine_coordinates_GFp(group, generator, x, y, NULL)) { ++ KAE_ThrowFromOpenssl(env, "EC_POINT_set_affine_coordinates_GFp", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ // Set x. ++ if ((paramX = KAE_GetByteArrayFromBigNum(env, x)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhX, paramX); ++ ++ // Set y. ++ if ((paramY = KAE_GetByteArrayFromBigNum(env, y)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhY, paramY); ++ BN_free(x); ++ BN_free(y); ++ (*env)->DeleteLocalRef(env, paramX); ++ (*env)->DeleteLocalRef(env, paramY); ++ return true; ++ ++cleanup: ++ if (x != NULL) { ++ BN_free(x); ++ } ++ if (y != NULL) { ++ BN_free(y); ++ } ++ if (paramX != NULL) { ++ (*env)->DeleteLocalRef(env, paramX); ++ } ++ if (paramY != NULL) { ++ (*env)->DeleteLocalRef(env, paramY); ++ } ++ return false; ++} ++ ++// Set order, cofactor in group to params. ++static bool SetECDHOrderAndCofactor(JNIEnv* env, EC_GROUP* group, jobjectArray params) ++{ ++ BIGNUM* order = NULL; ++ BIGNUM* cofactor = NULL; ++ jbyteArray paramOrder = NULL; ++ jbyteArray paramCofactor = NULL; ++ if ((order = BN_new()) == NULL || (cofactor = BN_new()) == NULL) { ++ goto cleanup; ++ } ++ if (!EC_GROUP_get_order(group, order, NULL)) { ++ goto cleanup; ++ } ++ ++ // Set order. ++ if ((paramOrder = KAE_GetByteArrayFromBigNum(env, order)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhOrder, paramOrder); ++ if (!EC_GROUP_get_cofactor(group, cofactor, NULL)) { ++ goto cleanup; ++ } ++ ++ // Set cofactor. ++ if ((paramCofactor = KAE_GetByteArrayFromBigNum(env, cofactor)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhCofactor, paramCofactor); ++ BN_free(order); ++ BN_free(cofactor); ++ (*env)->DeleteLocalRef(env, paramOrder); ++ (*env)->DeleteLocalRef(env, paramCofactor); ++ return true; ++ ++cleanup: ++ if (order != NULL) { ++ BN_free(order); ++ } ++ if (cofactor != NULL) { ++ BN_free(cofactor); ++ } ++ if (paramOrder != NULL) { ++ (*env)->DeleteLocalRef(env, paramOrder); ++ } ++ if (paramCofactor != NULL) { ++ (*env)->DeleteLocalRef(env, paramCofactor); ++ } ++ return false; ++} ++ ++static void FreeECDHKeyParam(JNIEnv* env, ++ BIGNUM* wX, BIGNUM* wY, jbyteArray keyWX, jbyteArray keyWY, jbyteArray keyS) ++{ ++ if (wX != NULL) { ++ BN_free(wX); ++ } ++ if (wY != NULL) { ++ BN_free(wY); ++ } ++ if (keyWX != NULL) { ++ (*env)->DeleteLocalRef(env, keyWX); ++ } ++ if (keyWY != NULL) { ++ (*env)->DeleteLocalRef(env, keyWY); ++ } ++ if (keyS != NULL) { ++ (*env)->DeleteLocalRef(env, keyS); ++ } ++} ++ ++// Set publicKey(wX, wY) and privateKey(s) in eckey to params. ++static bool SetECDHKey(JNIEnv* env, const EC_GROUP* group, jobjectArray params, ++ const EC_KEY* eckey) ++{ ++ BIGNUM* wX = NULL; ++ BIGNUM* wY = NULL; ++ const EC_POINT* pub = NULL; ++ const BIGNUM* s = NULL; ++ jbyteArray keyWX = NULL; ++ jbyteArray keyWY = NULL; ++ jbyteArray keyS = NULL; ++ if ((wX = BN_new()) == NULL || (wY = BN_new()) == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate array"); ++ goto cleanup; ++ } ++ ++ if ((pub = EC_KEY_get0_public_key(eckey)) == NULL || ++ !EC_POINT_get_affine_coordinates_GFp(group, pub, wX, wY, NULL)) { ++ goto cleanup; ++ } ++ if ((s = EC_KEY_get0_private_key(eckey)) == NULL) { ++ goto cleanup; ++ } ++ ++ // Set wX. ++ if ((keyWX = KAE_GetByteArrayFromBigNum(env, wX)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhWX, keyWX); ++ ++ // Set wY. ++ if ((keyWY = KAE_GetByteArrayFromBigNum(env, wY)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhWY, keyWY); ++ ++ // Set s. ++ if ((keyS = KAE_GetByteArrayFromBigNum(env, s)) == NULL) { ++ goto cleanup; ++ } ++ (*env)->SetObjectArrayElement(env, params, ecdhS, keyS); ++ FreeECDHKeyParam(env, wX, wY, keyWX, keyWY, keyS); ++ return true; ++ ++cleanup: ++ FreeECDHKeyParam(env, wX, wY, keyWX, keyWY, keyS); ++ return false; ++} ++ ++// Convert EC_GROUP in openssl to byte[][] in java ++static jobjectArray NewECDHParam(JNIEnv* env, EC_GROUP* group) ++{ ++ jclass byteArrayClass = (*env)->FindClass(env, "[B"); ++ jobjectArray params = (*env)->NewObjectArray(env, KAE_EC_PARAM_NUM_SIZE, byteArrayClass, NULL); ++ if (params == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate array"); ++ goto cleanup; ++ } ++ ++ if (!SetECDHCurve(env, group, params)) { ++ goto cleanup; ++ } ++ if (!SetECDHPoint(env, group, params)) { ++ goto cleanup; ++ } ++ if (!SetECDHOrderAndCofactor(env, group, params)) { ++ goto cleanup; ++ } ++ ++ (*env)->DeleteLocalRef(env, byteArrayClass); ++ return params; ++ ++cleanup: ++ if (byteArrayClass != NULL) { ++ (*env)->DeleteLocalRef(env, byteArrayClass); ++ } ++ if (params != NULL) { ++ (*env)->DeleteLocalRef(env, params); ++ } ++ return NULL; ++} ++ ++// Convert EC_KEY in openssl to byte[][] in java ++static jobjectArray NewECDHKey(JNIEnv* env, const EC_GROUP* group, const EC_KEY* eckey) ++{ ++ jclass byteArrayClass = (*env)->FindClass(env, "[B"); ++ jobjectArray params = (*env)->NewObjectArray(env, KAE_EC_KEY_NUM_SIZE, byteArrayClass, NULL); ++ if (params == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate array"); ++ goto cleanup; ++ } ++ if (!SetECDHKey(env, group, params, eckey)) { ++ goto cleanup; ++ } ++ ++ (*env)->DeleteLocalRef(env, byteArrayClass); ++ return params; ++ ++cleanup: ++ if (byteArrayClass != NULL) { ++ (*env)->DeleteLocalRef(env, byteArrayClass); ++ } ++ if (params != NULL) { ++ (*env)->DeleteLocalRef(env, params); ++ } ++ return NULL; ++} ++ ++static void FreeECDHParam(BIGNUM* p, BIGNUM* a, BIGNUM* b, BIGNUM* x, BIGNUM* y, BIGNUM* order, BIGNUM* cofactor) ++{ ++ KAE_ReleaseBigNumFromByteArray(p); ++ KAE_ReleaseBigNumFromByteArray(a); ++ KAE_ReleaseBigNumFromByteArray(b); ++ KAE_ReleaseBigNumFromByteArray(x); ++ KAE_ReleaseBigNumFromByteArray(y); ++ KAE_ReleaseBigNumFromByteArray(order); ++ KAE_ReleaseBigNumFromByteArray(cofactor); ++} ++ ++// Convert params in java to EC_GROUP in openssl ++static EC_GROUP* GetGroupByParam(JNIEnv* env, jbyteArray pArr, jbyteArray aArr, jbyteArray bArr, ++ jbyteArray xArr, jbyteArray yArr, jbyteArray orderArr, jint cofactorInt) ++{ ++ BIGNUM* p = NULL; ++ BIGNUM* a = NULL; ++ BIGNUM* b = NULL; ++ BIGNUM* x = NULL; ++ BIGNUM* y = NULL; ++ BIGNUM* order = NULL; ++ BIGNUM* cofactor = NULL; ++ EC_GROUP* group = NULL; ++ BN_CTX* ctx = NULL; ++ EC_POINT* generator = NULL; ++ if ((p = KAE_GetBigNumFromByteArray(env, pArr)) == NULL || (a = KAE_GetBigNumFromByteArray(env, aArr)) == NULL || ++ (b = KAE_GetBigNumFromByteArray(env, bArr)) == NULL || (x = KAE_GetBigNumFromByteArray(env, xArr)) == NULL || ++ (y = KAE_GetBigNumFromByteArray(env, yArr)) == NULL || (cofactor = BN_new()) == NULL || ++ (order = KAE_GetBigNumFromByteArray(env, orderArr)) == NULL || !BN_set_word(cofactor, cofactorInt)) { ++ goto cleanup; ++ } ++ ++ // Create the curve. ++ if ((ctx = BN_CTX_new()) == NULL || (group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) { ++ goto cleanup; ++ } ++ ++ // Create the generator and set x, y. ++ if ((generator = EC_POINT_new(group)) == NULL || ++ !EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, ctx)) { ++ goto cleanup; ++ } ++ ++ // Set the generator, order and cofactor. ++ if (!EC_GROUP_set_generator(group, generator, order, cofactor)) { ++ goto cleanup; ++ } ++ ++ FreeECDHParam(p, a, b, x, y, order, cofactor); ++ EC_POINT_free(generator); ++ BN_CTX_free(ctx); ++ return group; ++ ++cleanup: ++ FreeECDHParam(p, a, b, x, y, order, cofactor); ++ if (group != NULL) { ++ EC_GROUP_free(group); ++ } ++ if (generator != NULL) { ++ EC_POINT_free(generator); ++ } ++ if (ctx != NULL) { ++ BN_CTX_free(ctx); ++ } ++ return NULL; ++} ++ ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEECKeyPairGenerator ++ * Method: nativeGenerateParam ++ * Signature: (Ljava/lang/String;)[[B ++ */ ++JNIEXPORT jobjectArray JNICALL Java_org_openeuler_security_openssl_KAEECKeyPairGenerator_nativeGenerateParam( ++ JNIEnv* env, jclass cls, jstring curveName) ++{ ++ EC_GROUP* group = NULL; ++ jobjectArray ecdhParam = NULL; ++ ++ const char *curve = (*env)->GetStringUTFChars(env, curveName, 0); ++ KAE_TRACE("KAEECKeyPairGenerator_nativeGenerateParam(curveName = %s)", curve); ++ int nid = OBJ_sn2nid(curve); ++ (*env)->ReleaseStringUTFChars(env, curveName, curve); ++ if (nid == NID_undef) { ++ goto cleanup; ++ } ++ // Construct a builtin curve. ++ if ((group = EC_GROUP_new_by_curve_name(nid)) == NULL) { ++ goto cleanup; ++ } ++ ecdhParam = NewECDHParam(env, group); ++ ++ if (group != NULL) { ++ EC_GROUP_free(group); ++ } ++ KAE_TRACE("KAEECKeyPairGenerator_nativeGenerateParam success, ecdhParam = %p", ecdhParam); ++ return ecdhParam; ++ ++cleanup: ++ if (group != NULL) { ++ EC_GROUP_free(group); ++ } ++ if (ecdhParam != NULL) { ++ (*env)->DeleteLocalRef(env, ecdhParam); ++ } ++ return NULL; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEECKeyPairGenerator ++ * Method: nativeGenerateKeyPair ++ * Signature: ([B[B[B[B[B[BI)[[B ++ */ ++JNIEXPORT jobjectArray JNICALL Java_org_openeuler_security_openssl_KAEECKeyPairGenerator_nativeGenerateKeyPair( ++ JNIEnv* env, jclass cls, jbyteArray pArr, jbyteArray aArr, jbyteArray bArr, ++ jbyteArray xArr, jbyteArray yArr, jbyteArray orderArr, jint cofactorInt) ++{ ++ EC_GROUP* group = NULL; ++ EC_KEY* eckey = NULL; ++ jobjectArray ecdhKey = NULL; ++ ++ if ((group = GetGroupByParam(env, pArr, aArr, bArr, xArr, yArr, orderArr, cofactorInt)) == NULL) { ++ goto cleanup; ++ } ++ if ((eckey = EC_KEY_new()) == NULL) { ++ goto cleanup; ++ } ++ if (!EC_KEY_set_group(eckey, group)) { ++ goto cleanup; ++ } ++ // Generates a new public and private key for the supplied eckey object. ++ // Refer to {@link https://www.openssl.org/docs/man1.1.0/man3/EC_KEY_generate_key.html} for details. ++ if (!EC_KEY_generate_key(eckey)) { ++ goto cleanup; ++ } ++ ++ ecdhKey = NewECDHKey(env, group, eckey); ++ ++ EC_KEY_free(eckey); ++ EC_GROUP_free(group); ++ ++ KAE_TRACE("KAEECKeyPairGenerator_nativeGenerateKeyPair success, ecdhKey = %p", ecdhKey); ++ return ecdhKey; ++ ++cleanup: ++ if (eckey != NULL) { ++ EC_KEY_free(eckey); ++ } ++ if (group != NULL) { ++ EC_GROUP_free(group); ++ } ++ if (ecdhKey != NULL) { ++ (*env)->DeleteLocalRef(env, ecdhKey); ++ } ++ return NULL; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c +new file mode 100644 +index 000000000..84c2ed109 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c +@@ -0,0 +1,173 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include "kae_log.h" ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "org_openeuler_security_openssl_KAERSAKeyPairGenerator.h" ++#define KAE_RSA_PARAM_SIZE 8 ++ ++// rsa param index ++typedef enum RSAParamIndex { ++ rsaN = 0, ++ rsaE, ++ rsaD, ++ rsaP, ++ rsaQ, ++ rsaDmp1, ++ rsaDmq1, ++ rsaIqmp ++} 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) { ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("NewRSA: kaeEngine => %p", kaeEngine); ++ ++ // new rsa ++ RSA* rsa = RSA_new_method(kaeEngine); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "RSA_new_method", 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 value ++ * step 2. Convert paramValue (BIGNUM) to jbyteArray ++ * step 3. Set the rsa param to the param array ++ */ ++static bool SetRSAKeyParam(JNIEnv* env, RSA* rsa, jobjectArray params, RSAParamIndex rsaParamIndex) { ++ // get rsa param value ++ const BIGNUM* rsaParamValue = GetRSAParamFunctionList[rsaParamIndex](rsa); ++ if (rsaParamValue == NULL) { ++ return false; ++ } ++ ++ // Convert paramValue to jbyteArray ++ jbyteArray param = KAE_GetByteArrayFromBigNum(env, rsaParamValue); ++ if (param == NULL) { ++ return false; ++ } ++ ++ // Set the rsa param to the param array ++ (*env)->SetObjectArrayElement(env, params, rsaParamIndex, param); ++ return true; ++} ++ ++/* ++ * 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 ++ RSAParamIndex paramIndex; ++ for (paramIndex = rsaN; paramIndex <= rsaIqmp; paramIndex++) { ++ if (!SetRSAKeyParam(env, rsa, params, paramIndex)) { ++ 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; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_log.h b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_log.h +new file mode 100644 +index 000000000..b618546c5 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_log.h +@@ -0,0 +1,33 @@ ++/* ++ * Copyright (c) 2023, 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/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_provider.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_provider.c +new file mode 100644 +index 000000000..f4f71005a +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_provider.c +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include ++#include "kae_exception.h" ++#include "kae_util.h" ++#include "org_openeuler_security_openssl_KAEProvider.h" ++ ++#define KAE_OPENSSL_LIBRARY "libcrypto.so" ++ ++/* ++ * Class: Java_org_openeuler_security_openssl_KAEProvider ++ * Method: initOpenssl ++ * Signature: ()V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEProvider_initOpenssl ++ (JNIEnv *env, jclass cls, jboolean useGlobalMode, jstring engineId, jbooleanArray algorithmKaeFlags) { ++ SSL_load_error_strings(); ++ ERR_load_BIO_strings(); ++ OpenSSL_add_all_algorithms(); ++ ++ /* ++ * If the same shared object is opened again with dlopen(), the same object handle is returned. ++ * The dynamic linker maintains reference counts for object handles. ++ * An object that was previously opened with RTLD_LOCAL can be promoted to RTLD_GLOBAL in a subsequent dlopen(). ++ * ++ * RTLD_GLOBAL ++ * The symbols defined by this shared object will be made ++ * available for symbol resolution of subsequently loaded ++ * shared objects. ++ * RTLD_LOCAL ++ * This is the converse of RTLD_GLOBAL, and the default if ++ * neither flag is specified. Symbols defined in this shared ++ * object are not made available to resolve references in ++ * subsequently loaded shared objects. ++ * For more information see https://man7.org/linux/man-pages/man3/dlopen.3.html. ++ */ ++ if (useGlobalMode) { ++ char msg[1024]; ++ void *handle = NULL; ++ // Promote the flags of the loaded libcrypto.so library from RTLD_LOCAL to RTLD_GLOBAL ++ handle = dlopen(KAE_OPENSSL_LIBRARY, RTLD_LAZY | RTLD_GLOBAL); ++ if (handle == NULL) { ++ snprintf(msg, sizeof(msg), "Cannot load %s (%s)!", KAE_OPENSSL_LIBRARY, dlerror()); ++ KAE_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg); ++ return; ++ } ++ dlclose(handle); ++ } ++ ++ // check if KaeEngine holder is already set ++ ENGINE* e = GetKaeEngine(); ++ if (e != NULL) { ++ ENGINE_free(e); ++ e = NULL; ++ } ++ ++ // determine whether KAE is loaded successfully ++ const char* id = (*env)->GetStringUTFChars(env, engineId, 0); ++ e = ENGINE_by_id(id); ++ (*env)->ReleaseStringUTFChars(env, engineId, id); ++ if (e == NULL) { ++ KAE_ThrowFromOpenssl(env, "ENGINE_by_id", KAE_ThrowRuntimeException); ++ return; ++ } ++ SetKaeEngine(e); ++ ++ // initialize the engine for each algorithm ++ initEngines(env, algorithmKaeFlags); ++} ++ ++/* ++ * Class: Java_org_openeuler_security_openssl_KAEProvider ++ * Method: getEngineFlags ++ * Signature: ()V ++ */ ++JNIEXPORT jbooleanArray JNICALL Java_org_openeuler_security_openssl_KAEProvider_getEngineFlags ++ (JNIEnv *env, jclass cls) { ++ return getEngineFlags(env); ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_signature_rsa.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_signature_rsa.c +new file mode 100644 +index 000000000..496ebc775 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_signature_rsa.c +@@ -0,0 +1,366 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include ++#include "kae_log.h" ++#include "kae_util.h" ++#include "kae_exception.h" ++ ++// get EVP_MD by digestName ++static const EVP_MD* getEvpMd(JNIEnv* env, jstring digestName) { ++ const char* digestNameUtf = (*env)->GetStringUTFChars(env, digestName, 0); ++ const EVP_MD* md = (EVP_MD*)EVP_get_digestbyname(digestNameUtf); ++ (*env)->ReleaseStringUTFChars(env, digestName, digestNameUtf); ++ if (md == NULL) { ++ KAE_ThrowSignatureException(env, "Unsupported digest algorithm."); ++ } ++ return md; ++} ++ ++// sign release ++static void signRelease(JNIEnv* env, jbyteArray digestValue, jbyte* digestBytes, jbyte* sigBytes, ++ EVP_PKEY_CTX* pkeyCtx) { ++ if (digestBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, digestValue, digestBytes, 0); ++ } ++ if (sigBytes != NULL) { ++ free(sigBytes); ++ } ++ if (pkeyCtx != NULL) { ++ EVP_PKEY_CTX_free(pkeyCtx); ++ } ++} ++ ++// verify release ++static void verifyRelease(JNIEnv* env, jbyteArray digestValue, jbyte* digestBytes, jbyteArray sigValue, jbyte* sigBytes, ++ EVP_PKEY_CTX* pkeyCtx) { ++ if (digestBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, digestValue, digestBytes, 0); ++ } ++ if (sigBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, sigValue, sigBytes, 0); ++ } ++ if (pkeyCtx != NULL) { ++ EVP_PKEY_CTX_free(pkeyCtx); ++ } ++} ++ ++// set rsa PkeyCtx parameters ++static bool setRsaPkeyCtxParameters(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, jint paddingType, jstring digestName) { ++ // set rsa padding ++ if (EVP_PKEY_CTX_set_rsa_padding(pkeyCtx, paddingType) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_padding", KAE_ThrowSignatureException); ++ return false; ++ } ++ ++ // set signature md ++ const EVP_MD* md = getEvpMd(env, digestName); ++ if (md == NULL) { ++ return false; ++ } ++ ++ if (EVP_PKEY_CTX_set_signature_md(pkeyCtx, md) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_signature_md", KAE_ThrowSignatureException); ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSASignatureNative ++ * Method: rsaSign ++ * Signature: (JLjava/lang/String;[BI)[B ++ */ ++JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAERSASignatureNative_rsaSign(JNIEnv* env, jclass cls, ++ jlong keyAddress, jstring digestName, jbyteArray digestValue, jint paddingType) { ++ EVP_PKEY* pkey = (EVP_PKEY*)keyAddress; ++ EVP_PKEY_CTX* pkeyCtx = NULL; ++ jbyte* digestBytes = NULL; ++ jbyte* sigBytes = NULL; ++ jbyteArray sigByteArray = NULL; ++ static ENGINE* kaeEngine = NULL; ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ // new EVP_PKEY_CTX ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // sign init ++ if (EVP_PKEY_sign_init(pkeyCtx) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign_init", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set rsa PkeyCtx parameters ++ if (!setRsaPkeyCtxParameters(env, pkeyCtx, paddingType, digestName)) { ++ goto cleanup; ++ } ++ ++ // sign ++ size_t sigLen = (size_t)EVP_PKEY_size(pkey); ++ if (sigLen <= 0) { ++ KAE_ThrowSignatureException(env, "The sigLen size cannot be zero or negative"); ++ goto cleanup; ++ } ++ if ((sigBytes = malloc(sigLen)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ goto cleanup; ++ } ++ if ((digestBytes = (*env)->GetByteArrayElements(env, digestValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ size_t digestLen = (size_t)(*env)->GetArrayLength(env, digestValue); ++ if (EVP_PKEY_sign(pkeyCtx, (unsigned char*)sigBytes, &sigLen, ++ (const unsigned char*)digestBytes, digestLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set signature byte to jbyteArray ++ if ((sigByteArray = (*env)->NewByteArray(env, (jsize)sigLen)) == NULL) { ++ KAE_ThrowOOMException(env, "NewByteArray failed"); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, sigByteArray, 0, (jsize)sigLen, sigBytes); ++ ++cleanup: ++ signRelease(env, digestValue, digestBytes, sigBytes, pkeyCtx); ++ return sigByteArray; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSASignatureNative ++ * Method: rsaVerify ++ * Signature: (JLjava/lang/String;[BI[B)Z ++ */ ++JNIEXPORT jboolean JNICALL Java_org_openeuler_security_openssl_KAERSASignatureNative_rsaVerify(JNIEnv* env, jclass cls, ++ jlong keyAddress, jstring digestName, jbyteArray digestValue, jint paddingType, jbyteArray sigValue) { ++ EVP_PKEY* pkey = (EVP_PKEY*)keyAddress; ++ EVP_PKEY_CTX* pkeyCtx = NULL; ++ jbyte* digestBytes = NULL; ++ jbyte* sigBytes = NULL; ++ jboolean isSuccess = JNI_FALSE; ++ static ENGINE* kaeEngine = NULL; ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ // new EVP_PKEY_CTX ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // verify init ++ if (EVP_PKEY_verify_init(pkeyCtx) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign_init", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set rsa PkeyCtx parameters ++ if (!setRsaPkeyCtxParameters(env, pkeyCtx, paddingType, digestName)) { ++ goto cleanup; ++ } ++ ++ // verify ++ if ((digestBytes = (*env)->GetByteArrayElements(env, digestValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ if ((sigBytes = (*env)->GetByteArrayElements(env, sigValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ size_t sigLen = (size_t)(*env)->GetArrayLength(env, sigValue); ++ size_t digestLen = (size_t)(*env)->GetArrayLength(env, digestValue); ++ if (EVP_PKEY_verify(pkeyCtx, (const unsigned char*)sigBytes, sigLen, ++ (const unsigned char*)digestBytes, digestLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_verify", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ isSuccess = JNI_TRUE; ++ ++cleanup: ++ verifyRelease(env, digestValue, digestBytes, sigValue, sigBytes, pkeyCtx); ++ return isSuccess; ++} ++ ++// set pss pkeyCtx parameters ++static bool setPssPkeyCtxParameters(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, jint paddingType, jstring digestName, ++ jstring mgf1DigestName, jint saltLen) { ++ // set rsa padding ++ if (EVP_PKEY_CTX_set_rsa_padding(pkeyCtx, paddingType) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_padding", KAE_ThrowSignatureException); ++ return false; ++ } ++ ++ // set signature md ++ const EVP_MD* md = getEvpMd(env, digestName); ++ if (md == NULL) { ++ return false; ++ } ++ if (EVP_PKEY_CTX_set_signature_md(pkeyCtx, md) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_signature_md", KAE_ThrowSignatureException); ++ return false; ++ } ++ ++ // set rsa mgf1 md ++ const EVP_MD* mgf1Md = getEvpMd(env, mgf1DigestName); ++ if (mgf1Md == NULL) { ++ return false; ++ } ++ if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkeyCtx, mgf1Md) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_mgf1_md", KAE_ThrowSignatureException); ++ return false; ++ } ++ ++ // set salt len ++ if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkeyCtx, saltLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_pss_saltlen", KAE_ThrowSignatureException); ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSASignatureNative ++ * Method: pssSign ++ * Signature: (JLjava/lang/String;[BILjava/lang/String;I)[B ++ */ ++JNIEXPORT jbyteArray JNICALL Java_org_openeuler_security_openssl_KAERSASignatureNative_pssSign(JNIEnv* env, jclass cls, ++ jlong keyAddress, jstring digestName, jbyteArray digestValue, jint paddingType, jstring mgf1DigestName, ++ jint saltLen) { ++ EVP_PKEY* pkey = (EVP_PKEY*)keyAddress; ++ EVP_PKEY_CTX* pkeyCtx = NULL; ++ jbyte* digestBytes = NULL; ++ jbyte* sigBytes = NULL; ++ jbyteArray sigByteArray = NULL; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSASignatureNative_pssSign: kaeEngine => %p", kaeEngine); ++ ++ // new EVP_PKEY_CTX ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // sign init ++ if (EVP_PKEY_sign_init(pkeyCtx) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign_init", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set pss pkeyCtx parameters ++ if (!setPssPkeyCtxParameters(env, pkeyCtx, paddingType, digestName, mgf1DigestName, saltLen)) { ++ goto cleanup; ++ } ++ ++ // sign ++ size_t sigLen = (size_t)EVP_PKEY_size(pkey); ++ if (sigLen <= 0) { ++ KAE_ThrowSignatureException(env, "The sigLen size cannot be zero or negative"); ++ goto cleanup; ++ } ++ if ((sigBytes = malloc(sigLen)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ goto cleanup; ++ } ++ if ((digestBytes = (*env)->GetByteArrayElements(env, digestValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ size_t digestLen = (size_t)(*env)->GetArrayLength(env, digestValue); ++ if (EVP_PKEY_sign(pkeyCtx, (unsigned char*)sigBytes, &sigLen, ++ (const unsigned char*)digestBytes, digestLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set signature byte to jbyteArray ++ if ((sigByteArray = (*env)->NewByteArray(env, (jsize)sigLen)) == NULL) { ++ KAE_ThrowOOMException(env, "NewByteArray failed"); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, sigByteArray, 0, (jsize)sigLen, sigBytes); ++ ++cleanup: ++ signRelease(env, digestValue, digestBytes, sigBytes, pkeyCtx); ++ return sigByteArray; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSASignatureNative ++ * Method: pssVerify ++ * Signature: (JLjava/lang/String;[BILjava/lang/String;I[B)Z ++ */ ++JNIEXPORT jboolean JNICALL Java_org_openeuler_security_openssl_KAERSASignatureNative_pssVerify(JNIEnv* env, jclass cls, ++ jlong keyAddress, jstring digestName, jbyteArray digestValue, jint paddingType, jstring mgf1DigestName, ++ jint saltLen, jbyteArray sigValue) { ++ EVP_PKEY* pkey = (EVP_PKEY*)keyAddress; ++ EVP_PKEY_CTX* pkeyCtx = NULL; ++ jbyte* digestBytes = NULL; ++ jbyte* sigBytes = NULL; ++ jboolean isSuccess = JNI_FALSE; ++ ENGINE* kaeEngine = GetEngineByAlgorithmIndex(RSA_INDEX); ++ KAE_TRACE("KAERSASignatureNative_pssVerify: kaeEngine => %p", kaeEngine); ++ ++ // new EVP_PKEY_CTX ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, kaeEngine)) == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // verify init ++ if (EVP_PKEY_verify_init(pkeyCtx) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_sign_init", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ ++ // set pkeyCtx parameters ++ if (!setPssPkeyCtxParameters(env, pkeyCtx, paddingType, digestName, mgf1DigestName, saltLen)) { ++ goto cleanup; ++ } ++ ++ // verify ++ if ((digestBytes = (*env)->GetByteArrayElements(env, digestValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ if ((sigBytes = (*env)->GetByteArrayElements(env, sigValue, NULL)) == NULL) { ++ KAE_ThrowOOMException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ size_t sigLen = (size_t)(*env)->GetArrayLength(env, sigValue); ++ size_t digestLen = (size_t)(*env)->GetArrayLength(env, digestValue); ++ if (EVP_PKEY_verify(pkeyCtx, (const unsigned char*)sigBytes, sigLen, ++ (const unsigned char*)digestBytes, digestLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_verify", KAE_ThrowSignatureException); ++ goto cleanup; ++ } ++ isSuccess = JNI_TRUE; ++ ++cleanup: ++ verifyRelease(env, digestValue, digestBytes, sigValue, sigBytes, pkeyCtx); ++ return isSuccess; ++} +\ No newline at end of file +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_symmetric_cipher.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_symmetric_cipher.c +new file mode 100644 +index 000000000..67151f53a +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_symmetric_cipher.c +@@ -0,0 +1,415 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include ++#include ++#include ++#include "kae_exception.h" ++#include "kae_log.h" ++#include "kae_util.h" ++#include "org_openeuler_security_openssl_KAESymmetricCipherBase.h" ++ ++bool StartsWith(const char* str1, const char* str2) ++{ ++ if (str1 == NULL || str2 == NULL) { ++ return 0; ++ } ++ int len1 = strlen(str1); ++ int len2 = strlen(str2); ++ if (len1 > len2 || (len1 == 0 || len2 == 0)) { ++ return false; ++ } ++ const char *cur = str1; ++ int i = 0; ++ while (*cur != '\0') { ++ if (*cur != str2[i]) { ++ return 0; ++ } ++ cur++; ++ i++; ++ } ++ return true; ++} ++ ++static const EVP_CIPHER* EVPGetSm4CipherByName(JNIEnv* env, const char* algo) ++{ ++ static const EVP_CIPHER* sm4Ecb = NULL; ++ static const EVP_CIPHER* sm4Cbc = NULL; ++ static const EVP_CIPHER* sm4Ctr = NULL; ++ static const EVP_CIPHER* sm4Ofb = NULL; ++ ++ if (strcasecmp(algo, "sm4-ecb") == 0) { ++ return sm4Ecb == NULL ? sm4Ecb = EVP_get_cipherbyname(algo) : sm4Ecb; ++ } else if (strcasecmp(algo, "sm4-cbc") == 0) { ++ return sm4Cbc == NULL ? sm4Cbc = EVP_get_cipherbyname(algo) : sm4Cbc; ++ } else if (strcasecmp(algo, "sm4-ctr") == 0) { ++ return sm4Ctr == NULL ? sm4Ctr = EVP_get_cipherbyname(algo) : sm4Ctr; ++ } else if (strcasecmp(algo, "sm4-ofb") == 0) { ++ return sm4Ofb == NULL ? sm4Ofb = EVP_get_cipherbyname(algo) : sm4Ofb; ++ } else { ++ KAE_ThrowRuntimeException(env, "EVPGetSm4CipherByName error"); ++ return 0; ++ } ++} ++ ++static const EVP_CIPHER* EVPGetAesCipherByName(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* aes128Gcm = NULL; ++ static const EVP_CIPHER* aes192Ecb = NULL; ++ static const EVP_CIPHER* aes192Cbc = NULL; ++ static const EVP_CIPHER* aes192Ctr = NULL; ++ static const EVP_CIPHER* aes192Gcm = NULL; ++ static const EVP_CIPHER* aes256Ecb = NULL; ++ static const EVP_CIPHER* aes256Cbc = NULL; ++ static const EVP_CIPHER* aes256Ctr = NULL; ++ static const EVP_CIPHER* aes256Gcm = 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-128-gcm") == 0) { ++ return aes128Gcm == NULL ? aes128Gcm = EVP_get_cipherbyname(algo) : aes128Gcm; ++ } 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-192-gcm") == 0) { ++ return aes192Gcm == NULL ? aes192Gcm = EVP_get_cipherbyname(algo) : aes192Gcm; ++ } 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 if (strcasecmp(algo, "aes-256-gcm") == 0) { ++ return aes256Gcm == NULL ? aes256Gcm = EVP_get_cipherbyname(algo) : aes256Gcm; ++ } else { ++ KAE_ThrowRuntimeException(env, "EVPGetAesCipherByName error"); ++ return 0; ++ } ++} ++ ++void FreeMemoryFromInit(JNIEnv* env, jbyteArray iv, jbyte* ivBytes, jbyteArray key, jbyte* keyBytes, ++ int keyLength) ++{ ++ if (ivBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, iv, ivBytes, 0); ++ } ++ if (keyBytes != NULL) { ++ memset(keyBytes, 0, keyLength); ++ (*env)->ReleaseByteArrayElements(env, key, keyBytes, JNI_ABORT); ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAESymmetricCipherBase ++ * Method: nativeInit ++ * Signature: (Ljava/lang/String;Z[B[B)J ++ */ ++JNIEXPORT jlong JNICALL ++Java_org_openeuler_security_openssl_KAESymmetricCipherBase_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; ++ ENGINE* kaeEngine = NULL; ++ int keyLength = (*env)->GetArrayLength(env, key); ++ ++ const char* algo = (*env)->GetStringUTFChars(env, cipherType, 0); ++ if (StartsWith("aes", algo)) { ++ cipher = EVPGetAesCipherByName(env, algo); ++ kaeEngine = GetAesEngineByAlgorithmName(algo); ++ } else { ++ cipher = EVPGetSm4CipherByName(env, algo); ++ kaeEngine = GetSm4EngineByAlgorithmName(algo); ++ } ++ ++ KAE_TRACE("KAESymmetricCipherBase_nativeInit: kaeEngine => %p", kaeEngine); ++ ++ (*env)->ReleaseStringUTFChars(env, cipherType, algo); ++ if (cipher == NULL) { ++ KAE_ThrowOOMException(env, "create EVP_CIPHER fail"); ++ goto cleanup; ++ } ++ if ((ctx = EVP_CIPHER_CTX_new()) == NULL) { ++ KAE_ThrowOOMException(env, "create EVP_CIPHER_CTX fail"); ++ goto cleanup; ++ } ++ ++ if (iv != NULL) { ++ ivBytes = (*env)->GetByteArrayElements(env, iv, NULL); ++ } ++ if (key != NULL) { ++ keyBytes = (*env)->GetByteArrayElements(env, key, NULL); ++ } ++ ++ if (!EVP_CipherInit_ex(ctx, cipher, kaeEngine, (const unsigned char*)keyBytes, ++ (const unsigned char*)ivBytes, encrypt ? 1 : 0)) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherInit_ex failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ EVP_CIPHER_CTX_set_padding(ctx, padding ? 1 : 0); ++ ++ FreeMemoryFromInit(env, iv, ivBytes, key, keyBytes, keyLength); ++ return (jlong)ctx; ++ ++cleanup: ++ if (ctx != NULL) { ++ EVP_CIPHER_CTX_free(ctx); ++ } ++ FreeMemoryFromInit(env, iv, ivBytes, key, keyBytes, keyLength); ++ return 0; ++} ++ ++static void FreeMemoryFromUpdate(unsigned char* in, unsigned char* aad, unsigned char* out) ++{ ++ if (in != NULL) { ++ free(in); ++ } ++ if (out != NULL) { ++ free(out); ++ } ++ if (aad != NULL) { ++ free(aad); ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAESymmetricCipherBase ++ * Method: nativeUpdate ++ * Signature: (J[BII[BIZ[B)I ++ */ ++JNIEXPORT jint JNICALL ++Java_org_openeuler_security_openssl_KAESymmetricCipherBase_nativeUpdate(JNIEnv* env, jclass cls, jlong ctxAddress, ++ jbyteArray inArr, jint inOfs, jint inLen, jbyteArray outArr, jint outOfs, jboolean gcm, jbyteArray gcmAAD) ++{ ++ unsigned char* in = NULL; ++ unsigned char* aad = NULL; ++ unsigned char* out = NULL; ++ ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)ctxAddress; ++ if (ctx == NULL || inArr == NULL || outArr == NULL) { ++ goto cleanup; ++ } ++ ++ in = (unsigned char*)malloc(inLen); ++ int outLen = (*env)->GetArrayLength(env, outArr) - outOfs; ++ out = (unsigned char*)malloc(outLen); ++ if (in == NULL || out == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(in, 0, inLen); ++ memset(out, 0, outLen); ++ (*env)->GetByteArrayRegion(env, inArr, inOfs, inLen, (jbyte*)in); ++ ++ int bytesWritten = 0; ++ if (gcm && (gcmAAD != NULL)) { ++ int aadLen = (*env)->GetArrayLength(env, gcmAAD); ++ if ((aad = (unsigned char*)malloc(aadLen)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(aad, 0, aadLen); ++ (*env)->GetByteArrayRegion(env, gcmAAD, 0, aadLen, (jbyte*)aad); ++ ++ // Specify aad. ++ if (EVP_CipherUpdate(ctx, NULL, &bytesWritten, aad, aadLen) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherUpdate failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ } ++ ++ if (EVP_CipherUpdate(ctx, out, &bytesWritten, in, inLen) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherUpdate failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, outArr, outOfs, bytesWritten, (jbyte*)out); ++ ++ FreeMemoryFromUpdate(in, aad, out); ++ return bytesWritten; ++ ++cleanup: ++ FreeMemoryFromUpdate(in, aad, out); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAESymmetricCipherBase ++ * Method: nativeFinal ++ * Signature: (JZ[BI)I ++ */ ++JNIEXPORT jint JNICALL ++Java_org_openeuler_security_openssl_KAESymmetricCipherBase_nativeFinal(JNIEnv* env, jclass cls, ++ jlong ctxAddress, jbyteArray outArr, jint outOfs) ++{ ++ unsigned char* out = NULL; ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)ctxAddress; ++ KAE_TRACE("KAESymmetricCipherBase_nativeFinal(ctxAddress = %p, outArr = %p, outOfs = %d)", ++ ctx, outArr, outOfs); ++ if (ctx == NULL || outArr == NULL) { ++ goto cleanup; ++ } ++ int outLen = (*env)->GetArrayLength(env, outArr) - outOfs; ++ out = (unsigned char*)malloc(outLen); ++ if (out == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(out, 0, outLen); ++ 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 cleanup; ++ } ++ KAE_TRACE("KAESymmetricCipherBase_nativeFinal EVP_CipherFinal_ex success, bytesWritten = %d", bytesWritten); ++ (*env)->SetByteArrayRegion(env, outArr, outOfs, bytesWritten, (jbyte*)out); ++ free(out); ++ KAE_TRACE("KAESymmetricCipherBase_nativeFinal: finished"); ++ return bytesWritten; ++ ++cleanup: ++ if (out != NULL) { ++ free(out); ++ } ++ return 0; ++} ++ ++static void FreeMemoryFromFinalGcm(unsigned char* out, unsigned char* gcmTag, unsigned char* gcmOut) ++{ ++ if (out != NULL) { ++ free(out); ++ } ++ if (gcmTag != NULL) { ++ free(gcmTag); ++ } ++ if (gcmOut != NULL) { ++ free(gcmOut); ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAECipherAES ++ * Method: nativeFinalGcm ++ * Signature: (J[BIZI[BZ)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAESymmetricCipherBase_nativeFinalGcm(JNIEnv* env, ++ jclass cls, jlong ctxAddress, jbyteArray outArr, jint outOfs, jboolean gcm, jint tagLength, ++ jbyteArray gcmTagArr, jboolean encrypt) ++{ ++ unsigned char* out = NULL; ++ unsigned char* gcmTag = NULL; ++ unsigned char* gcmOut = NULL; ++ ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)ctxAddress; ++ if (ctx == NULL || outArr == NULL) { ++ goto cleanup; ++ } ++ ++ int bytesWritten = 0; ++ if (encrypt) { ++ int outLen = (*env)->GetArrayLength(env, outArr) - outOfs; ++ if ((out = malloc(outLen)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(out, 0, outLen); ++ if (EVP_CipherFinal_ex(ctx, out, &bytesWritten) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherFinal_ex failed", KAE_ThrowBadPaddingException); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, outArr, outOfs, bytesWritten, (jbyte*)out); ++ ++ // Writes tagLength bytes of the tag value to the buffer. ++ // Refer to {@link https://www.openssl.org/docs/man1.1.0/man3/EVP_CIPHER_CTX_ctrl.html} for details. ++ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tagLength, out + bytesWritten) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CIPHER_CTX_ctrl failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, outArr, outOfs + bytesWritten, tagLength, (jbyte*)(out + bytesWritten)); ++ bytesWritten += tagLength; ++ } else { ++ // gcmOut is the plaintext that has been decrypted in the EVP_CipherUpdate. ++ // outOfs is the length of the gcmOut, where it's always > 0. ++ if ((gcmTag = (unsigned char*)malloc(tagLength)) == NULL || (gcmOut = (unsigned char*)malloc(outOfs)) == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto cleanup; ++ } ++ memset(gcmTag, 0, tagLength); ++ memset(gcmOut, 0, outOfs); ++ ++ (*env)->GetByteArrayRegion(env, gcmTagArr, 0, tagLength, (jbyte*)gcmTag); ++ // Sets the expected gcmTag to tagLength bytes from gcmTag. ++ // Refer to {@link https://www.openssl.org/docs/man1.1.0/man3/EVP_CIPHER_CTX_ctrl.html} for details. ++ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tagLength, gcmTag) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CTRL_AEAD_SET_TAG failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ ++ (*env)->GetByteArrayRegion(env, outArr, 0, outOfs, (jbyte*)gcmOut); ++ // Finalise: note get no output for GCM ++ if (EVP_CipherFinal_ex(ctx, gcmOut, &bytesWritten) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherFinal_ex failed", KAE_ThrowAEADBadTagException); ++ goto cleanup; ++ } ++ } ++ FreeMemoryFromFinalGcm(out, gcmTag, gcmOut); ++ ++ return bytesWritten; ++ ++cleanup: ++ FreeMemoryFromFinalGcm(out, gcmTag, gcmOut); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAESymmetricCipherBase ++ * Method: nativeFree ++ * Signature: (J)V ++ */ ++JNIEXPORT void JNICALL ++Java_org_openeuler_security_openssl_KAESymmetricCipherBase_nativeFree(JNIEnv* env, jclass cls, jlong ctxAddress) ++{ ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*)ctxAddress; ++ KAE_TRACE("KAESymmetricCipherBase_nativeFree(ctx = %p)", ctx); ++ if (ctx != NULL) { ++ EVP_CIPHER_CTX_free(ctx); ++ ctx = NULL; ++ } ++ ++ KAE_TRACE("KAESymmetricCipherBase_nativeFree: finished"); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.c b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.c +new file mode 100644 +index 000000000..471ae834b +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.c +@@ -0,0 +1,246 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++#include "kae_util.h" ++#include "kae_exception.h" ++ ++static ENGINE* kaeEngine = NULL; ++ ++void SetKaeEngine(ENGINE* engine) { ++ kaeEngine = engine; ++} ++ ++ENGINE* GetKaeEngine() { ++ return kaeEngine; ++} ++ ++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 cleanup; ++ } ++ 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 cleanup; ++ } ++ return bn; ++ ++cleanup: ++ BN_free(bn); ++ return NULL; ++} ++ ++void KAE_ReleaseBigNumFromByteArray(BIGNUM* bn) { ++ if (bn != NULL) { ++ BN_free(bn); ++ } ++} ++ ++jbyteArray KAE_GetByteArrayFromBigNum(JNIEnv* env, const BIGNUM* bn) { ++ 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; ++} ++ ++#define ENGINE_LENGTH (EC_INDEX + 1) ++static ENGINE* engines[ENGINE_LENGTH] = {NULL}; ++static jboolean engineFlags[ENGINE_LENGTH] = {JNI_FALSE}; ++static KAEAlgorithm kaeAlgorithms[ENGINE_LENGTH] = { ++ {MD5_INDEX, "md5"}, ++ {SHA256_INDEX, "sha256"}, ++ {SHA384_INDEX, "sha384"}, ++ {SM3_INDEX, "sm3"}, ++ {AES_128_ECB_INDEX, "aes-128-ecb"}, ++ {AES_128_CBC_INDEX, "aes-128-cbc"}, ++ {AES_128_CTR_INDEX, "aes-128-ctr"}, ++ {AES_128_GCM_INDEX, "aes-128-gcm"}, ++ {AES_192_ECB_INDEX, "aes-192-ecb"}, ++ {AES_192_CBC_INDEX, "aes-192-cbc"}, ++ {AES_192_CTR_INDEX, "aes-192-ctr"}, ++ {AES_192_GCM_INDEX, "aes-192-gcm"}, ++ {AES_256_ECB_INDEX, "aes-256-ecb"}, ++ {AES_256_CBC_INDEX, "aes-256-cbc"}, ++ {AES_256_CTR_INDEX, "aes-256-ctr"}, ++ {AES_256_GCM_INDEX, "aes-256-gcm"}, ++ {SM4_ECB_INDEX, "sm4-ecb"}, ++ {SM4_CBC_INDEX, "sm4-cbc"}, ++ {SM4_CTR_INDEX, "sm4-ctr"}, ++ {SM4_OFB_INDEX, "sm4-ofb"}, ++ {HMAC_MD5_INDEX, "hmac-md5"}, ++ {HMAC_SHA1_INDEX, "hmac-sha1"}, ++ {HMAC_SHA224_INDEX, "hmac-sha224"}, ++ {HMAC_SHA256_INDEX, "hmac-sha256"}, ++ {HMAC_SHA384_INDEX, "hmac-sha384"}, ++ {HMAC_SHA512_INDEX, "hmac-sha512"}, ++ {RSA_INDEX, "rsa"}, ++ {DH_INDEX, "dh"}, ++ {EC_INDEX, "ec"} ++}; ++ ++void initEngines(JNIEnv* env, jbooleanArray algorithmKaeFlags) { ++ if (algorithmKaeFlags == NULL) { ++ return; ++ } ++ ++ // get jTemp ++ jboolean* jTemp = NULL; ++ int length = (*env)->GetArrayLength(env, algorithmKaeFlags); ++ jTemp = (jboolean*) malloc(length); ++ if (jTemp == NULL) { ++ KAE_ThrowOOMException(env, "initEngines GetArrayLength error"); ++ return; ++ } ++ (*env)->GetBooleanArrayRegion(env, algorithmKaeFlags, 0, length, jTemp); ++ ++ // assign engines ++ int minLen = length < ENGINE_LENGTH ? length : ENGINE_LENGTH; ++ int i; ++ for (i = 0; i < minLen; i++) { ++ if (jTemp[i]) { ++ engines[i] = kaeEngine; ++ engineFlags[i] = JNI_TRUE; ++ } ++ } ++ if (length < ENGINE_LENGTH) { ++ for (i = minLen; i < ENGINE_LENGTH; i++) { ++ engines[i] = kaeEngine; ++ engineFlags[i] = JNI_TRUE; ++ } ++ } ++ ++ // free jTemp ++ if (jTemp != NULL) { ++ free(jTemp); ++ } ++} ++ ++jbooleanArray getEngineFlags(JNIEnv* env) { ++ jbooleanArray array = (*env)->NewBooleanArray(env, ENGINE_LENGTH); ++ (*env)->SetBooleanArrayRegion(env, array, 0, ENGINE_LENGTH, engineFlags); ++ return array; ++} ++ ++ENGINE* GetEngineByAlgorithmIndex(AlgorithmIndex algorithmIndex) { ++ return engines[algorithmIndex]; ++} ++ ++/* ++ * Get the engine used by the specified algorithm. ++ * @param beginIndex the beginning index, inclusive. ++ * @param endIndex the ending index, exclusive. ++ * @param algorithmName algorithm name ++ * @return engine ++ */ ++ENGINE* GetEngineByBeginIndexAndEndIndex(int beginIndex, int endIndex, ++ const char* algorithmName) { ++ if (beginIndex < 0 || endIndex > ENGINE_LENGTH) { ++ return NULL; ++ } ++ ++ int i; ++ for (i = beginIndex; i < endIndex; i++) { ++ if (strcasecmp(kaeAlgorithms[i].algorithmName, algorithmName) == 0) { ++ return engines[kaeAlgorithms[i].algorithmIndex]; ++ } ++ } ++ return NULL; ++} ++ ++ENGINE* GetHmacEngineByAlgorithmName(const char* algorithmName) { ++ char prefix[] = {"hmac-"}; ++ int len = strlen(algorithmName); ++ int newLen = strlen(algorithmName) + strlen(prefix) + 1; ++ char* newAlgorithmName = NULL; ++ newAlgorithmName = malloc(newLen); ++ if (newAlgorithmName == NULL) { ++ return NULL; ++ } ++ strcpy(newAlgorithmName, prefix); ++ strcat(newAlgorithmName, algorithmName); ++ ENGINE* engine = GetEngineByBeginIndexAndEndIndex(HMAC_MD5_INDEX, HMAC_SHA512_INDEX + 1, newAlgorithmName); ++ if (newAlgorithmName != NULL) { ++ free(newAlgorithmName); ++ } ++ return engine; ++} ++ ++ENGINE* GetDigestEngineByAlgorithmName(const char* algorithmName) { ++ return GetEngineByBeginIndexAndEndIndex(MD5_INDEX, SM3_INDEX + 1, algorithmName); ++} ++ ++ENGINE* GetAesEngineByAlgorithmName(const char* algorithmName) { ++ return GetEngineByBeginIndexAndEndIndex(AES_128_ECB_INDEX, AES_256_GCM_INDEX + 1, algorithmName); ++} ++ ++ENGINE* GetSm4EngineByAlgorithmName(const char* algorithmName) { ++ return GetEngineByBeginIndexAndEndIndex(SM4_ECB_INDEX, SM4_OFB_INDEX + 1, algorithmName); ++} +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.h b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.h +new file mode 100644 +index 000000000..6eb980d62 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.h +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (c) 2023, 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 ++#include ++ ++typedef enum { ++ MD5_INDEX, ++ SHA256_INDEX, ++ SHA384_INDEX, ++ SM3_INDEX, ++ AES_128_ECB_INDEX, ++ AES_128_CBC_INDEX, ++ AES_128_CTR_INDEX, ++ AES_128_GCM_INDEX, ++ AES_192_ECB_INDEX, ++ AES_192_CBC_INDEX, ++ AES_192_CTR_INDEX, ++ AES_192_GCM_INDEX, ++ AES_256_ECB_INDEX, ++ AES_256_CBC_INDEX, ++ AES_256_CTR_INDEX, ++ AES_256_GCM_INDEX, ++ SM4_ECB_INDEX, ++ SM4_CBC_INDEX, ++ SM4_CTR_INDEX, ++ SM4_OFB_INDEX, ++ HMAC_MD5_INDEX, ++ HMAC_SHA1_INDEX, ++ HMAC_SHA224_INDEX, ++ HMAC_SHA256_INDEX, ++ HMAC_SHA384_INDEX, ++ HMAC_SHA512_INDEX, ++ RSA_INDEX, ++ DH_INDEX, ++ EC_INDEX ++} AlgorithmIndex; ++ ++typedef struct { ++ AlgorithmIndex algorithmIndex; ++ const char* algorithmName; ++} KAEAlgorithm; ++ ++/* 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); ++ ++void SetKaeEngine(ENGINE* engine); ++ ++ENGINE* GetKaeEngine(); ++ ++void initEngines(JNIEnv* env, jbooleanArray algorithmKaeFlags); ++ ++jbooleanArray getEngineFlags(JNIEnv* env); ++ ++ENGINE* GetEngineByAlgorithmIndex(AlgorithmIndex algorithmIndex); ++ ++ENGINE* GetHmacEngineByAlgorithmName(const char* algorithmName); ++ ++ENGINE* GetDigestEngineByAlgorithmName(const char* algorithmName); ++ ++ENGINE* GetAesEngineByAlgorithmName(const char* algorithmName); ++ ++ENGINE* GetSm4EngineByAlgorithmName(const char* algorithmName); ++ ++#endif +diff --git a/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/openssl_ad.h b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/openssl_ad.h +new file mode 100644 +index 000000000..f4b552137 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/openssl_ad.h +@@ -0,0 +1,10 @@ ++#include ++#include ++ ++#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 ++ ++// ERR_GET_FUNC() was removed since Openssl3 ++#ifndef ERR_GET_FUNC ++#define ERR_GET_FUNC(e) (int)(((e) >> 12L) & 0xFFFL) ++#endif ++#endif +diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups +index 21793455f..b24070a70 100644 +--- a/test/jdk/TEST.groups ++++ b/test/jdk/TEST.groups +@@ -247,6 +247,9 @@ jdk_security = \ + jdk_security_infra = \ + security/infra/java/security/cert/CertPathValidator/certification + ++jdk_kae_security = \ ++ org/openeuler/security/openssl ++ + jdk_text = \ + java/text \ + sun/text +diff --git a/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java b/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java +index 1e16c157f..9ed420d52 100644 +--- a/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java ++++ b/test/jdk/java/security/KeyAgreement/KeyAgreementTest.java +@@ -39,6 +39,7 @@ import java.security.KeyPairGenerator; + import java.security.spec.NamedParameterSpec; + import java.security.spec.AlgorithmParameterSpec; + import java.security.spec.ECGenParameterSpec; ++import java.security.Security; + import java.util.ArrayList; + import java.util.Arrays; + import java.util.List; +@@ -53,7 +54,13 @@ public class KeyAgreementTest { + String kpgAlgo = args[1]; + String provider = args[2]; + System.out.println("Testing " + kaAlgo); +- AlgoSpec aSpec = AlgoSpec.valueOf(AlgoSpec.class, kaAlgo); ++ AlgoSpec aSpec; ++ if (Security.getProperty("security.provider.1").equals("KAEProvider") && ++ kaAlgo.equals("ECDH")) { ++ aSpec = AlgoSpec.valueOf(AlgoSpec.class, "KAEECDH"); ++ } else { ++ aSpec = AlgoSpec.valueOf(AlgoSpec.class, kaAlgo); ++ } + List specs = aSpec.getAlgorithmParameterSpecs(); + for (AlgorithmParameterSpec spec : specs) { + testKeyAgreement(provider, kaAlgo, kpgAlgo, spec); +@@ -70,6 +77,7 @@ public class KeyAgreementTest { + // "java.base/share/classes/sun/security/util/CurveDB.java" + + ECDH("secp256r1", "secp384r1", "secp521r1"), ++ KAEECDH("secp224r1", "secp256r1", "secp384r1", "secp521r1"), + XDH("X25519", "X448", "x25519"), + // There is no curve for DiffieHellman + DiffieHellman(new String[]{}); +@@ -81,6 +89,7 @@ public class KeyAgreementTest { + for (String crv : curves) { + switch (this.name()) { + case "ECDH": ++ case "KAEECDH": + specs.add(new ECGenParameterSpec(crv)); + break; + case "XDH": +diff --git a/test/jdk/java/security/Signature/SignatureGetInstance.java b/test/jdk/java/security/Signature/SignatureGetInstance.java +index c246773f8..b69258cd9 100644 +--- a/test/jdk/java/security/Signature/SignatureGetInstance.java ++++ b/test/jdk/java/security/Signature/SignatureGetInstance.java +@@ -49,8 +49,11 @@ public class SignatureGetInstance { + MyPrivKey testPriv = new MyPrivKey(); + MyPubKey testPub = new MyPubKey(); + ++ Provider kaeProvider = Security.getProvider("KAEProvider"); ++ String expectedProvName = kaeProvider != null ? "KAEProvider" : "SunRsaSign"; ++ + testDblInit(testPriv, testPub, true, "TestProvider"); +- testDblInit(kp.getPrivate(), kp.getPublic(), true, "SunRsaSign"); ++ testDblInit(kp.getPrivate(), kp.getPublic(), true, expectedProvName); + testDblInit(testPriv, kp.getPublic(), false, null); + testDblInit(kp.getPrivate(), testPub, false, null); + +diff --git a/test/jdk/org/openeuler/security/openssl/AESTest.java b/test/jdk/org/openeuler/security/openssl/AESTest.java +new file mode 100644 +index 000000000..aac14568d +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/AESTest.java +@@ -0,0 +1,115 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.nio.charset.StandardCharsets; ++import java.security.Security; ++import java.security.spec.AlgorithmParameterSpec; ++import javax.crypto.Cipher; ++import javax.crypto.KeyGenerator; ++import javax.crypto.SecretKey; ++import javax.crypto.spec.IvParameterSpec; ++ ++/** ++ * @test ++ * @summary Basic test for AES ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main AESTest ++ */ ++ ++public class AESTest { ++ private static final String[] ALGORITHM = {"AES", "AES_128", "AES_192", "AES_256"}; ++ private static final String[] MODES = {"ECB", "CBC", "CTR", "GCM"}; ++ private static final String[] PADDING = {"NoPadding", "PKCS5Padding"}; ++ private static final int AES_128_KEY_LENGTH = 128; ++ private static final int AES_192_KEY_LENGTH = 192; ++ private static final int AES_256_KEY_LENGTH = 256; ++ private static String plainText = "helloworldhellow"; // 16bytes for NoPadding ++ private static String shortPlainText = "helloworld"; // 5 bytes for padding ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (String algo : ALGORITHM) { ++ for (String mode : MODES) { ++ int padKinds = 2; ++ if (mode.equalsIgnoreCase("CTR")) { ++ padKinds = 1; ++ } ++ for (int k = 0; k < padKinds; k++) { ++ test(algo, mode, PADDING[k]); ++ } ++ } ++ } ++ } ++ ++ public static void test(String algo, String mo, String pad) throws Exception { ++ AlgorithmParameterSpec aps = null; ++ ++ Cipher cipher = Cipher.getInstance(algo + "/" + mo + "/" + pad); ++ ++ KeyGenerator kg = KeyGenerator.getInstance("AES"); ++ if (algo.equalsIgnoreCase("AES_192")) { ++ kg.init(AES_192_KEY_LENGTH); ++ } else if (algo.equalsIgnoreCase("AES_256")) { ++ kg.init(AES_256_KEY_LENGTH); ++ } else { ++ kg.init(AES_128_KEY_LENGTH); ++ } ++ ++ SecretKey key = kg.generateKey(); ++ ++ // encrypt ++ if (!mo.equalsIgnoreCase("GCM")) { ++ cipher.init(Cipher.ENCRYPT_MODE, key, aps); ++ } else { ++ cipher.init(Cipher.ENCRYPT_MODE, key); ++ } ++ ++ String cipherString = null; ++ if (!pad.equalsIgnoreCase("NoPadding")) { ++ cipherString = shortPlainText; ++ } else { ++ cipherString = plainText; ++ } ++ byte[] cipherText = cipher.doFinal(cipherString.getBytes(StandardCharsets.UTF_8)); ++ if (!mo.equalsIgnoreCase("ECB")) { ++ aps = new IvParameterSpec(cipher.getIV()); ++ } else { ++ aps = null; ++ } ++ ++ if (!mo.equalsIgnoreCase("GCM")) { ++ cipher.init(Cipher.DECRYPT_MODE, key, aps); ++ } else { ++ cipher.init(Cipher.DECRYPT_MODE, key, cipher.getParameters()); ++ } ++ ++ String decryptPlainText = new String(cipher.doFinal(cipherText)); ++ ++ if (!cipherString.equals(decryptPlainText)) { ++ throw new RuntimeException("aes decryption failed, algo = " + algo + ", mo = " + mo + ", pad = " + pad); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/DHTest.java b/test/jdk/org/openeuler/security/openssl/DHTest.java +new file mode 100644 +index 000000000..51dab7664 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/DHTest.java +@@ -0,0 +1,122 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import java.io.Serializable; ++import java.math.BigInteger; ++import java.security.*; ++import java.util.Arrays; ++import javax.crypto.KeyAgreement; ++import javax.crypto.spec.*; ++import org.openeuler.security.openssl.KAEProvider; ++ ++/** ++ * This class implements the Diffie-Hellman key exchange algorithm. ++ * D-H means combining your private key with your partners public key to ++ * generate a number. The peer does the same with its private key and our ++ * public key. Through the magic of Diffie-Hellman we both come up with the ++ * same number. This number is secret (discounting MITM attacks) and hence ++ * called the shared secret. It has the same length as the modulus, e.g. 512 ++ * or 1024 bit. Man-in-the-middle attacks are typically countered by an ++ * independent authentication step using certificates (RSA, DSA, etc.). ++ * ++ * The thing to note is that the shared secret is constant for two partners ++ * with constant private keys. This is often not what we want, which is why ++ * it is generally a good idea to create a new private key for each session. ++ * Generating a private key involves one modular exponentiation assuming ++ * suitable D-H parameters are available. ++ * ++ * General usage of this class (TLS DHE case): ++ * . if we are server, call DHCrypt(keyLength,random). This generates ++ * an ephemeral keypair of the request length. ++ * . if we are client, call DHCrypt(modulus, base, random). This ++ * generates an ephemeral keypair using the parameters specified by ++ * the server. ++ * . send parameters and public value to remote peer ++ * . receive peers ephemeral public key ++ * . call getAgreedSecret() to calculate the shared secret ++ * ++ * In TLS the server chooses the parameter values itself, the client must use ++ * those sent to it by the server. ++ * ++ * The use of ephemeral keys as described above also achieves what is called ++ * "forward secrecy". This means that even if the authentication keys are ++ * broken at a later date, the shared secret remains secure. The session is ++ * compromised only if the authentication keys are already broken at the ++ * time the key exchange takes place and an active MITM attack is used. ++ * This is in contrast to straightforward encrypting RSA key exchanges. ++ * ++ */ ++ ++/** ++ * @test ++ * @summary Basic test for DH ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main DHTest ++ */ ++ ++public class DHTest implements Serializable { ++ private static BigInteger g512; ++ private static BigInteger p512; ++ ++ private static volatile Provider sunJceProvider; ++ private static volatile Provider kaeProvider; ++ ++ public static void main(String[] args) throws Exception { ++ Security.addProvider(new KAEProvider()); ++ sunJceProvider = Security.getProvider("SunJCE"); ++ kaeProvider = Security.getProvider("KAEProvider"); ++ ++ g512 = new BigInteger("30270326776012916323988175351831539351616124181011347910931933302640902603480679235129557617566480716138395926949700593986872757726720164601940036524221141391913433558162442022339559255078339658108149162251643458301671465579040759659507434340437396584664407572026953757806341363255195983514333141770938654900099033797866272818739547343977583089845850158637618703095710047154252655157633638171416516716598940884520592858762209135010804267830977334033327483815694794951984230264309784679409488441905236794443014066406150649287037909246107758452315504212879842042858577191624250834553614056794526338841821045329189780334"); ++ ++ p512 = new BigInteger("27672987386729926592037876826877634387173876890702920770064392919138769821035856568775311919542560094764667151024449425954917954337048895981297730855891532066350935045229294626339548842381843985759061682551900379979643117695834175891578650111093016914264824311693147701566019122696621248493126219217339690346346921463135605151471303957324058301097079967414639146647429422884520134312590056632178576758580657240245655739869017244657144448267757255018625514803292549109401806336918448001843022629625467069714240279603204909633404992842479161100500474744098408277938070656334892106100534117209709263785505019003765693651"); ++ ++ DHParameterSpec dhParams = new DHParameterSpec(p512, g512); ++ KeyPairGenerator SunJCEkeyGen = KeyPairGenerator.getInstance("DH", sunJceProvider); ++ KeyPairGenerator KAEkeyGen = KeyPairGenerator.getInstance("DH", kaeProvider); ++ SunJCEkeyGen.initialize(dhParams, new SecureRandom()); ++ KAEkeyGen.initialize(dhParams, new SecureRandom()); ++ KeyAgreement aKeyAgree = KeyAgreement.getInstance("DH", sunJceProvider); ++ KeyPair aPair = SunJCEkeyGen.generateKeyPair(); ++ KeyAgreement bKeyAgree = KeyAgreement.getInstance("DH", kaeProvider); ++ KeyPair bPair = KAEkeyGen.generateKeyPair(); ++ ++ aKeyAgree.init(aPair.getPrivate()); ++ bKeyAgree.init(bPair.getPrivate()); ++ ++ aKeyAgree.doPhase(bPair.getPublic(), true); ++ bKeyAgree.doPhase(aPair.getPublic(), true); ++ ++ MessageDigest hash = MessageDigest.getInstance("MD5"); ++ byte[] b1 = hash.digest(aKeyAgree.generateSecret()); ++ byte[] b2 = hash.digest(bKeyAgree.generateSecret()); ++ if(Arrays.equals(b1, b2)){ ++ System.out.println("SUCCESS!"); ++ }else{ ++ System.out.println("Failed!"); ++ throw new RuntimeException("Not Equal DH keyagreement ouput from SunJCE and KAE Provider!"); ++ } ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/org/openeuler/security/openssl/DigestTest.java b/test/jdk/org/openeuler/security/openssl/DigestTest.java +new file mode 100644 +index 000000000..120b6ac47 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/DigestTest.java +@@ -0,0 +1,61 @@ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.nio.charset.StandardCharsets; ++import java.security.MessageDigest; ++import java.security.Security; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.Map; ++ ++/** ++ * @test ++ * @summary Basic test for MD5 SHA256 SHA384 ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm DigestTest ++ */ ++public class DigestTest { ++ private static String PLAIN_TEXT = "hello world"; ++ ++ private static Map alg = new HashMap(); ++ ++ static { ++ alg.put("MD5", new byte[] {94, -74, 59, -69, -32, 30, -18, -48, -109, -53, 34, -69, -113, 90, -51, -61}); ++ alg.put( ++ "SHA-256", ++ new byte[] { ++ -71, 77, 39, -71, -109, 77, 62, 8, -91, 46, 82, -41, -38, 125, -85, -6, ++ -60, -124, -17, -29, 122, 83, -128, -18, -112, -120, -9, -84, -30, -17, -51, -23 ++ }); ++ alg.put( ++ "SHA-384", ++ new byte[] { ++ -3, -67, -114, 117, -90, 127, 41, -9, 1, -92, -32, 64, 56, 94, 46, 35, ++ -104, 99, 3, -22, 16, 35, -110, 17, -81, -112, 127, -53, -72, 53, 120, -77, ++ -28, 23, -53, 113, -50, 100, 110, -3, 8, 25, -35, -116, 8, -115, -31, -67 ++ }); ++ alg.put( ++ "SM3", ++ new byte[] { ++ 68, -16, 6, 30, 105, -6, 111, -33, -62, -112, -60, -108, 101, 74, 5, ++ -36, 12, 5, 61, -89, -27, -59, 43, -124, -17, -109, -87, -42, 125, 63, ++ -1, -120 ++ }); ++ } ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (String key : alg.keySet()) { ++ test(PLAIN_TEXT, key, alg.get(key)); ++ } ++ } ++ ++ public static void test(String plainText, String algo, byte[] expectRes) throws Exception { ++ MessageDigest md = MessageDigest.getInstance(algo); ++ md.update(plainText.getBytes(StandardCharsets.UTF_8)); ++ byte[] res = md.digest(); ++ if (!Arrays.equals(res, expectRes)) { ++ throw new RuntimeException(algo + " failed"); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/ECDHTest.java b/test/jdk/org/openeuler/security/openssl/ECDHTest.java +new file mode 100644 +index 000000000..791fec252 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/ECDHTest.java +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++import sun.security.ec.ECPrivateKeyImpl; ++import sun.security.ec.ECPublicKeyImpl; ++ ++import javax.crypto.KeyAgreement; ++import java.math.BigInteger; ++import java.security.KeyPair; ++import java.security.KeyPairGenerator; ++import java.security.Provider; ++import java.security.Security; ++import java.security.spec.ECFieldFp; ++import java.security.spec.ECParameterSpec; ++import java.security.spec.ECPoint; ++import java.security.spec.EllipticCurve; ++import java.util.Arrays; ++import java.nio.charset.StandardCharsets; ++import java.security.spec.*; ++import java.security.KeyFactory; ++import java.security.interfaces.ECPrivateKey; ++import java.security.interfaces.ECPublicKey; ++ ++/** ++ * @test ++ * @summary Basic test for ECDH ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @modules jdk.crypto.ec/sun.security.ec ++ * @requires os.arch=="aarch64" ++ * @run main ECDHTest ++ */ ++ ++public class ECDHTest { ++ ++ private static KeyPairGenerator keyPairGenerator; ++ private static String algorithm = "EC"; ++ private static int[] keyArr = {224, 256, 384, 521}; ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ ++ BigInteger a = new BigInteger("26959946667150639794667015087019630673557916260026308143510066298878"); ++ BigInteger b = new BigInteger("18958286285566608000408668544493926415504680968679321075787234672564"); ++ BigInteger p = new BigInteger("26959946667150639794667015087019630673557916260026308143510066298881"); ++ BigInteger x = new BigInteger("19277929113566293071110308034699488026831934219452440156649784352033"); ++ BigInteger y = new BigInteger("19926808758034470970197974370888749184205991990603949537637343198772"); ++ EllipticCurve CURVE = new EllipticCurve(new ECFieldFp(p), a, b); ++ ECPoint POINT = new ECPoint(x, y); ++ BigInteger ORDER = new BigInteger("26959946667150639794667015087019625940457807714424391721682722368061"); ++ int COFACTOR = 1; ++ ECParameterSpec PARAMS = new ECParameterSpec(CURVE, POINT, ORDER, COFACTOR); ++ ++ testKeyPairByParam(PARAMS); ++ for (int keySize : keyArr) { ++ testKeyPairByKeySize(keySize); ++ } ++ ++ KeyFactory keyFactory = KeyFactory.getInstance("EC"); ++ ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger("20135071615800221517902437867016717688420688735490569283842831828983"), PARAMS); ++ ECPrivateKeyImpl ecPrivKey = (ECPrivateKeyImpl)keyFactory.generatePrivate(privateKeySpec); ++ ++ ECPoint ecPoint = new ECPoint(new BigInteger("9490267631555585552004372465967099662885480699902812460349461311384"), new BigInteger("1974573604976093871117393045089050409882519645527397292712281520811")); ++ ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(ecPoint,PARAMS); ++ ECPublicKeyImpl ecPublicKey = (ECPublicKeyImpl)keyFactory.generatePublic(publicKeySpec); ++ testKeyAgreement(ecPrivKey, ecPublicKey, new byte[]{-88, -65, 43, -84, 26, 43, 46, 106, 20, 39, -76, 30, -71, 72, -102, 120, 108, -92, -86, -14, -96, -42, 93, -40, -43, -25, 15, -62}); ++ } ++ ++ public static void testKeyPairByParam(ECParameterSpec PARAMS) throws Exception { ++ keyPairGenerator = KeyPairGenerator.getInstance(algorithm); ++ keyPairGenerator.initialize(PARAMS); ++ KeyPair keyPair = keyPairGenerator.generateKeyPair(); ++ ECPrivateKeyImpl ecPrivKey = (ECPrivateKeyImpl) keyPair.getPrivate(); ++ ECPublicKeyImpl ecPublicKey = (ECPublicKeyImpl) keyPair.getPublic(); ++ } ++ ++ public static void testKeyPairByKeySize(int keySize) throws Exception { ++ keyPairGenerator = KeyPairGenerator.getInstance(algorithm); ++ keyPairGenerator.initialize(keySize); ++ KeyPair keyPair = keyPairGenerator.generateKeyPair(); ++ ECPrivateKeyImpl ecPrivKey = (ECPrivateKeyImpl) keyPair.getPrivate(); ++ ECPublicKeyImpl ecPublicKey = (ECPublicKeyImpl) keyPair.getPublic(); ++ } ++ ++ public static void testKeyAgreement(ECPrivateKeyImpl ecPrivKey, ECPublicKeyImpl ecPublicKey, byte[] expectRes) throws Exception { ++ KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH"); ++ keyAgreement.init(ecPrivKey); ++ keyAgreement.doPhase(ecPublicKey, true); ++ byte[] res = keyAgreement.generateSecret(); ++ if (!Arrays.equals(res, expectRes)) { ++ throw new RuntimeException("keyagreement failed"); ++ } ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/org/openeuler/security/openssl/HmacTest.java b/test/jdk/org/openeuler/security/openssl/HmacTest.java +new file mode 100644 +index 000000000..bddc37b4c +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/HmacTest.java +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import javax.crypto.Mac; ++import javax.crypto.spec.SecretKeySpec; ++import java.security.Key; ++import java.security.Security; ++import java.util.Arrays; ++ ++/** ++ * @test ++ * @summary test for Hmac ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm HmacTest ++ */ ++public class HmacTest { ++ private static final byte[] PLAIN_BYTES = "hello world".getBytes(); ++ private static final String[] ALGORITHMS = new String[]{ ++ "HmacMD5", ++ "HmacSHA1", ++ "HmacSHA224", ++ "HmacSHA256", ++ "HmacSHA384", ++ "HmacSHA512", ++ }; ++ private static final byte[][] EXPECTED_BYTES = { ++ {-40, 63, -96, 13, 107, -33, -1, -53, -116, 117, 75, -6, 85, -88, -112, -90}, ++ {-68, 104, 112, -36, 123, 123, -92, 104, 89, -90, 63, 56, 84, 45, 12, -7, 41, 103, -105, -27}, ++ {-31, 0, 103, 51, -119, -61, 2, -76, -83, -113, 95, 86, 8, 46, 91, 20, ++ -15, -23, -71, 62, -50, 86, -54, 71, -94, -47, -103, 43}, ++ {-69, -83, -3, 7, 61, 38, -122, -59, 7, -53, 106, 114, 58, 102, 65, -118, ++ 54, -50, 116, -56, 110, 54, -71, 36, 60, 84, 14, 97, 78, 18, -119, -24}, ++ {100, -58, 106, 64, -96, 91, 99, -33, 36, -78, -53, -50, -78, 116, -110, 85, ++ 84, -5, -63, 17, 51, -69, -39, -122, 65, 8, -122, -43, 39, 13, -41, -52, ++ 45, -38, -59, 70, 17, -87, -63, -126, 4, 120, -77, 71, 119, 96, -2, -68}, ++ {-89, 47, -98, -12, 110, -88, 23, 2, 28, 26, -71, 53, -108, 54, -52, 1, ++ -121, -121, 87, 6, -78, 123, -14, -86, 127, 114, 124, -73, -98, 79, -122, 69, ++ -32, 50, 48, -79, -110, 66, 38, 70, -3, -76, 95, 55, 74, 48, 57, -121, ++ 22, 60, -83, -109, 59, 79, 0, -49, 107, 88, -82, -35, 87, -36, 49, -54} ++ }; ++ private static final Key key = new SecretKeySpec("mac".getBytes(), ""); ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (int i = 0; i < ALGORITHMS.length; i++) { ++ test(ALGORITHMS[i], key, PLAIN_BYTES, EXPECTED_BYTES[i]); ++ } ++ } ++ ++ private static void test(String algorithm, Key key, byte[] inputBytes, byte[] expectedBytes) throws Exception { ++ Mac mac = Mac.getInstance(algorithm); ++ mac.init(key); ++ mac.update(inputBytes); ++ byte[] bytes = mac.doFinal(); ++ if (!(mac.getProvider() instanceof KAEProvider)) { ++ throw new RuntimeException(algorithm + " failed," + ++ "provider=" + mac.getProvider().getClass() + "," + ++ "expectedProvider=" + KAEProvider.class); ++ } ++ if (!Arrays.equals(bytes, expectedBytes)) { ++ throw new RuntimeException(algorithm + " failed," + ++ "bytes=" + Arrays.toString(bytes) + "," + ++ "expectedBytes=" + Arrays.toString(expectedBytes)); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAEConfTest.java b/test/jdk/org/openeuler/security/openssl/KAEConfTest.java +new file mode 100644 +index 000000000..4076aa2fc +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAEConfTest.java +@@ -0,0 +1,122 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEConfig; ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.File; ++import java.io.FileWriter; ++import java.io.IOException; ++import java.nio.file.Files; ++import java.util.ArrayList; ++import java.util.List; ++ ++/* ++ * @test ++ * @summary Test KAE Conf ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm KAEConfTest DEFAULT ++ * @run main/othervm KAEConfTest SPECIFY ++ */ ++public class KAEConfTest { ++ private static final String DEFAULT_CONF = System.getProperty("java.home") + ++ File.separator + "conf" + File.separator + "kaeprovider.conf"; ++ ++ private static final String SPECIFY_CONF = System.getProperty("user.dir") + ++ File.separator + "kaeprovider.conf"; ++ ++ private static final String SPECIFY_LOG_PATH = System.getProperty("user.dir") + File.separator + "kae.log"; ++ private static final List files = new ArrayList<>(); ++ ++ enum Mode { ++ DEFAULT, ++ SPECIFY ++ } ++ ++ public static void main(String[] args) throws IOException { ++ Mode mode = getMode(args); ++ try { ++ init(mode); ++ new KAEProvider(); ++ test(mode); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static Mode getMode(String[] args) { ++ if (args.length <= 0) { ++ return Mode.DEFAULT; ++ } ++ return Mode.valueOf(args[0]); ++ } ++ ++ private static void init(Mode mode) throws IOException { ++ if (Mode.SPECIFY.equals(mode)) { ++ System.setProperty("kae.conf", SPECIFY_CONF); ++ File file = new File(SPECIFY_CONF); ++ if (!file.exists()) { ++ Files.createFile(file.toPath()); ++ } ++ files.add(file); ++ try (FileWriter fileWriter = new FileWriter(file)) { ++ fileWriter.write("kae.log=true"); ++ fileWriter.flush(); ++ } ++ } ++ } ++ ++ private static void testDefault() { ++ File file = new File(DEFAULT_CONF); ++ if (!file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ } ++ ++ private static void testSpecify() { ++ String value = KAEConfig.privilegedGetOverridable("kae.log"); ++ if (!"true".equals(value)) { ++ throw new RuntimeException("test failed : kae.log=" + value); ++ } ++ File file = new File(SPECIFY_LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException(SPECIFY_LOG_PATH + "does not exist"); ++ } ++ // kae log file ++ files.add(file); ++ } ++ ++ private static void test(Mode mode) { ++ switch (mode) { ++ case DEFAULT: ++ testDefault(); ++ break; ++ case SPECIFY: ++ testSpecify(); ++ break; ++ default: ++ throw new IllegalArgumentException("invalid mode"); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java b/test/jdk/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java +new file mode 100644 +index 000000000..e8d767f0c +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAEDisabledAlgorithmsTest.java +@@ -0,0 +1,165 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEConfig; ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.util.HashSet; ++import java.util.Set; ++ ++/* ++ * @test ++ * @summary Test property kae.engine.disableAlgorithms ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm3 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-192-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=sm4-ofb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha1 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha224 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=hmac-sha512 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=rsa KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=dh KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=ec KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=aes-128-gcm,aes-192-gcm,aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.disabledAlgorithms=md5,aes-128-ecb,sm4-ecb,hmac-sha1,rsa,dh,ec KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm3 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-192-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-ecb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-cbc KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-ctr KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=sm4-ofb KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-md5 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha1 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha224 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha256 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha384 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=hmac-sha512 KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=rsa KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=dh KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=ec KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=aes-128-gcm,aes-192-gcm,aes-256-gcm KAEDisabledAlgorithmsTest ++ * @run main/othervm -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.engine.disabledAlgorithms=md5,aes-128-ecb,sm4-ecb,hmac-sha1,rsa,dh,ec KAEDisabledAlgorithmsTest ++ */ ++public class KAEDisabledAlgorithmsTest { ++ ++ public static void main(String[] args) { ++ KAETestHelper.Engine engine = KAETestHelper.getEngine(); ++ if (!engine.isValid()) { ++ System.out.println("Skip test, engine " + engine.getEngineId() + " does not exist."); ++ return; ++ } ++ String[] disabledAlgorithms = getDisabledAlgorithms(); ++ init(); ++ new KAEProvider(); ++ test(disabledAlgorithms); ++ } ++ ++ private static final String[] PROPERTY_NAMES = new String[]{ ++ "kae.digest.useKaeEngine", ++ "kae.aes.useKaeEngine", ++ "kae.sm4.useKaeEngine", ++ "kae.hmac.useKaeEngine", ++ "kae.rsa.useKaeEngine", ++ "kae.dh.useKaeEngine", ++ "kae.ec.useKaeEngine" ++ }; ++ ++ private static String[] getDisabledAlgorithms() { ++ String value = System.getProperty("kae.engine.disabledAlgorithms"); ++ if (value == null) { ++ return new String[0]; ++ } ++ return value.split(","); ++ } ++ ++ private static void init() { ++ for (String propertyName : PROPERTY_NAMES) { ++ System.setProperty(propertyName, "true"); ++ } ++ } ++ ++ private static void test(String[] disabledAlgorithms) { ++ boolean[] useKaeEngineFlags = KAEConfig.getUseKaeEngineFlags(); ++ Set disabledAlgorithmIndexSet = new HashSet<>(); ++ ++ // test disabled algorithms ++ for (String disabledAlgorithm : disabledAlgorithms) { ++ Integer index = KAETestHelper.getAlgorithmIndex(disabledAlgorithm); ++ if (index == null || index < 0 || index >= useKaeEngineFlags.length) { ++ continue; ++ } ++ if (useKaeEngineFlags[index]) { ++ throw new RuntimeException("test failed"); ++ } ++ disabledAlgorithmIndexSet.add(index); ++ } ++ ++ // test other algorithms that are not disabled (except ec) ++ for (int i = 0; i < useKaeEngineFlags.length - 1; i++) { ++ if (!disabledAlgorithmIndexSet.contains(i) && !useKaeEngineFlags[i]) { ++ throw new RuntimeException(KAETestHelper.getAlgorithmName(i) + " algorithm is not disabled"); ++ } ++ } ++ ++ // test whether the ec algorithm is disabled by default ++ if (useKaeEngineFlags[useKaeEngineFlags.length - 1]) { ++ throw new RuntimeException(KAETestHelper.getAlgorithmName(useKaeEngineFlags.length - 1) ++ + " algorithm is disabled by default"); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAEEngineIdTest.java b/test/jdk/org/openeuler/security/openssl/KAEEngineIdTest.java +new file mode 100644 +index 000000000..75248a432 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAEEngineIdTest.java +@@ -0,0 +1,77 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.BufferedReader; ++import java.io.File; ++import java.io.FileReader; ++import java.io.IOException; ++import java.util.ArrayList; ++import java.util.List; ++ ++/* ++ * @test ++ * @summary Test KAE property kae.engine.id and kae.libcrypto.useGlobalMode ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Dkae.log=true KAEEngineIdTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=kae KAEEngineIdTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true KAEEngineIdTest ++ */ ++public class KAEEngineIdTest { ++ ++ private static final String LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "kae.log"; ++ ++ private static final List files = new ArrayList<>(); ++ ++ public static void main(String[] args) throws IOException { ++ KAETestHelper.Engine engine = KAETestHelper.getEngine(); ++ if (!engine.isValid()) { ++ System.out.println("Skip test, engine " + engine.getEngineId() + " does not exist."); ++ return; ++ } ++ ++ try { ++ new KAEProvider(); ++ test(engine); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static void test(KAETestHelper.Engine engine) throws IOException { ++ File file = new File(LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException(LOG_PATH + " does not exist"); ++ } ++ files.add(file); ++ try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) { ++ String s = bufferedReader.readLine(); ++ if (!s.contains(engine.getEngineId() + " engine was found")) { ++ throw new RuntimeException("test failed"); ++ } ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAELogTest.java b/test/jdk/org/openeuler/security/openssl/KAELogTest.java +new file mode 100644 +index 000000000..f635d96f3 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAELogTest.java +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.File; ++import java.util.ArrayList; ++import java.util.List; ++ ++/* ++ * @test ++ * @summary Test KAE log ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm KAELogTest ++ * @run main/othervm -Dkae.log=false KAELogTest ++ * @run main/othervm -Dkae.log=true KAELogTest ++ * @run main/othervm -Dkae.log=true -Dkae.log.file=./KAELogTest/kae.log KAELogTest ++ */ ++public class KAELogTest { ++ private static final String DEFAULT_LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "kae.log"; ++ ++ private static final String SPECIFY_LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "KAELogTest" + File.separator + "kae.log"; ++ ++ private static final List files = new ArrayList<>(); ++ ++ enum Mode { ++ DEFAULT, ++ DISABLE, ++ ENABLE, ++ SPECIFY ++ } ++ ++ public static void main(String[] args) { ++ Mode mode = getMode(); ++ try { ++ new KAEProvider(); ++ test(mode); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static Mode getMode() { ++ String enableKaeLog = System.getProperty("kae.log"); ++ if (enableKaeLog == null) { ++ return Mode.DEFAULT; ++ } else if ("false".equals(enableKaeLog)) { ++ return Mode.DISABLE; ++ } else { ++ String logPath = System.getProperty("kae.log.file"); ++ if (logPath == null) { ++ return Mode.ENABLE; ++ } ++ return Mode.SPECIFY; ++ } ++ } ++ ++ private static void testDefault() { ++ testDisable(); ++ } ++ ++ private static void testDisable() { ++ File file = new File(DEFAULT_LOG_PATH); ++ if (file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ } ++ ++ private static void testEnable() { ++ File file = new File(DEFAULT_LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ files.add(file); ++ } ++ ++ private static void testSpecify() { ++ File file = new File(KAELogTest.SPECIFY_LOG_PATH); ++ if (!file.exists()) { ++ throw new RuntimeException("test failed"); ++ } ++ files.add(file); ++ files.add(file.getParentFile()); ++ } ++ ++ private static void test(Mode mode) { ++ switch (mode) { ++ case DEFAULT: ++ testDefault(); ++ break; ++ case DISABLE: ++ testDisable(); ++ break; ++ case ENABLE: ++ testEnable(); ++ break; ++ case SPECIFY: ++ testSpecify(); ++ break; ++ default: ++ throw new IllegalArgumentException("invalid mode"); ++ } ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAETestHelper.java b/test/jdk/org/openeuler/security/openssl/KAETestHelper.java +new file mode 100644 +index 000000000..59ad91ddc +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAETestHelper.java +@@ -0,0 +1,209 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import java.io.BufferedReader; ++import java.io.File; ++import java.io.FileReader; ++import java.io.IOException; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++ ++class KAETestHelper { ++ private static final String KAE_ENGINE_ID = "kae"; ++ private static final String UADK_ENGINE_ID = "uadk_engine"; ++ private static boolean hasKaeEngine; ++ private static boolean hasUadkEngine; ++ ++ private static String engineRootPath; ++ ++ // algorithm names ++ private static final String[] ALGORITHM_NAMES = new String[]{ ++ "md5", ++ "sha256", ++ "sha384", ++ "sm3", ++ "aes-128-ecb", ++ "aes-128-cbc", ++ "aes-128-ctr", ++ "aes-128-gcm", ++ "aes-192-ecb", ++ "aes-192-cbc", ++ "aes-192-ctr", ++ "aes-192-gcm", ++ "aes-256-ecb", ++ "aes-256-cbc", ++ "aes-256-ctr", ++ "aes-256-gcm", ++ "sm4-ecb", ++ "sm4-cbc", ++ "sm4-ctr", ++ "sm4-ofb", ++ "hmac-md5", ++ "hmac-sha1", ++ "hmac-sha224", ++ "hmac-sha256", ++ "hmac-sha384", ++ "hmac-sha512", ++ "rsa", ++ "dh", ++ "ec" ++ }; ++ private static final Map ALGORITHM_NAME_MAP = new HashMap<>(); ++ ++ private static final String PROVIDER_NAME = "KAEProvider"; ++ private static final String USE_OPENSSL_MSG = "Use openssl soft calculation"; ++ private static final String USE_KAE_HARDWARE_MSG = "enable KAE hardware acceleration"; ++ private static final Map ALGORITHM_MSG_MAP = new HashMap<>(); ++ ++ static { ++ init(); ++ } ++ ++ enum Engine { ++ default_engine(hasKaeEngine, KAE_ENGINE_ID), ++ kae(hasKaeEngine, KAE_ENGINE_ID), ++ uadk_engine(hasUadkEngine, UADK_ENGINE_ID); ++ private final boolean isValid; ++ private final String engineId; ++ ++ Engine(boolean isValid, String engineId) { ++ this.isValid = isValid; ++ this.engineId = engineId; ++ } ++ ++ public boolean isValid() { ++ return isValid; ++ } ++ ++ public String getEngineId() { ++ return engineId; ++ } ++ } ++ ++ private static void init() { ++ engineRootPath = System.getenv("OPENSSL_ENGINES"); ++ if (engineRootPath == null || engineRootPath.equals("")) { ++ System.out.println("Environment variable OPENSSL_ENGINES is not configured"); ++ } ++ hasKaeEngine = hasEngine(KAE_ENGINE_ID); ++ hasUadkEngine = hasEngine(UADK_ENGINE_ID); ++ ++ for (int i = 0; i < ALGORITHM_NAMES.length; i++) { ++ ALGORITHM_NAME_MAP.put(ALGORITHM_NAMES[i], i); ++ } ++ ++ ALGORITHM_MSG_MAP.put(USE_OPENSSL_MSG, false); ++ ALGORITHM_MSG_MAP.put(USE_KAE_HARDWARE_MSG, true); ++ } ++ ++ static Integer getAlgorithmIndex(String algorithmName) { ++ return ALGORITHM_NAME_MAP.get(algorithmName); ++ } ++ ++ static String getAlgorithmName(Integer algorithmIndex) { ++ return ALGORITHM_NAMES[algorithmIndex]; ++ } ++ ++ private static boolean hasEngine(String engineId) { ++ String filePath = engineRootPath + File.separator + engineId + ".so"; ++ File file = new File(filePath); ++ return file.exists(); ++ } ++ ++ static boolean hasKaeEngine() { ++ return hasKaeEngine; ++ } ++ ++ static boolean hasUadkEngine() { ++ return hasUadkEngine; ++ } ++ ++ static void cleanUp(List files) { ++ for (File file : files) { ++ System.out.println("delete file : " + file); ++ file.delete(); ++ } ++ } ++ ++ static boolean[] parseLog(Engine engine, File file) throws IOException { ++ boolean[] kaeUseEngineFlags; ++ String expectedEngineMsg = engine.getEngineId() + " engine was found"; ++ try (BufferedReader reader = new BufferedReader(new FileReader(file))) { ++ // load engine message ++ String engineMsg = reader.readLine(); ++ if (engineMsg == null || !engineMsg.contains(expectedEngineMsg)) { ++ throw new RuntimeException("test failed : actual message :" + engineMsg); ++ } ++ ++ // summary message ++ String summaryMessage = reader.readLine(); ++ if (summaryMessage == null) { ++ throw new RuntimeException("test failed : summary message is null"); ++ } ++ ++ kaeUseEngineFlags = new boolean[ALGORITHM_NAMES.length]; ++ // strategy of each algorithm ++ String strategy; ++ while ((strategy = reader.readLine()) != null) { ++ String[] splitArray = strategy.split("=>"); ++ if (splitArray.length < 2) { ++ throw new RuntimeException("test failed : strategy = " + strategy); ++ } ++ ++ // algorithm Index ++ String algorithm = splitArray[0].replace(" ", ""); ++ Integer algorithmIndex = ALGORITHM_NAME_MAP.get(algorithm); ++ if (algorithmIndex == null) { ++ throw new RuntimeException("test failed : illegal algorithm " + algorithm); ++ } ++ ++ // provider and algorithm value ++ String detail = splitArray[1]; ++ String[] detailArray = detail.split(":"); ++ if (detailArray.length < 2) { ++ throw new RuntimeException("test failed : detail=" + strategy); ++ } ++ String provider = detailArray[0].replace(" ", ""); ++ if (!PROVIDER_NAME.equals(provider)) { ++ throw new RuntimeException("test failed : provider= " + provider); ++ } ++ String algorithmMsg = detailArray[1].trim(); ++ Boolean algorithmValue = ALGORITHM_MSG_MAP.get(algorithmMsg); ++ if (algorithmValue == null) { ++ throw new RuntimeException("test failed : algorithmMsg= " + algorithmMsg); ++ } ++ kaeUseEngineFlags[algorithmIndex] = algorithmValue; ++ } ++ } ++ return kaeUseEngineFlags; ++ } ++ ++ static KAETestHelper.Engine getEngine() { ++ String engineId = System.getProperty("kae.engine.id"); ++ if (engineId == null) { ++ return KAETestHelper.Engine.default_engine; ++ } ++ return KAETestHelper.Engine.valueOf(engineId); ++ } ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KAEUseEngineTest.java b/test/jdk/org/openeuler/security/openssl/KAEUseEngineTest.java +new file mode 100644 +index 000000000..a5b9b5386 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KAEUseEngineTest.java +@@ -0,0 +1,263 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.io.File; ++import java.io.IOException; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++ ++/* ++ * @test ++ * @summary Test KAE property kae..useKaeEngine ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Dkae.log=true -Dall.test=default KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.digest.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=enable -Dkae.digest.useKaeEngine=true -Dkae.aes.useKaeEngine=true -Dkae.sm4.useKaeEngine=true -Dkae.hmac.useKaeEngine=true -Dkae.rsa.useKaeEngine=true -Dkae.dh.useKaeEngine=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.digest.useKaeEngine=false KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=disable -Dkae.digest.useKaeEngine=false -Dkae.aes.useKaeEngine=false -Dkae.sm4.useKaeEngine=false -Dkae.hmac.useKaeEngine=false -Dkae.rsa.useKaeEngine=false -Dkae.dh.useKaeEngine=false -Dkae.ec.useKaeEngine=false KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=default -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=enable -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=true -Dkae.aes.useKaeEngine=true -Dkae.sm4.useKaeEngine=true -Dkae.hmac.useKaeEngine=true -Dkae.rsa.useKaeEngine=true -Dkae.dh.useKaeEngine=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=false KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.aes.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.sm4.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.hmac.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.rsa.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.dh.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.ec.useKaeEngine=true KAEUseEngineTest ++ * @run main/othervm -Dkae.log=true -Dall.test=disable -Dkae.engine.id=uadk_engine -Dkae.libcrypto.useGlobalMode=true -Dkae.digest.useKaeEngine=false -Dkae.aes.useKaeEngine=false -Dkae.sm4.useKaeEngine=false -Dkae.hmac.useKaeEngine=false -Dkae.rsa.useKaeEngine=false -Dkae.dh.useKaeEngine=false -Dkae.ec.useKaeEngine=false KAEUseEngineTest ++ */ ++public class KAEUseEngineTest { ++ enum Mode { ++ DEFAULT(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }), ++ DIGEST_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 0, true), ++ AES_ENABLE(new boolean[]{ ++ true, false, false, true, true, true, true, true, true, true, ++ true, true, true, true, true, true, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 1, true), ++ SM4_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 2, true), ++ HMAC_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ true, true, true, true, true, true, true, true, false ++ }, 3, true), ++ RSA_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 4, true), ++ DH_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 5, true), ++ EC_ENABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 6, true), ++ ALL_ENABLE(new boolean[]{ ++ true, false, false, true, true, true, true, true, true, true, ++ true, true, true, true, true, true, true, true, true, true, ++ true, true, true, true, true, true, true, true, false ++ }, true), ++ DIGEST_DISABLE(new boolean[]{ ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 0, false), ++ AES_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 1, false), ++ SM4_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, false ++ }, 2, false), ++ HMAC_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 3, false), ++ RSA_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, false, true, false ++ }, 4, false), ++ DH_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, false, false ++ }, 5, false), ++ EC_DISABLE(new boolean[]{ ++ true, false, false, true, false, false, false, false, false, false, ++ false, false, false, false, false, false, true, true, true, true, ++ false, false, false, false, false, false, true, true, false ++ }, 6, false), ++ ALL_DISABLE(new boolean[]{ ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, false, false, false, false, ++ false, false, false, false, false, false, false, false, false ++ }, false); ++ private final boolean[] expectedResult; ++ private final Integer propertyNameIndex; ++ private final boolean enable; ++ private static final Map modeMap = new HashMap<>(); ++ ++ static { ++ Mode[] modes = Mode.values(); ++ for (Mode mode : modes) { ++ if (mode.propertyNameIndex != null) { ++ modeMap.put(PROPERTY_NAMES[mode.propertyNameIndex] + ":" + mode.enable, mode); ++ } ++ } ++ modeMap.put("default", DEFAULT); ++ modeMap.put("disable", ALL_DISABLE); ++ modeMap.put("enable", ALL_ENABLE); ++ } ++ ++ Mode(boolean[] expectedResult) { ++ this(expectedResult, false); ++ } ++ ++ Mode(boolean[] expectedResult, boolean enable) { ++ this(expectedResult, null, enable); ++ } ++ ++ Mode(boolean[] expectedResult, Integer propertyNameIndex, boolean enable) { ++ this.expectedResult = expectedResult; ++ this.propertyNameIndex = propertyNameIndex; ++ this.enable = enable; ++ } ++ ++ static Mode getMode(String name, Boolean enable) { ++ return modeMap.get(name + ":" + enable); ++ } ++ ++ static Mode getMode(String key) { ++ return modeMap.get(key); ++ } ++ } ++ ++ private static final String KAE_LOG_PATH = System.getProperty("user.dir") + ++ File.separator + "kae.log"; ++ ++ private static final String[] PROPERTY_NAMES = new String[]{ ++ "kae.digest.useKaeEngine", ++ "kae.aes.useKaeEngine", ++ "kae.sm4.useKaeEngine", ++ "kae.hmac.useKaeEngine", ++ "kae.rsa.useKaeEngine", ++ "kae.dh.useKaeEngine", ++ "kae.ec.useKaeEngine" ++ }; ++ ++ private static final List files = new ArrayList<>(); ++ ++ public static void main(String[] args) throws IOException { ++ KAETestHelper.Engine engine = KAETestHelper.getEngine(); ++ if (!engine.isValid()) { ++ System.out.println("Skip test, engine " + engine.getEngineId() + " does not exist."); ++ return; ++ } ++ Mode mode = getMode(); ++ if (mode == null) { ++ throw new RuntimeException("test failed: mode is null"); ++ } ++ ++ try { ++ new KAEProvider(); ++ test(mode, engine); ++ } finally { ++ KAETestHelper.cleanUp(files); ++ } ++ } ++ ++ private static Mode getMode() { ++ String value = System.getProperty("all.test"); ++ if (value != null) { ++ return Mode.getMode(value); ++ } ++ for (String propertyName : PROPERTY_NAMES) { ++ String property = System.getProperty(propertyName); ++ Boolean enable = null; ++ if (property != null) { ++ enable = Boolean.valueOf(property); ++ } ++ Mode mode = Mode.getMode(propertyName, enable); ++ if (mode != null) { ++ return mode; ++ } ++ } ++ return null; ++ } ++ ++ private static void test(Mode mode, KAETestHelper.Engine engine) throws IOException { ++ File file = new File(KAE_LOG_PATH); ++ files.add(file); ++ boolean[] kaeUseEngineFlags = KAETestHelper.parseLog(engine, file); ++ if (!Arrays.equals(mode.expectedResult, kaeUseEngineFlags)) { ++ throw new RuntimeException("test failed : expected : " + Arrays.toString(mode.expectedResult) + "," + ++ "actual:" + Arrays.toString(kaeUseEngineFlags)); ++ } ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/org/openeuler/security/openssl/KaeDebugLogTest.java b/test/jdk/org/openeuler/security/openssl/KaeDebugLogTest.java +new file mode 100644 +index 000000000..7bffbd6ec +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KaeDebugLogTest.java +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import javax.crypto.Cipher; ++import javax.crypto.spec.SecretKeySpec; ++import java.io.PrintStream; ++import java.nio.charset.StandardCharsets; ++import java.nio.file.Files; ++import java.nio.file.Paths; ++import java.security.Security; ++import java.util.Objects; ++import java.util.stream.Collectors; ++import java.util.stream.Stream; ++ ++/** ++ * @test ++ * @summary test for KaeDebugLogTest ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main/othervm -Djava.security.debug=kae -Dkae.sm4.maxChunkSize=65536 KaeDebugLogTest ++ * @run main/othervm -Djava.security.debug=kae KaeDebugLogTest ++ * @run main/othervm -Djava.security.auth.debug=kae KaeDebugLogTest ++ * @run main/othervm KaeDebugLogTest ++ */ ++ ++public class KaeDebugLogTest { ++ ++ private static final PrintStream err = System.err; ++ ++ public static void main(String[] args) throws Exception { ++ PrintStream printStream = new PrintStream("kaetest.out"); ++ System.setErr(printStream); ++ testDebugLog(); ++ System.setErr(printStream); ++ testSm4ChunkSize(); ++ } ++ ++ public static void testDebugLog() throws Exception { ++ new KAEProvider(); ++ Stream lines = Files.lines(Paths.get("kaetest.out")); ++ System.setErr(err); ++ String content = lines.collect(Collectors.joining(System.lineSeparator())); ++ if(("kae".equals(System.getProperty("java.security.debug")) ++ || "kae".equals(System.getProperty("java.security..auth.debug"))) ++ && !content.contains("reading kae properties file:")){ ++ throw new RuntimeException("KaeDebugLogTest Failed! Failed to set the debug log."); ++ } ++ lines.close(); ++ } ++ ++ public static void testSm4ChunkSize() throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ Cipher cipher = Cipher.getInstance("SM4"); ++ cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("sm4EncryptionKey".getBytes(StandardCharsets.UTF_8), "SM4")); ++ Stream lines = Files.lines(Paths.get("kaetest.out")); ++ System.setErr(err); ++ String content = lines.collect(Collectors.joining(System.lineSeparator())); ++ String log = "The configured chunk size is " + System.getProperty("kae.sm4.maxChunkSize"); ++ if(("kae".equals(System.getProperty("java.security.debug")) ++ || "kae".equals(System.getProperty("java.security..auth.debug"))) ++ && Objects.nonNull(System.getProperty("kae.sm4.maxChunkSize")) &&!content.contains(log)){ ++ throw new RuntimeException("KaeDebugLogTest Failed! Failed to set the kae.sm4.maxChunkSize = " + System.getProperty("kae.sm4.maxChunkSize")); ++ } ++ lines.close(); ++ } ++ ++} +diff --git a/test/jdk/org/openeuler/security/openssl/KaeProviderTest.java b/test/jdk/org/openeuler/security/openssl/KaeProviderTest.java +new file mode 100644 +index 000000000..0f4425b6d +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/KaeProviderTest.java +@@ -0,0 +1,171 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import javax.crypto.Cipher; ++import javax.crypto.Mac; ++import javax.crypto.NoSuchPaddingException; ++import java.security.KeyPairGenerator; ++import java.security.MessageDigest; ++import java.security.NoSuchAlgorithmException; ++import java.security.Security; ++ ++/** ++ * @test ++ * @requires os.arch=="aarch64" ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @summary test for KaeProviderTest ++ * @run main/othervm KaeProviderTest ++ * @run main/othervm KaeProviderTest true ++ * @run main/othervm KaeProviderTest false ++ * @run main/othervm KaeProviderTest wrong ++ */ ++ ++public class KaeProviderTest { ++ ++ private static final String[] algorithmKaeProviderPropertyNames = new String[]{ ++ "kae.md5", ++ "kae.sha256", ++ "kae.sha384", ++ "kae.sm3", ++ "kae.aes", ++ "kae.sm4", ++ "kae.hmac", ++ "kae.rsa", ++ "kae.dh", ++ "kae.ec" ++ }; ++ ++ private static final String KAE = "KAEProvider"; ++ ++ public static void main(String[] args) throws Exception { ++ initProperty(args); ++ Security.insertProviderAt(new KAEProvider(), 1); ++ testALL(); ++ } ++ ++ private static void initProperty(String[] args) { ++ if (args.length <= 0) { ++ return; ++ } ++ String value = args[0]; ++ for (String name : algorithmKaeProviderPropertyNames){ ++ System.setProperty(name,value); ++ } ++ } ++ ++ public static void testALL() throws Exception { ++ testMd5(); ++ testSha256(); ++ testSha384(); ++ testSm3(); ++ testAes(); ++ testSm4(); ++ testHmac(); ++ testRsa(); ++ testDh(); ++ testEc(); ++ } ++ ++ public static void testMd5() throws NoSuchAlgorithmException { ++ MessageDigest messageDigest = MessageDigest.getInstance("MD5"); ++ judge("kae.md5",messageDigest.getProvider().getName()); ++ ++ } ++ ++ public static void testSha256() throws NoSuchAlgorithmException { ++ MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); ++ judge("kae.sha256",messageDigest.getProvider().getName()); ++ } ++ ++ public static void testSha384() throws NoSuchAlgorithmException { ++ MessageDigest messageDigest = MessageDigest.getInstance("SHA-384"); ++ judge("kae.sha384",messageDigest.getProvider().getName()); ++ } ++ ++ public static void testSm3() throws NoSuchAlgorithmException { ++ try{ ++ MessageDigest messageDigest = MessageDigest.getInstance("SM3"); ++ judge("kae.sm3",messageDigest.getProvider().getName()); ++ }catch (NoSuchAlgorithmException e){ ++ if(Boolean.parseBoolean(System.getProperty("kae.sm3"))){ ++ throw e; ++ } ++ } ++ } ++ ++ public static void testAes() throws NoSuchAlgorithmException, NoSuchPaddingException { ++ Cipher cipher = Cipher.getInstance("AES"); ++ judge("kae.aes",cipher.getProvider().getName()); ++ } ++ ++ public static void testSm4() throws NoSuchAlgorithmException, NoSuchPaddingException { ++ try{ ++ Cipher cipher = Cipher.getInstance("SM4"); ++ judge("kae.sm4",cipher.getProvider().getName()); ++ }catch (NoSuchAlgorithmException e){ ++ if(Boolean.parseBoolean(System.getProperty("kae.sm4"))){ ++ throw e; ++ } ++ } ++ } ++ ++ public static void testHmac() throws NoSuchAlgorithmException { ++ Mac mac = Mac.getInstance("HmacMD5"); ++ judge("kae.hmac",mac.getProvider().getName()); ++ } ++ ++ public static void testRsa() throws NoSuchAlgorithmException, NoSuchPaddingException { ++ Cipher cipher = Cipher.getInstance("RSA"); ++ judge("kae.rsa",cipher.getProvider().getName()); ++ } ++ ++ public static void testDh() throws NoSuchAlgorithmException { ++ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH"); ++ judge("kae.dh",keyPairGenerator.getProvider().getName()); ++ } ++ ++ public static void testEc() throws NoSuchAlgorithmException { ++ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); ++ judge("kae.ec",keyPairGenerator.getProvider().getName()); ++ } ++ ++ private static void judge(String algorithm , String providerName){ ++ String value = System.getProperty(algorithm); ++ if (value == null) { ++ if (!KAE.equals(providerName)) { ++ throw new RuntimeException("KaeProviderTest Failed! default Provider.name is not right!"); ++ } ++ } else { ++ if (Boolean.parseBoolean(value) && !KAE.equals(providerName)) { ++ throw new RuntimeException("KaeProviderTest Failed! " + algorithm + " is " + value + "," + ++ " Provider.name is not right!"); ++ } ++ if (!Boolean.parseBoolean(value) && KAE.equals(providerName)) { ++ throw new RuntimeException("KaeProviderTest Failed! " + algorithm + " is " + value + ", " + ++ " Provider.name is not right!"); ++ } ++ } ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/org/openeuler/security/openssl/RSATest.java b/test/jdk/org/openeuler/security/openssl/RSATest.java +new file mode 100644 +index 000000000..8a787e1f7 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/RSATest.java +@@ -0,0 +1,115 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++ ++import java.nio.charset.StandardCharsets; ++import java.security.Security; ++import java.security.spec.AlgorithmParameterSpec; ++import javax.crypto.Cipher; ++import javax.crypto.KeyGenerator; ++import javax.crypto.SecretKey; ++import javax.crypto.spec.IvParameterSpec; ++ ++/** ++ * @test ++ * @summary Basic test for AES ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @requires os.arch=="aarch64" ++ * @run main AESTest ++ */ ++ ++public class AESTest { ++ private static final String[] ALGORITHM = {"AES", "AES_128", "AES_192", "AES_256"}; ++ private static final String[] MODES = {"ECB", "CBC", "CTR", "GCM"}; ++ private static final String[] PADDING = {"NoPadding", "PKCS5Padding"}; ++ private static final int AES_128_KEY_LENGTH = 128; ++ private static final int AES_192_KEY_LENGTH = 192; ++ private static final int AES_256_KEY_LENGTH = 256; ++ private static String plainText = "helloworldhellow"; // 16bytes for NoPadding ++ private static String shortPlainText = "helloworld"; // 5 bytes for padding ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ for (String algo : ALGORITHM) { ++ for (String mode : MODES) { ++ int padKinds = 2; ++ if (mode.equalsIgnoreCase("CTR")) { ++ padKinds = 1; ++ } ++ for (int k = 0; k < padKinds; k++) { ++ test(algo, mode, PADDING[k]); ++ } ++ } ++ } ++ } ++ ++ public static void test(String algo, String mo, String pad) throws Exception { ++ AlgorithmParameterSpec aps = null; ++ ++ Cipher cipher = Cipher.getInstance(algo + "/" + mo + "/" + pad); ++ ++ KeyGenerator kg = KeyGenerator.getInstance("AES"); ++ if (algo.equalsIgnoreCase("AES_192")) { ++ kg.init(AES_192_KEY_LENGTH); ++ } else if (algo.equalsIgnoreCase("AES_256")) { ++ kg.init(AES_256_KEY_LENGTH); ++ } else { ++ kg.init(AES_128_KEY_LENGTH); ++ } ++ ++ SecretKey key = kg.generateKey(); ++ ++ // encrypt ++ if (!mo.equalsIgnoreCase("GCM")) { ++ cipher.init(Cipher.ENCRYPT_MODE, key, aps); ++ } else { ++ cipher.init(Cipher.ENCRYPT_MODE, key); ++ } ++ ++ String cipherString = null; ++ if (!pad.equalsIgnoreCase("NoPadding")) { ++ cipherString = shortPlainText; ++ } else { ++ cipherString = plainText; ++ } ++ byte[] cipherText = cipher.doFinal(cipherString.getBytes(StandardCharsets.UTF_8)); ++ if (!mo.equalsIgnoreCase("ECB")) { ++ aps = new IvParameterSpec(cipher.getIV()); ++ } else { ++ aps = null; ++ } ++ ++ if (!mo.equalsIgnoreCase("GCM")) { ++ cipher.init(Cipher.DECRYPT_MODE, key, aps); ++ } else { ++ cipher.init(Cipher.DECRYPT_MODE, key, cipher.getParameters()); ++ } ++ ++ String decryptPlainText = new String(cipher.doFinal(cipherText)); ++ ++ if (!cipherString.equals(decryptPlainText)) { ++ throw new RuntimeException("aes decryption failed, algo = " + algo + ", mo = " + mo + ", pad = " + pad); ++ } ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/org/openeuler/security/openssl/SM3Test.java b/test/jdk/org/openeuler/security/openssl/SM3Test.java +new file mode 100644 +index 000000000..e1c5346c9 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/SM3Test.java +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++import java.nio.charset.StandardCharsets; ++import java.util.Arrays; ++import java.security.MessageDigest; ++import java.security.Security; ++ ++/** ++ * @test ++ * @summary Basic test for sm3 ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @run main SM3Test ++ */ ++ ++public class SM3Test { ++ ++ private static String plainText = "helloworldhellow"; ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ test(plainText, "SM3", new byte[]{40, -103, -71, 4, -80, -49, 94, 112, 11, -75, -66, 121, 63, 80, 62, -14, -45, -75, -34, 66, -77, -34, -26, 26, 33, -23, 45, 52, -74, 67, -18, 118}); ++ } ++ ++ public static void test(String plainText, String algo, byte[] expectRes) throws Exception { ++ MessageDigest md = MessageDigest.getInstance(algo); ++ md.update(plainText.getBytes(StandardCharsets.UTF_8)); ++ byte[] res = md.digest(); ++ if (!Arrays.equals(res, expectRes)) { ++ throw new RuntimeException("sm3 failed"); ++ } ++ } ++ ++} +diff --git a/test/jdk/org/openeuler/security/openssl/SM4Test.java b/test/jdk/org/openeuler/security/openssl/SM4Test.java +new file mode 100644 +index 000000000..ac81831ba +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/SM4Test.java +@@ -0,0 +1,153 @@ ++/* ++ * Copyright (c) 2023, 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. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++import java.nio.ByteBuffer; ++import java.nio.charset.StandardCharsets; ++import java.util.Arrays; ++import java.security.Security; ++import javax.crypto.Cipher; ++import javax.crypto.spec.IvParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++ ++/** ++ * @test ++ * @summary Basic test for sm4 ++ * @modules jdk.crypto.kaeprovider/org.openeuler.security.openssl ++ * @run main SM4Test ++ */ ++ ++public class SM4Test { ++ ++ private static SecretKeySpec ks = new SecretKeySpec("sm4EncryptionKey".getBytes(StandardCharsets.UTF_8), "SM4"); // key has 16 bytes ++ private static IvParameterSpec iv = new IvParameterSpec("abcdefghabcdefgh".getBytes(StandardCharsets.UTF_8)); // iv has 16 bytes ++ private static IvParameterSpec shortIv = new IvParameterSpec("abcdefgh".getBytes(StandardCharsets.UTF_8)); // CTR support >= 8bytes iv ++ private static String plainText = "helloworldhellow"; // 16bytes for NoPadding ++ private static String shortPlainText = "helloworld"; // 5 bytes for padding ++ ++ public static void main(String[] args) throws Exception { ++ Security.insertProviderAt(new KAEProvider(), 1); ++ test(plainText, "SM4/CBC/NOPADDING", new byte[]{86, 69, 47, -115, -63, 54, 35, 24, -2, 114, 113, 102, 82, 20, 69, 59}); ++ test(shortPlainText, "SM4/CBC/PKCS5Padding", new byte[]{10, 105, 75, -80, -85, -68, 13, -53, 42, 91, -64, 99, 104, 35, -85, 8}); ++ test(plainText, "SM4/ECB/NOPADDING", new byte[]{103, 36, -31, -53, -109, -12, -71, -79, -54, 106, 10, -3, -35, -22, -122, -67}); ++ test(shortPlainText, "SM4/ECB/PKCS5Padding", new byte[]{-10, 99, -9, 90, 58, -36, -109, 54, -55, -52, 7, -49, 110, -88, 72, 40}); ++ test(plainText, "SM4/CTR/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ test(plainText, "SM4/OFB/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ test(shortPlainText, "SM4/OFB/PKCS5Padding", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110}); ++ ++ testCtrShortIv(plainText, "SM4/CTR/NOPADDING", new byte[]{-13, 73, 40, -36, -64, -67, 75, -72, 90, 58, 73, -4, -36, 115, 126, -48}); ++ ++ testByteBuffer(plainText, "SM4/CBC/NOPADDING", new byte[]{86, 69, 47, -115, -63, 54, 35, 24, -2, 114, 113, 102, 82, 20, 69, 59}); ++ testByteBuffer(shortPlainText, "SM4/CBC/PKCS5Padding", new byte[]{10, 105, 75, -80, -85, -68, 13, -53, 42, 91, -64, 99, 104, 35, -85, 8}); ++ testByteBuffer(plainText, "SM4/ECB/NOPADDING", new byte[]{103, 36, -31, -53, -109, -12, -71, -79, -54, 106, 10, -3, -35, -22, -122, -67}); ++ testByteBuffer(shortPlainText, "SM4/ECB/PKCS5Padding", new byte[]{-10, 99, -9, 90, 58, -36, -109, 54, -55, -52, 7, -49, 110, -88, 72, 40}); ++ testByteBuffer(plainText, "SM4/CTR/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(plainText, "SM4/OFB/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(shortPlainText, "SM4/OFB/PKCS5Padding", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110}); ++ ++ System.setProperty("kae.sm4.maxChunkSize", "65536"); ++ testByteBuffer(plainText, "SM4/CBC/NOPADDING", new byte[]{86, 69, 47, -115, -63, 54, 35, 24, -2, 114, 113, 102, 82, 20, 69, 59}); ++ testByteBuffer(shortPlainText, "SM4/CBC/PKCS5Padding", new byte[]{10, 105, 75, -80, -85, -68, 13, -53, 42, 91, -64, 99, 104, 35, -85, 8}); ++ testByteBuffer(plainText, "SM4/ECB/NOPADDING", new byte[]{103, 36, -31, -53, -109, -12, -71, -79, -54, 106, 10, -3, -35, -22, -122, -67}); ++ testByteBuffer(shortPlainText, "SM4/ECB/PKCS5Padding", new byte[]{-10, 99, -9, 90, 58, -36, -109, 54, -55, -52, 7, -49, 110, -88, 72, 40}); ++ testByteBuffer(plainText, "SM4/CTR/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(plainText, "SM4/OFB/NOPADDING", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110, -100, -113, -46, -29, -11, 71}); ++ testByteBuffer(shortPlainText, "SM4/OFB/PKCS5Padding", new byte[]{32, 108, 35, 108, -16, 119, -111, 114, 94, 110}); ++ } ++ ++ public static void test(String plainText, String algo, byte[] expectRes) throws Exception { ++ Cipher encryptCipher = Cipher.getInstance(algo); ++ if (algo.contains("ECB")) { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks); ++ } else { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, iv); ++ } ++ byte[] cipherText = encryptCipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); ++ if (!Arrays.equals(cipherText, expectRes)) { ++ throw new RuntimeException("sm4 encryption failed, algo = " + algo); ++ } ++ ++ Cipher decryptCipher = Cipher.getInstance(algo); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ String decryptPlainText = new String(decryptCipher.doFinal(cipherText)); ++ if (!plainText.equals(decryptPlainText)) { ++ throw new RuntimeException("sm4 decryption failed, algo = " + algo); ++ } ++ } ++ ++ public static void testCtrShortIv(String plainText, String algo, byte[] expectRes) throws Exception { ++ Cipher encryptCipher = Cipher.getInstance(algo); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, shortIv); ++ byte[] cipherText = encryptCipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); ++ if (!Arrays.equals(cipherText, expectRes)) { ++ throw new RuntimeException("sm4 encryption failed, algo = " + algo); ++ } ++ ++ Cipher decryptCipher = Cipher.getInstance(algo); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ String decryptPlainText = new String(decryptCipher.doFinal(cipherText)); ++ if (!plainText.equals(decryptPlainText)) { ++ throw new RuntimeException("sm4 decryption failed, algo = " + algo); ++ } ++ } ++ ++ public static void testByteBuffer(String plainText, String algo, byte[] expectRes) throws Exception { ++ // encrypt ++ Cipher encryptCipher = Cipher.getInstance(algo); ++ if (algo.contains("ECB")) { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks); ++ } else { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, iv); ++ } ++ int inputLen = plainText.length(); ++ ByteBuffer sourceByteBuffer = ByteBuffer.allocateDirect(inputLen); ++ sourceByteBuffer.put(plainText.getBytes()); ++ sourceByteBuffer.flip(); ++ int outputLen = encryptCipher.getOutputSize(inputLen); ++ ByteBuffer encryptedByteBuffer = ByteBuffer.allocate(outputLen); ++ encryptCipher.doFinal(sourceByteBuffer,encryptedByteBuffer); ++ encryptedByteBuffer.flip(); ++ byte[] encryptedBytes = new byte[encryptedByteBuffer.limit()]; ++ encryptedByteBuffer.get(encryptedBytes); ++ if (!Arrays.equals(encryptedBytes, expectRes)) { ++ throw new RuntimeException("sm4 encryption failed, algo = " + algo); ++ } ++ sourceByteBuffer.clear(); ++ encryptedByteBuffer.flip(); ++ ++ // decrypt ++ Cipher decryptCipher = Cipher.getInstance(algo); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ outputLen = decryptCipher.getOutputSize(encryptedBytes.length); ++ ByteBuffer decryptedByteBuffer = ByteBuffer.allocate(outputLen); ++ decryptCipher.doFinal(encryptedByteBuffer, decryptedByteBuffer); ++ decryptedByteBuffer.flip(); ++ byte[] decryptedBytes = new byte[decryptedByteBuffer.limit()]; ++ decryptedByteBuffer.get(decryptedBytes); ++ if (!Arrays.equals(plainText.getBytes(), decryptedBytes)) { ++ throw new RuntimeException("sm4 decryption failed, algo = " + algo); ++ } ++ encryptedByteBuffer.clear(); ++ decryptedByteBuffer.clear(); ++ } ++} +\ No newline at end of file +diff --git a/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java b/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java +index 58bcbe911..bfc38df35 100644 +--- a/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java ++++ b/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java +@@ -107,7 +107,12 @@ public class PreferredProviderNegativeTest { + + String expected; + String value = args[1]; +- expected = "SunJCE"; ++ ++ if (Security.getProperty("security.provider.1").equals("KAEProvider")) { ++ expected = "KAEProvider"; ++ } else { ++ expected = "SunJCE"; ++ } + + if (args.length >= 2) { + switch (args[0]) { +diff --git a/test/jdk/sun/security/krb5/auto/BasicProc.java b/test/jdk/sun/security/krb5/auto/BasicProc.java +index 0ba0b907b..c67efa446 100644 +--- a/test/jdk/sun/security/krb5/auto/BasicProc.java ++++ b/test/jdk/sun/security/krb5/auto/BasicProc.java +@@ -298,7 +298,9 @@ public class BasicProc { + Proc p = Proc.create("BasicProc") + .inheritProp("jdk.net.hosts.file") + .prop("java.security.manager", "") +- .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") +diff --git a/test/jdk/sun/security/pkcs11/Secmod/policy b/test/jdk/sun/security/pkcs11/Secmod/policy +index e4c95ca6d..60488fd06 100644 +--- a/test/jdk/sun/security/pkcs11/Secmod/policy ++++ b/test/jdk/sun/security/pkcs11/Secmod/policy +@@ -3,4 +3,5 @@ grant { + permission java.io.FilePermission "${test.src}/-", "read"; + permission java.io.FilePermission "${pkcs11test.nss.db}/-", "read"; + permission java.io.FilePermission "${pkcs11test.nss.libdir}/-", "read"; ++ permission java.util.PropertyPermission "kae.disableKaeDispose", "read"; + }; +\ No newline at end of file +diff --git a/test/jdk/sun/security/pkcs11/policy b/test/jdk/sun/security/pkcs11/policy +index 54281a781..4d887e239 100644 +--- a/test/jdk/sun/security/pkcs11/policy ++++ b/test/jdk/sun/security/pkcs11/policy +@@ -1,3 +1,4 @@ + grant { + permission java.lang.RuntimePermission "setSecurityManager"; ++ permission java.util.PropertyPermission "kae.disableKaeDispose", "read"; + }; +\ No newline at end of file +diff --git a/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java b/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java +index 26304c5df..ca618ccfe 100644 +--- a/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java ++++ b/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java +@@ -91,6 +91,10 @@ public class DisabledCurve extends SSLSocketTemplate { + } + + public static void main(String[] args) throws Exception { ++ // KAEProvider does not support sect283r1 ++ if (Security.getProperty("security.provider.1").equals("KAEProvider")) { ++ return; ++ } + String expected = args[1]; + String disabledName = ("DISABLE_NONE".equals(args[0]) ? "" : args[0]); + boolean disabled = false; +diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/NotifyHandshakeTest.policy b/test/jdk/sun/security/ssl/SSLSocketImpl/NotifyHandshakeTest.policy +index b426b173f..6f65e48a3 100644 +--- a/test/jdk/sun/security/ssl/SSLSocketImpl/NotifyHandshakeTest.policy ++++ b/test/jdk/sun/security/ssl/SSLSocketImpl/NotifyHandshakeTest.policy +@@ -33,5 +33,7 @@ grant codeBase "file:com.jar" { + "javax.net.ssl.trustStore", "write"; + permission java.util.PropertyPermission + "javax.net.ssl.trustStorePassword", "write"; ++ permission java.util.PropertyPermission ++ "kae.disableKaeDispose", "read"; + }; + +diff --git a/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java b/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java +new file mode 100644 +index 000000000..8a6e5658d +--- /dev/null ++++ b/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) 2023, 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(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ 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(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] decryptDispose() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] e = encryptedData[index]; ++ index = (index + 1) % SET_SIZE; ++ return decryptCipher.doFinal(e); ++ } ++} ++ +diff --git a/test/micro/org/openeuler/bench/security/openssl/AESGCMBenchmark.java b/test/micro/org/openeuler/bench/security/openssl/AESGCMBenchmark.java +new file mode 100644 +index 000000000..222405235 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/AESGCMBenchmark.java +@@ -0,0 +1,133 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.bench.security.openssl; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++import org.openjdk.jmh.annotations.Fork; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import javax.crypto.NoSuchPaddingException; ++import javax.crypto.spec.GCMParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidKeyException; ++import java.security.NoSuchAlgorithmException; ++import java.security.spec.InvalidParameterSpecException; ++ ++import java.security.Provider; ++ ++ ++public class AESGCMBenchmark extends BenchmarkBase{ ++ ++ @Param({"AES/GCM/NoPadding","AES/GCM/PKCS5Padding"}) ++ private String algorithm; ++ ++ @Param({"128", "192", "256"}) ++ private int keyLength; ++ ++ @Param({""+1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) ++ private int dataSize; ++ ++ byte[] data; ++ byte[] encryptedData; ++ private Cipher encryptCipher; ++ private Cipher decryptCipher; ++ SecretKeySpec ks; ++ GCMParameterSpec gcm_spec; ++ byte[] aad; ++ byte[] iv; ++ ++ public static final int IV_BUFFER_SIZE = 32; ++ public static final int IV_MODULO = IV_BUFFER_SIZE - 16; ++ int iv_index = 0; ++ ++ private int next_iv_index() { ++ int r = iv_index; ++ iv_index = (iv_index + 1) % IV_MODULO; ++ return r; ++ } ++ ++ @Setup ++ public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidParameterSpecException { ++ setupProvider(); ++ assert algorithm.split("/")[1].compareToIgnoreCase("GCM") == 0; ++ ++ byte[] keystring = fillSecureRandom(new byte[keyLength / 8]); ++ ks = new SecretKeySpec(keystring, "AES"); ++ iv = fillSecureRandom(new byte[IV_BUFFER_SIZE]); ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ aad = fillSecureRandom(new byte[5]); ++ encryptCipher = makeCipher(prov, algorithm); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ encryptCipher.updateAAD(aad); ++ decryptCipher = makeCipher(prov, algorithm); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters().getParameterSpec(GCMParameterSpec.class)); ++ decryptCipher.updateAAD(aad); ++ data = fillRandom(new byte[dataSize]); ++ encryptedData = encryptCipher.doFinal(data); ++ } ++ ++ @Benchmark ++ public byte[] encrypt() throws BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException { ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ encryptCipher.updateAAD(aad); ++ return encryptCipher.doFinal(data); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] encrypt_arg() throws BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException { ++ gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec); ++ encryptCipher.updateAAD(aad); ++ return encryptCipher.doFinal(data); ++ } ++ ++ @Benchmark ++ public byte[] decrypt() throws BadPaddingException, IllegalBlockSizeException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException { ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, gcm_spec); ++ decryptCipher.updateAAD(aad); ++ return decryptCipher.doFinal(encryptedData); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] decrypt_arg() throws BadPaddingException, IllegalBlockSizeException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException { ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, gcm_spec); ++ decryptCipher.updateAAD(aad); ++ return decryptCipher.doFinal(encryptedData); ++ } ++ ++ public static Cipher makeCipher(Provider prov, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException { ++ return (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ } ++} ++ +diff --git a/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java b/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java +new file mode 100644 +index 000000000..4e3e7f817 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java +@@ -0,0 +1,106 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.Throughput) ++@OutputTimeUnit(TimeUnit.SECONDS) ++@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS) ++@Measurement(iterations = 8, time = 2, timeUnit = TimeUnit.SECONDS) ++@Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch"}, value = 5) ++@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[] fillRandom(byte[] data) { ++ Random rnd = new Random(); ++ rnd.nextBytes(data); ++ 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/test/micro/org/openeuler/bench/security/openssl/DHKeyAgreementBenchMark.java b/test/micro/org/openeuler/bench/security/openssl/DHKeyAgreementBenchMark.java +new file mode 100644 +index 000000000..eb5ece804 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/DHKeyAgreementBenchMark.java +@@ -0,0 +1,139 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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 java.math.BigInteger; ++import java.security.*; ++import javax.crypto.*; ++import javax.crypto.spec.*; ++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; ++ ++public class DHKeyAgreementBenchMark extends BenchmarkBase { ++ @Param({"DH"}) ++ private String algorithm; ++ ++ @Param({"512", "1024", "2048", "3072", "4096"}) ++ private int keySize; ++ ++ private KeyPairGenerator aliceKpairGen; ++ private KeyPairGenerator bobKpairGen; ++ private KeyPairGenerator carolKpairGen; ++ ++ private KeyPair aliceKpair; ++ private KeyPair bobKpair; ++ private KeyPair carolKpair; ++ ++ private DHParameterSpec dhSkipParamSpec; ++ ++ @Setup ++ public void setUp() throws Exception { ++ setupProvider(); ++ aliceKpairGen = createKeyPairGenerator(); ++ bobKpairGen = createKeyPairGenerator(); ++ carolKpairGen = createKeyPairGenerator(); ++ ++ // Alice creates her own DH key pair ++ aliceKpairGen.initialize(keySize); ++ aliceKpair = aliceKpairGen.generateKeyPair(); ++ // Bob creates his own DH key pair ++ bobKpairGen.initialize(keySize); ++ bobKpair = bobKpairGen.generateKeyPair(); ++ // Carol creates her own DH key pair ++ carolKpairGen.initialize(keySize); ++ carolKpair = carolKpairGen.generateKeyPair(); ++ } ++ ++ @Benchmark ++ public void KeyAgreement() throws Exception { ++ ++ // Alice initialize ++ KeyAgreement aliceKeyAgree = (prov == null ? KeyAgreement.getInstance("DH") : KeyAgreement.getInstance("DH", prov)); ++ aliceKeyAgree.init(aliceKpair.getPrivate()); ++ // Bob initialize ++ KeyAgreement bobKeyAgree = (prov == null ? KeyAgreement.getInstance("DH") : KeyAgreement.getInstance("DH", prov)); ++ bobKeyAgree.init(bobKpair.getPrivate()); ++ // Carol initialize ++ KeyAgreement carolKeyAgree = (prov == null ? KeyAgreement.getInstance("DH") : KeyAgreement.getInstance("DH", prov)); ++ carolKeyAgree.init(carolKpair.getPrivate()); ++ // Alice uses Carol's public key ++ Key ac = aliceKeyAgree.doPhase(carolKpair.getPublic(), false); ++ // Bob uses Alice's public key ++ Key ba = bobKeyAgree.doPhase(aliceKpair.getPublic(), false); ++ // Carol uses Bob's public key ++ Key cb = carolKeyAgree.doPhase(bobKpair.getPublic(), false); ++ // Alice uses Carol's result from above ++ aliceKeyAgree.doPhase(cb, true); ++ // Bob uses Alice's result from above ++ bobKeyAgree.doPhase(ac, true); ++ // Carol uses Bob's result from above ++ carolKeyAgree.doPhase(ba, true); ++ ++ // Alice, Bob and Carol compute their secrets ++ byte[] aliceSharedSecret = aliceKeyAgree.generateSecret(); ++ int aliceLen = aliceSharedSecret.length; ++ ++ byte[] bobSharedSecret = bobKeyAgree.generateSecret(); ++ int bobLen = bobSharedSecret.length; ++ ++ byte[] carolSharedSecret = carolKeyAgree.generateSecret(); ++ int carolLen = carolSharedSecret.length; ++ ++ // Compare Alice and Bob ++ if (aliceLen != bobLen) { ++ throw new Exception("Alice and Bob have different lengths"); ++ } ++ for (int i=0; i pssParameterSpecMap; ++ ++ static { ++ initPSSParameterSpecMap(); ++ } ++ ++ @Param({"SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"}) ++ private String algorithm; ++ ++ @Param({"2048", "3072", "4096"}) ++ private int keySize; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 256 * 1024, "" + 1024 * 1024, "" + 10 * 1024 * 1024}) ++ private int dataSize; ++ ++ private KeyPair keyPair; ++ ++ private byte[][] sigData; ++ ++ ++ private static void initPSSParameterSpecMap() { ++ pssParameterSpecMap = new HashMap<>(); ++ pssParameterSpecMap.put("SHA-1", new PSSParameterSpec("SHA-1", ++ "MGF1", MGF1ParameterSpec.SHA1, 20, PSSParameterSpec.TRAILER_FIELD_BC)); ++ pssParameterSpecMap.put("SHA-224", new PSSParameterSpec("SHA-224", ++ "MGF1", MGF1ParameterSpec.SHA224, 28, PSSParameterSpec.TRAILER_FIELD_BC)); ++ pssParameterSpecMap.put("SHA-256", new PSSParameterSpec("SHA-256", ++ "MGF1", MGF1ParameterSpec.SHA256, 32, PSSParameterSpec.TRAILER_FIELD_BC)); ++ pssParameterSpecMap.put("SHA-384", new PSSParameterSpec("SHA-384", ++ "MGF1", MGF1ParameterSpec.SHA384, 48, PSSParameterSpec.TRAILER_FIELD_BC)); ++ pssParameterSpecMap.put("SHA-512", new PSSParameterSpec("SHA-512", ++ "MGF1", MGF1ParameterSpec.SHA512, 64, PSSParameterSpec.TRAILER_FIELD_BC)); ++ } ++ ++ @Setup ++ public void setup() throws Exception { ++ setupProvider(); ++ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); ++ keyPairGenerator.initialize(keySize); ++ keyPair = keyPairGenerator.generateKeyPair(); ++ data = new byte[SET_SIZE][dataSize]; ++ sigData = getSigBytes(data); ++ } ++ ++ private byte[][] getSigBytes(byte[][] data) throws Exception { ++ byte[][] sigBytes = new byte[data.length][]; ++ Signature signature = prov != null ? Signature.getInstance("RSASSA-PSS", prov) : ++ Signature.getInstance("RSASSA-PSS"); ++ signature.setParameter(pssParameterSpecMap.get(algorithm)); ++ signature.initSign(keyPair.getPrivate()); ++ for (int i = 0; i < sigBytes.length; i++) { ++ signature.update(data[i]); ++ sigBytes[i] = signature.sign(); ++ } ++ return sigBytes; ++ } ++ ++ @Benchmark ++ public void sign() throws Exception { ++ Signature signature = prov != null ? Signature.getInstance("RSASSA-PSS", prov) : ++ Signature.getInstance("RSASSA-PSS"); ++ signature.setParameter(pssParameterSpecMap.get(algorithm)); ++ signature.initSign(keyPair.getPrivate()); ++ signature.update(data[index]); ++ signature.sign(); ++ index = (index + 1) % SET_SIZE; ++ } ++ ++ @Benchmark ++ public void verify() throws Exception { ++ Signature signature = prov != null ? Signature.getInstance("RSASSA-PSS", prov) : ++ Signature.getInstance("RSASSA-PSS"); ++ signature.setParameter(pssParameterSpecMap.get(algorithm)); ++ signature.initVerify(keyPair.getPublic()); ++ signature.update(data[index]); ++ signature.verify(sigData[index]); ++ index = (index + 1) % SET_SIZE; ++ } ++} +diff --git a/test/micro/org/openeuler/bench/security/openssl/RSASignatureBenchmark.java b/test/micro/org/openeuler/bench/security/openssl/RSASignatureBenchmark.java +new file mode 100644 +index 000000000..31112ea57 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/RSASignatureBenchmark.java +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (c) 2023, Huawei Technologies Co., Ltd. All rights reserved. ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++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.security.*; ++ ++/** ++ * RSA Signature Benchmark ++ */ ++public class RSASignatureBenchmark extends BenchmarkBase { ++ @Param({"MD5withRSA", "SHA1withRSA", "SHA224withRSA", "SHA384withRSA", "SHA256withRSA", "SHA512withRSA"}) ++ private String algorithm; ++ ++ @Param({"2048", "3072", "4096"}) ++ private int keySize; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 256 * 1024, "" + 1024 * 1024, "" + 10 * 1024 * 1024}) ++ private int dataSize; ++ ++ private KeyPair keyPair; ++ ++ private byte[][] sigData; ++ ++ @Setup ++ public void setup() throws Exception { ++ setupProvider(); ++ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); ++ keyPairGenerator.initialize(keySize); ++ keyPair = keyPairGenerator.generateKeyPair(); ++ data = new byte[SET_SIZE][dataSize]; ++ sigData = getSigBytes(data); ++ } ++ ++ private byte[][] getSigBytes(byte[][] data) throws Exception { ++ byte[][] sigBytes = new byte[data.length][]; ++ Signature signature = prov != null ? Signature.getInstance(algorithm, prov) : ++ Signature.getInstance(algorithm); ++ signature.initSign(keyPair.getPrivate()); ++ for (int i = 0; i < sigBytes.length; i++) { ++ signature.update(data[i]); ++ sigBytes[i] = signature.sign(); ++ } ++ return sigBytes; ++ } ++ ++ @Benchmark ++ public void sign() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { ++ Signature signature = prov != null ? Signature.getInstance(algorithm, prov) : ++ Signature.getInstance(algorithm); ++ signature.initSign(keyPair.getPrivate()); ++ signature.update(data[index]); ++ signature.sign(); ++ index = (index + 1) % SET_SIZE; ++ } ++ ++ @Benchmark ++ public void verify() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { ++ Signature signature = prov != null ? Signature.getInstance(algorithm, prov) : ++ Signature.getInstance(algorithm); ++ signature.initVerify(keyPair.getPublic()); ++ signature.update(data[index]); ++ signature.verify(sigData[index]); ++ index = (index + 1) % SET_SIZE; ++ } ++} +diff --git a/test/micro/org/openeuler/bench/security/openssl/SM3Benchmark.java b/test/micro/org/openeuler/bench/security/openssl/SM3Benchmark.java +new file mode 100644 +index 000000000..eea830dbe +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/SM3Benchmark.java +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.Benchmark; ++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.Scope; ++import org.openjdk.jmh.annotations.Param; ++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 java.security.MessageDigest; ++import java.security.NoSuchAlgorithmException; ++import java.security.Provider; ++import java.security.Security; ++import java.util.Random; ++import java.util.concurrent.TimeUnit; ++ ++@BenchmarkMode(Mode.Throughput) ++@OutputTimeUnit(TimeUnit.SECONDS) ++@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS) ++@Measurement(iterations = 8, time = 2, timeUnit = TimeUnit.SECONDS) ++@Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch"}, value = 5) ++@Threads(1) ++@State(Scope.Thread) ++public class SM3Benchmark { ++ public static final int SET_SIZE = 128; ++ byte[][] data; ++ int index = 0; ++ ++ @Param({"SM3"}) ++ private String algorithm; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) ++ int dataSize; ++ ++ MessageDigest md; ++ ++ @Setup ++ public void setup() throws NoSuchAlgorithmException { ++ Security.addProvider(new KAEProvider()); ++ Provider prov = Security.getProvider("KAEProvider"); ++ 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(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] digestDispose() { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return md.digest(d); ++ } ++ ++ public static byte[][] fillRandom(byte[][] data) { ++ Random rnd = new Random(); ++ for (byte[] d : data) { ++ rnd.nextBytes(d); ++ } ++ return data; ++ } ++} ++ +diff --git a/test/micro/org/openeuler/bench/security/openssl/SM4Benchmark.java b/test/micro/org/openeuler/bench/security/openssl/SM4Benchmark.java +new file mode 100644 +index 000000000..32de2b235 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/SM4Benchmark.java +@@ -0,0 +1,157 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2023, 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.Benchmark; ++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.Scope; ++import org.openjdk.jmh.annotations.Param; ++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 java.security.InvalidKeyException; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.NoSuchAlgorithmException; ++import java.security.Provider; ++import java.security.SecureRandom; ++import java.security.Security; ++import java.util.Random; ++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; ++ ++@BenchmarkMode(Mode.Throughput) ++@OutputTimeUnit(TimeUnit.SECONDS) ++@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS) ++@Measurement(iterations = 8, time = 2, timeUnit = TimeUnit.SECONDS) ++@Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch"}, value = 5) ++@Threads(1) ++@State(Scope.Thread) ++public class SM4Benchmark { ++ public static final int SET_SIZE = 128; ++ byte[][] data; ++ int index = 0; ++ ++ @Param({"SM4/ECB/NoPadding", "SM4/ECB/PKCS5Padding", "SM4/CBC/NoPadding", "SM4/CBC/PKCS5Padding", "SM4/CTR/NoPadding", "SM4/OFB/NoPadding", "SM4/OFB/PKCS5Padding"}) ++ private String algorithm; ++ ++ @Param({"128"}) ++ 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 { ++ Security.addProvider(new KAEProvider()); ++ Provider prov = Security.getProvider("KAEProvider"); ++ ++ byte[] keystring = fillSecureRandom(new byte[keyLength / 8]); ++ SecretKeySpec ks = new SecretKeySpec(keystring, "SM4"); ++ ++ 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(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ 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(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch", "-Dkae.disableKaeDispose=true"}, value = 5) ++ public byte[] decryptDispose() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] e = encryptedData[index]; ++ index = (index + 1) % SET_SIZE; ++ return decryptCipher.doFinal(e); ++ } ++ ++ public static byte[][] fillRandom(byte[][] data) { ++ Random rnd = new Random(); ++ for (byte[] d : data) { ++ rnd.nextBytes(d); ++ } ++ return data; ++ } ++ ++ public static byte[] fillRandom(byte[] data) { ++ Random rnd = new Random(); ++ rnd.nextBytes(data); ++ 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; ++ } ++} ++ +-- +2.44.0 + diff --git a/openjdk-17.spec b/openjdk-17.spec index a200b536c17daa6f3be178e444d751fdcdf9ef71..94d7a92688ae862458c44eaa2fbab59e943dc3f0 100644 --- a/openjdk-17.spec +++ b/openjdk-17.spec @@ -161,7 +161,7 @@ # Used via new version scheme. JDK 17 was # GA'ed in March 2021 => 21.9 %global vendor_version_string 21.9 -%global securityver 11 +%global securityver 12 # buildjdkver is usually same as %%{majorver}, # but in time of bootstrap of next jdk, it is majorver-1, # and this it is better to change it here, on single place @@ -176,14 +176,18 @@ %global lts_designator_zip "" %endif +%ifarch loongarch64 +%global vendor_version_string Loongson +%else %global vendor_version_string BiSheng +%endif # Standard JPackage naming and versioning defines %global origin openjdk %global origin_nice OpenJDK %global top_level_dir_name %{origin} %global minorver 0 -%global buildver 9 +%global buildver 7 # priority must be 8 digits in total; up to openjdk 1.8, we were using 18..... so when we moved to 11, we had to add another digit %if %is_system_jdk %global priority %( printf '%02d%02d%02d%02d' %{majorver} %{minorver} %{securityver} %{buildver} ) @@ -558,6 +562,9 @@ exit 0 %ifarch %{svml_arches} %{_jvmdir}/%{sdkdir -- %{?1}}/lib/libjsvml.so %endif +%ifarch %{aarch64} +%{_jvmdir}/%{sdkdir -- %{?1}}/lib/libj2kae.so +%endif %{_jvmdir}/%{sdkdir -- %{?1}}/lib/libsyslookup.so %{_jvmdir}/%{sdkdir -- %{?1}}/lib/libverify.so %{_jvmdir}/%{sdkdir -- %{?1}}/lib/libzip.so @@ -594,6 +601,9 @@ exit 0 %{etcjavadir -- %{?1}}/conf/security/policy/README.txt %config(noreplace) %{etcjavadir -- %{?1}}/conf/security/java.policy %config(noreplace) %{etcjavadir -- %{?1}}/conf/security/java.security +%ifarch %{aarch64} +%config(noreplace) %{etcjavadir -- %{?1}}/conf/kaeprovider.conf +%endif %config(noreplace) %{etcjavadir -- %{?1}}/conf/logging.properties %config(noreplace) %{etcjavadir -- %{?1}}/conf/security/nss.cfg %config(noreplace) %{etcjavadir -- %{?1}}/conf/management/jmxremote.access @@ -893,7 +903,7 @@ Provides: java-src%{?1} = %{epoch}:%{version}-%{release} Name: java-%{javaver}-%{origin} Version: %{newjavaver}.%{buildver} -Release: 1 +Release: 0 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages @@ -1000,6 +1010,9 @@ Patch41: 8312200-Fix-Parse-catch_call_exceptions-memory-leak.patch Patch42: Add-problemlist.patch Patch43: puyuan-jdk17.0.9-patch.patch +#17.0.11 +Patch44: jdk17-Add-KAE-provider.patch + ############################################ # # LoongArch64 specific patches @@ -1040,6 +1053,7 @@ BuildRequires: nss-devel BuildRequires: pkgconfig BuildRequires: xorg-x11-proto-devel BuildRequires: zip +BuildRequires: openssl-devel BuildRequires: javapackages-filesystem BuildRequires: java-%{buildjdkver}-openjdk-devel # Zero-assembler build requirement @@ -1255,6 +1269,7 @@ pushd %{top_level_dir_name} %patch41 -p1 %patch42 -p1 %patch43 -p1 +%patch44 -p1 popd # openjdk %endif @@ -1377,23 +1392,19 @@ bash ../configure \ %endif %ifarch %{ppc64le} --with-jobs=1 \ +%endif +%ifarch %{aarch64} + --enable-kae=yes \ %endif --with-version-build=%{buildver} \ --with-version-pre=\"${EA_DESIGNATOR}\" \ --with-version-opt=%{lts_designator} \ -%ifnarch loongarch64 - --with-vendor-version-string="%{vendor_version_string}" \ - --with-vendor-name="openEuler Community" \ -%endif %if "%toolchain" == "clang" --with-toolchain-type=clang \ %endif --with-vendor-url="https://openeuler.org/" \ --with-vendor-bug-url="%{bug_url}" \ --with-vendor-vm-bug-url="%{bug_url}" \ - --with-vendor-bug-url="https://gitee.com/src-openeuler/openjdk-17/issues/" \ - --with-vendor-vm-bug-url="https://gitee.com/src-openeuler/openjdk-17/issues/" \ - --with-vendor-name="BiSheng" \ --with-vendor-version-string="%{vendor_version_string}" \ --with-boot-jdk=/usr/lib/jvm/java-%{buildjdkver}-openjdk \ --with-debug-level=$debugbuild \ @@ -1410,7 +1421,12 @@ bash ../configure \ --with-num-cores="$NUM_PROC" \ --with-source-date="${SOURCE_DATE_EPOCH}" \ --disable-javac-server \ - --disable-warnings-as-errors + --disable-warnings-as-errors \ +%ifarch loongarch64 + --with-vendor-name="Loongson" \ +%else + --with-vendor-name="BiSheng" \ +%endif # Debug builds don't need same targets as release for # build speed-up @@ -1693,9 +1709,10 @@ else end end -- run content of included file with fake args +arg = nil; -- it is better to null the arg up, no meter if they exists or not, and use cjc as module in unified way, instead of relaying on "main" method during require "copy_jdk_configs.lua" cjc = require "copy_jdk_configs.lua" -arg = {"--currentjvm", "%{uniquesuffix %{nil}}", "--jvmdir", "%{_jvmdir %{nil}}", "--origname", "%{name}", "--origjavaver", "%{javaver}", "--arch", "%{_arch}", "--temp", "%{rpm_state_dir}/%{name}.%{_arch}"} -cjc.mainProgram(arg) +args = {"--currentjvm", "%{uniquesuffix %{nil}}", "--jvmdir", "%{_jvmdir %{nil}}", "--origname", "%{name}", "--origjavaver", "%{javaver}", "--arch", "%{_arch}", "--temp", "%{rpm_state_dir}/%{name}.%{_arch}"} +cjc.mainProgram(args) -- the returns from copy_jdk_configs.lua should not affect this 'main', so it should run under all circumstances, except fatal error %post %{post_script %{nil}} @@ -1820,12 +1837,26 @@ cjc.mainProgram(arg) %changelog -* Thu Jun 6 2024 panxuefeng - 1:17.0.11.9-1 -- update LoongArch64-support.patch +* Thu Jul 18 2024 DXwangg - 1:17.0.12.7-0 +- modify 8280872-Reorder-code-cache-segments-to-improv.patch +- update to 17.0.12+7(ga) + +* Tue Jul 16 2024 songliyang - 1:17.0.11.9-4 +- null the arg to solve openjdk-headless install error + +* Thu Jul 4 2024 Autistic_boyya - 1:17.0.11.9-3 +- add jdk17-Add-KAE-provider.patch + +* Thu Jun 20 2024 aoqi - 1:17.0.11.9-2 +- update LoongArch64 port to 17.0.11 + +* Thu May 16 2024 songliyang - 1:17.0.11.9-1 +- rewrite LoongArch64-support.patch to sovle error while applying this patch in prep stage +- fix loongarch vendor error and delete redundant vendor args * Thu Apr 18 2024 Autistic_boyya - 1:17.0.11.9-0.rolling - del 8295068-SSLEngine-throws-NPE-parsing-CertificateRequ.patch -- modify puyuan-jdk17.0.9-patch.patch +- modify puyuan-jdk17.0.9-patch.patch * Mon Feb 26 2024 misaka00251 - 1:17.0.10.9-2 - Remove riscv64 support patch, already upstreamed