diff --git a/8257145-Performance-regression-with-XX-ResizePLAB-af.patch b/8257145-Performance-regression-with-XX-ResizePLAB-af.patch new file mode 100755 index 0000000000000000000000000000000000000000..81b88e7de36e6031513880548ec95a2348d3d056 --- /dev/null +++ b/8257145-Performance-regression-with-XX-ResizePLAB-af.patch @@ -0,0 +1,127 @@ +From 1c751a064538c9e80b49fd0270db034ed0dcf11f Mon Sep 17 00:00:00 2001 +From: wuyan +Date: Thu, 5 Aug 2021 17:29:26 +0800 +Subject: [PATCH 2/8] 8257145: Performance regression with -XX:-ResizePLAB + after JDK-8079555 + +Summary: : backport of JDK-8264640, Performance regression with -XX:-ResizePLAB after JDK-8079555 +LLT: NA +Patch Type: backport +Bug url: https://bugs.openjdk.java.net/browse/JDK-8257145 +--- + src/hotspot/share/gc/cms/parNewGeneration.cpp | 2 +- + src/hotspot/share/gc/g1/g1EvacStats.cpp | 5 +++-- + src/hotspot/share/gc/g1/g1EvacStats.hpp | 2 +- + src/hotspot/share/gc/shared/plab.cpp | 3 +++ + src/hotspot/share/gc/shared/plab.hpp | 6 ++++-- + test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java | 2 +- + 6 files changed, 13 insertions(+), 7 deletions(-) + +diff --git a/src/hotspot/share/gc/cms/parNewGeneration.cpp b/src/hotspot/share/gc/cms/parNewGeneration.cpp +index 1b95cf52e..b1e8bde61 100644 +--- a/src/hotspot/share/gc/cms/parNewGeneration.cpp ++++ b/src/hotspot/share/gc/cms/parNewGeneration.cpp +@@ -627,7 +627,7 @@ ParNewGeneration::ParNewGeneration(ReservedSpace rs, size_t initial_byte_size) + : DefNewGeneration(rs, initial_byte_size, "PCopy"), + _overflow_list(NULL), + _is_alive_closure(this), +- _plab_stats("Young", YoungPLABSize, PLABWeight) ++ _plab_stats("Young", YoungPLABSize, YoungPLABSize * ParallelGCThreads, PLABWeight) + { + NOT_PRODUCT(_overflow_counter = ParGCWorkQueueOverflowInterval;) + NOT_PRODUCT(_num_par_pushes = 0;) +diff --git a/src/hotspot/share/gc/g1/g1EvacStats.cpp b/src/hotspot/share/gc/g1/g1EvacStats.cpp +index 70c399691..7070e1840 100644 +--- a/src/hotspot/share/gc/g1/g1EvacStats.cpp ++++ b/src/hotspot/share/gc/g1/g1EvacStats.cpp +@@ -28,6 +28,7 @@ + #include "gc/shared/gcId.hpp" + #include "logging/log.hpp" + #include "memory/allocation.inline.hpp" ++#include "runtime/globals.hpp" + + void G1EvacStats::log_plab_allocation() { + PLABStats::log_plab_allocation(); +@@ -89,8 +90,8 @@ size_t G1EvacStats::compute_desired_plab_sz() { + return cur_plab_sz; + } + +-G1EvacStats::G1EvacStats(const char* description, size_t desired_plab_sz_, unsigned wt) : +- PLABStats(description, desired_plab_sz_, wt), ++G1EvacStats::G1EvacStats(const char* description, size_t default_per_thread_plab_size, unsigned wt) : ++ PLABStats(description, default_per_thread_plab_size, default_per_thread_plab_size * ParallelGCThreads, wt), + _region_end_waste(0), + _regions_filled(0), + _direct_allocated(0), +diff --git a/src/hotspot/share/gc/g1/g1EvacStats.hpp b/src/hotspot/share/gc/g1/g1EvacStats.hpp +index 4ac6fd9f5..0baf2fc20 100644 +--- a/src/hotspot/share/gc/g1/g1EvacStats.hpp ++++ b/src/hotspot/share/gc/g1/g1EvacStats.hpp +@@ -56,7 +56,7 @@ class G1EvacStats : public PLABStats { + virtual size_t compute_desired_plab_sz(); + + public: +- G1EvacStats(const char* description, size_t desired_plab_sz_, unsigned wt); ++ G1EvacStats(const char* description, size_t default_per_thread_plab_size, unsigned wt); + + ~G1EvacStats(); + +diff --git a/src/hotspot/share/gc/shared/plab.cpp b/src/hotspot/share/gc/shared/plab.cpp +index 29c4cc694..0ad6dda4a 100644 +--- a/src/hotspot/share/gc/shared/plab.cpp ++++ b/src/hotspot/share/gc/shared/plab.cpp +@@ -136,6 +136,9 @@ void PLABStats::log_sizing(size_t calculated_words, size_t net_desired_words) { + + // Calculates plab size for current number of gc worker threads. + size_t PLABStats::desired_plab_sz(uint no_of_gc_workers) { ++ if (!ResizePLAB) { ++ return _default_plab_sz; ++ } + return align_object_size(MIN2(MAX2(min_size(), _desired_net_plab_sz / no_of_gc_workers), max_size())); + } + +diff --git a/src/hotspot/share/gc/shared/plab.hpp b/src/hotspot/share/gc/shared/plab.hpp +index 608dce56c..06e9cfef3 100644 +--- a/src/hotspot/share/gc/shared/plab.hpp ++++ b/src/hotspot/share/gc/shared/plab.hpp +@@ -151,6 +151,7 @@ class PLABStats : public CHeapObj { + size_t _wasted; // of which wasted (internal fragmentation) + size_t _undo_wasted; // of which wasted on undo (is not used for calculation of PLAB size) + size_t _unused; // Unused in last buffer ++ size_t _default_plab_sz; + size_t _desired_net_plab_sz;// Output of filter (below), suitably trimmed and quantized + AdaptiveWeightedAverage + _filter; // Integrator with decay +@@ -169,13 +170,14 @@ class PLABStats : public CHeapObj { + virtual size_t compute_desired_plab_sz(); + + public: +- PLABStats(const char* description, size_t desired_net_plab_sz_, unsigned wt) : ++ PLABStats(const char* description, size_t default_per_thread_plab_size, size_t desired_net_plab_sz, unsigned wt) : + _description(description), + _allocated(0), + _wasted(0), + _undo_wasted(0), + _unused(0), +- _desired_net_plab_sz(desired_net_plab_sz_), ++ _default_plab_sz(default_per_thread_plab_size), ++ _desired_net_plab_sz(desired_net_plab_sz), + _filter(wt) + { } + +diff --git a/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java b/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java +index 97f221eeb..6be46e36b 100644 +--- a/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java ++++ b/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java +@@ -73,7 +73,7 @@ public class TestPLABPromotion { + private static final int PLAB_SIZE_HIGH = 65536; + private static final int OBJECT_SIZE_SMALL = 10; + private static final int OBJECT_SIZE_MEDIUM = 100; +- private static final int OBJECT_SIZE_HIGH = 1000; ++ private static final int OBJECT_SIZE_HIGH = 3500; + private static final int GC_NUM_SMALL = 1; + private static final int GC_NUM_MEDIUM = 3; + private static final int GC_NUM_HIGH = 7; +-- +2.22.0 + diff --git a/8268427-Improve-AlgorithmConstraints-checkAlgorithm-.patch b/8268427-Improve-AlgorithmConstraints-checkAlgorithm-.patch new file mode 100755 index 0000000000000000000000000000000000000000..776c4e75397edbd72d5c3dd0c3148f5a6f7d1a73 --- /dev/null +++ b/8268427-Improve-AlgorithmConstraints-checkAlgorithm-.patch @@ -0,0 +1,242 @@ +From e3d9485d01941cfbbe01dc8dcea7b913c2e8469d Mon Sep 17 00:00:00 2001 +From: chenshanyao +Date: Tue, 14 Sep 2021 11:43:18 +0800 +Subject: [PATCH 8/8] 8268427: Improve AlgorithmConstraints:checkAlgorithm + performance + +Summary: : performance +LLT: jdk_security +Patch Type: backport +Bug url: https://bugs.openjdk.java.net/browse/JDK-8268427 +--- + .../util/AbstractAlgorithmConstraints.java | 39 +++++------ + .../util/DisabledAlgorithmConstraints.java | 28 ++++---- + .../util/LegacyAlgorithmConstraints.java | 2 +- + .../security/AlgorithmConstraintsPermits.java | 66 +++++++++++++++++++ + 4 files changed, 95 insertions(+), 40 deletions(-) + create mode 100644 test/micro/org/openjdk/bench/java/security/AlgorithmConstraintsPermits.java + +diff --git a/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java +index 8d8c5d6fe..3f5678950 100644 +--- a/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java ++++ b/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java +@@ -32,6 +32,7 @@ import java.security.Security; + import java.util.ArrayList; + import java.util.Arrays; + import java.util.Collections; ++import java.util.TreeSet; + import java.util.List; + import java.util.Set; + +@@ -48,7 +49,7 @@ public abstract class AbstractAlgorithmConstraints + } + + // Get algorithm constraints from the specified security property. +- static List getAlgorithms(String propertyName) { ++ static Set getAlgorithms(String propertyName) { + String property = AccessController.doPrivileged( + new PrivilegedAction() { + @Override +@@ -72,38 +73,30 @@ public abstract class AbstractAlgorithmConstraints + + // map the disabled algorithms + if (algorithmsInProperty == null) { +- return Collections.emptyList(); ++ return Collections.emptySet(); + } +- return new ArrayList<>(Arrays.asList(algorithmsInProperty)); ++ Set algorithmsInPropertySet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); ++ algorithmsInPropertySet.addAll(Arrays.asList(algorithmsInProperty)); ++ return algorithmsInPropertySet; + } + +- static boolean checkAlgorithm(List algorithms, String algorithm, ++ static boolean checkAlgorithm(Set algorithms, String algorithm, + AlgorithmDecomposer decomposer) { + if (algorithm == null || algorithm.isEmpty()) { + throw new IllegalArgumentException("No algorithm name specified"); + } + +- Set elements = null; +- for (String item : algorithms) { +- if (item == null || item.isEmpty()) { +- continue; +- } +- +- // check the full name +- if (item.equalsIgnoreCase(algorithm)) { +- return false; +- } ++ if (algorithms.contains(algorithm)) { ++ return false; ++ } + +- // decompose the algorithm into sub-elements +- if (elements == null) { +- elements = decomposer.decompose(algorithm); +- } ++ // decompose the algorithm into sub-elements ++ Set elements = decomposer.decompose(algorithm); + +- // check the items of the algorithm +- for (String element : elements) { +- if (item.equalsIgnoreCase(element)) { +- return false; +- } ++ // check the element of the elements ++ for (String element : elements) { ++ if (algorithms.contains(element)) { ++ return false; + } + } + +diff --git a/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java +index 3ee431e62..efc6d339f 100644 +--- a/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java ++++ b/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java +@@ -85,6 +85,9 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { + private static final String PROPERTY_DISABLED_EC_CURVES = + "jdk.disabled.namedCurves"; + ++ private static final Pattern INCLUDE_PATTERN = Pattern.compile("include " + ++ PROPERTY_DISABLED_EC_CURVES, Pattern.CASE_INSENSITIVE); ++ + private static class CertPathHolder { + static final DisabledAlgorithmConstraints CONSTRAINTS = + new DisabledAlgorithmConstraints(PROPERTY_CERTPATH_DISABLED_ALGS); +@@ -95,7 +98,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { + new DisabledAlgorithmConstraints(PROPERTY_JAR_DISABLED_ALGS); + } + +- private final List disabledAlgorithms; ++ private final Set disabledAlgorithms; + private final Constraints algorithmConstraints; + + public static DisabledAlgorithmConstraints certPathConstraints() { +@@ -130,21 +133,14 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { + disabledAlgorithms = getAlgorithms(propertyName); + + // Check for alias +- int ecindex = -1, i = 0; + for (String s : disabledAlgorithms) { +- if (s.regionMatches(true, 0,"include ", 0, 8)) { +- if (s.regionMatches(true, 8, PROPERTY_DISABLED_EC_CURVES, 0, +- PROPERTY_DISABLED_EC_CURVES.length())) { +- ecindex = i; +- break; +- } ++ Matcher matcher = INCLUDE_PATTERN.matcher(s); ++ if (matcher.matches()) { ++ disabledAlgorithms.remove(matcher.group()); ++ disabledAlgorithms.addAll( ++ getAlgorithms(PROPERTY_DISABLED_EC_CURVES)); ++ break; + } +- i++; +- } +- if (ecindex > -1) { +- disabledAlgorithms.remove(ecindex); +- disabledAlgorithms.addAll(ecindex, +- getAlgorithms(PROPERTY_DISABLED_EC_CURVES)); + } + algorithmConstraints = new Constraints(propertyName, disabledAlgorithms); + } +@@ -323,8 +319,8 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { + "denyAfter\\s+(\\d{4})-(\\d{2})-(\\d{2})"); + } + +- public Constraints(String propertyName, List constraintArray) { +- for (String constraintEntry : constraintArray) { ++ public Constraints(String propertyName, Set constraintSet) { ++ for (String constraintEntry : constraintSet) { + if (constraintEntry == null || constraintEntry.isEmpty()) { + continue; + } +diff --git a/src/java.base/share/classes/sun/security/util/LegacyAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/LegacyAlgorithmConstraints.java +index e4e5cedc1..550173080 100644 +--- a/src/java.base/share/classes/sun/security/util/LegacyAlgorithmConstraints.java ++++ b/src/java.base/share/classes/sun/security/util/LegacyAlgorithmConstraints.java +@@ -40,7 +40,7 @@ public class LegacyAlgorithmConstraints extends AbstractAlgorithmConstraints { + public static final String PROPERTY_TLS_LEGACY_ALGS = + "jdk.tls.legacyAlgorithms"; + +- private final List legacyAlgorithms; ++ private final Set legacyAlgorithms; + + public LegacyAlgorithmConstraints(String propertyName, + AlgorithmDecomposer decomposer) { +diff --git a/test/micro/org/openjdk/bench/java/security/AlgorithmConstraintsPermits.java b/test/micro/org/openjdk/bench/java/security/AlgorithmConstraintsPermits.java +new file mode 100644 +index 000000000..3cb9567b9 +--- /dev/null ++++ b/test/micro/org/openjdk/bench/java/security/AlgorithmConstraintsPermits.java +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openjdk.bench.java.security; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.BenchmarkMode; ++import org.openjdk.jmh.annotations.Fork; ++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 sun.security.util.DisabledAlgorithmConstraints; ++ ++import java.security.AlgorithmConstraints; ++import java.security.CryptoPrimitive; ++import java.util.concurrent.TimeUnit; ++import java.util.EnumSet; ++import java.util.Set; ++ ++import static sun.security.util.DisabledAlgorithmConstraints.PROPERTY_TLS_DISABLED_ALGS; ++ ++@BenchmarkMode(Mode.AverageTime) ++@OutputTimeUnit(TimeUnit.NANOSECONDS) ++@Fork(jvmArgsAppend = {"--add-exports", "java.base/sun.security.util=ALL-UNNAMED"}) ++@State(Scope.Thread) ++public class AlgorithmConstraintsPermits { ++ ++ AlgorithmConstraints tlsDisabledAlgConstraints; ++ Set primitives = EnumSet.of(CryptoPrimitive.KEY_AGREEMENT); ++ ++ @Param({"SSLv3", "DES", "NULL", "TLS1.3"}) ++ String algorithm; ++ ++ @Setup ++ public void setup() { ++ tlsDisabledAlgConstraints = new DisabledAlgorithmConstraints(PROPERTY_TLS_DISABLED_ALGS); ++ } ++ ++ @Benchmark ++ public boolean permits() { ++ return tlsDisabledAlgConstraints.permits(primitives, algorithm, null); ++ } ++} ++ +-- +2.22.0 + diff --git a/Add-KAE-implementation.patch b/Add-KAE-implementation.patch new file mode 100755 index 0000000000000000000000000000000000000000..77e1ca751623cf89e7098a8818a89ed0f10158da --- /dev/null +++ b/Add-KAE-implementation.patch @@ -0,0 +1,11284 @@ +From 91191c089cd8ad301c9e5b423b657d18b98ad6c9 Mon Sep 17 00:00:00 2001 +From: hedongbo +Date: Mon, 13 Sep 2021 10:18:05 +0800 +Subject: [PATCH 7/8] Add KAE implementation + +Summary: : Add KAE impl +LLT: test/jdk/org/openeuler/security/openssl/ +Patch Type: huawei +Bug url: NA +--- + make/ZipSecurity.gmk | 1 + + make/autoconf/configure.ac | 1 + + make/autoconf/jdk-options.m4 | 23 + + make/autoconf/spec.gmk.in | 1 + + make/common/Modules.gmk | 13 + + make/copy/Copy-jdk.crypto.kaeprovider.gmk | 46 + + make/lib/Lib-jdk.crypto.kaeprovider.gmk | 51 ++ + make/nb_native/nbproject/configurations.xml | 104 +++ + src/java.base/share/classes/module-info.java | 10 +- + .../share/lib/security/default.policy | 5 + + .../share/classes/module-info.java | 6 + + .../linux/classes/module-info.java | 39 + + .../security/openssl/KAEAESCipher.java | 365 ++++++++ + .../security/openssl/KAEDHKeyAgreement.java | 289 +++++++ + .../openssl/KAEDHKeyPairGenerator.java | 166 ++++ + .../openeuler/security/openssl/KAEDigest.java | 264 ++++++ + .../security/openssl/KAEECDHKeyAgreement.java | 146 ++++ + .../openssl/KAEECKeyPairGenerator.java | 154 ++++ + .../openeuler/security/openssl/KAEHMac.java | 228 +++++ + .../security/openssl/KAEProvider.java | 338 ++++++++ + .../security/openssl/KAERSACipher.java | 796 ++++++++++++++++++ + .../openssl/KAERSAKeyPairGenerator.java | 164 ++++ + .../security/openssl/KAERSAPSSSignature.java | 713 ++++++++++++++++ + .../security/openssl/KAERSAPaddingType.java | 83 ++ + .../security/openssl/KAERSASignature.java | 365 ++++++++ + .../openssl/KAERSASignatureNative.java | 46 + + .../security/openssl/KAESM4Cipher.java | 188 +++++ + .../openssl/KAESymmetricCipherBase.java | 615 ++++++++++++++ + .../openeuler/security/openssl/KAEUtils.java | 220 +++++ + .../linux/conf/security/kaeprovider.conf | 19 + + .../security/openssl/kae_cipher_rsa.c | 467 ++++++++++ + .../openeuler/security/openssl/kae_digest.c | 235 ++++++ + .../security/openssl/kae_exception.c | 134 +++ + .../security/openssl/kae_exception.h | 57 ++ + .../org/openeuler/security/openssl/kae_hmac.c | 203 +++++ + .../security/openssl/kae_keyagreement_dh.c | 139 +++ + .../security/openssl/kae_keyagreement_ecdh.c | 115 +++ + .../openssl/kae_keypairgenerator_dh.c | 132 +++ + .../openssl/kae_keypairgenerator_ec.c | 508 +++++++++++ + .../openssl/kae_keypairgenerator_rsa.c | 167 ++++ + .../org/openeuler/security/openssl/kae_log.h | 33 + + .../openeuler/security/openssl/kae_provider.c | 57 ++ + .../security/openssl/kae_signature_rsa.c | 363 ++++++++ + .../security/openssl/kae_symmetric_cipher.c | 409 +++++++++ + .../org/openeuler/security/openssl/kae_util.c | 111 +++ + .../org/openeuler/security/openssl/kae_util.h | 47 ++ + test/jdk/TEST.groups | 3 + + .../KeyAgreement/KeyAgreementTest.java | 12 +- + .../Signature/SignatureGetInstance.java | 5 +- + .../openeuler/security/openssl/DHTest.java | 130 +++ + .../openeuler/security/openssl/ECDHTest.java | 117 +++ + .../openeuler/security/openssl/SM3Test.java | 54 ++ + .../openeuler/security/openssl/SM4Test.java | 95 +++ + .../jca/PreferredProviderNegativeTest.java | 2 + + .../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 ++++ + 74 files changed, 10539 insertions(+), 4 deletions(-) + create mode 100644 make/copy/Copy-jdk.crypto.kaeprovider.gmk + create mode 100644 make/lib/Lib-jdk.crypto.kaeprovider.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/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/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/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 test/jdk/org/openeuler/security/openssl/DHTest.java + create mode 100644 test/jdk/org/openeuler/security/openssl/ECDHTest.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 ba5664122..382ca4218 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 6672d26a5..c3e8ceb35 100644 +--- a/make/autoconf/configure.ac ++++ b/make/autoconf/configure.ac +@@ -232,6 +232,7 @@ HOTSPOT_SETUP_JVM_FEATURES + # + ############################################################################### + ++JDKOPT_DETECT_KAE + JDKOPT_DETECT_INTREE_EC + JDKOPT_ENABLE_DISABLE_FAILURE_HANDLER + JDKOPT_ENABLE_DISABLE_GENERATE_CLASSLIST +diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 +index 9d64b31bf..e20eafa60 100644 +--- a/make/autoconf/jdk-options.m4 ++++ b/make/autoconf/jdk-options.m4 +@@ -280,6 +280,29 @@ AC_DEFUN_ONCE([JDKOPT_DETECT_INTREE_EC], + AC_SUBST(ENABLE_INTREE_EC) + ]) + ++############################################################################### ++# ++# 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="false" ++ AC_MSG_CHECKING([if kae should be enabled]) ++ if test "x$enable_kae" = "xyes"; then ++ AC_MSG_RESULT([yes]) ++ ENABLE_KAE="true" ++ elif test "x$enable_kae" = "x" || test "x$enable_kae" = "xno"; then ++ AC_MSG_RESULT([no]) ++ ENABLE_KAE="false" ++ else ++ AC_MSG_ERROR([Invalid value for --enable-kae: $enable_kae]) ++ fi ++ ++ AC_SUBST(ENABLE_KAE) ++]) ++ + AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS], + [ + # +diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in +index 39b4439cb..92cda01c9 100644 +--- a/make/autoconf/spec.gmk.in ++++ b/make/autoconf/spec.gmk.in +@@ -761,6 +761,7 @@ TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TRANSFORM@ + # Build setup + ENABLE_AOT:=@ENABLE_AOT@ + ENABLE_INTREE_EC:=@ENABLE_INTREE_EC@ ++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 41533e566..9fa545605 100644 +--- a/make/common/Modules.gmk ++++ b/make/common/Modules.gmk +@@ -118,6 +118,12 @@ PLATFORM_MODULES += \ + jdk.zipfs \ + # + ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ PLATFORM_MODULES += jdk.crypto.kaeprovider ++ endif ++endif ++ + ifeq ($(OPENJDK_TARGET_OS), windows) + PLATFORM_MODULES += jdk.crypto.mscapi + endif +@@ -228,6 +234,13 @@ ifeq ($(ENABLE_AOT), false) + MODULES_FILTER += jdk.aot + 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 ++ + ################################################################################ + # Module list macros + +diff --git a/make/copy/Copy-jdk.crypto.kaeprovider.gmk b/make/copy/Copy-jdk.crypto.kaeprovider.gmk +new file mode 100644 +index 000000000..ef0bfd88a +--- /dev/null ++++ b/make/copy/Copy-jdk.crypto.kaeprovider.gmk +@@ -0,0 +1,46 @@ ++# ++# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. ++# Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++# ++# This code is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License version 2 only, as ++# published by the Free Software Foundation. Oracle designates this ++# particular file as subject to the "Classpath" exception as provided ++# by Oracle in the LICENSE file that accompanied this code. ++# ++# This code is distributed in the hope that it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++# version 2 for more details (a copy is included in the LICENSE file that ++# accompanied this code). ++# ++# You should have received a copy of the GNU General Public License version ++# 2 along with this work; if not, write to the Free Software Foundation, ++# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++# or visit www.oracle.com if you need additional information or have any ++# questions. ++# ++ ++include CopyCommon.gmk ++ ++################################################################################ ++ ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ ++ KAEPROVIDER_CONF_SRC := $(TOPDIR)/src/jdk.crypto.kaeprovider/linux/conf/security/kaeprovider.conf ++ KAEPROVIDER_CONF_DST := $(CONF_DST_DIR)/kaeprovider.conf ++ ++ $(KAEPROVIDER_CONF_DST): $(KAEPROVIDER_CONF_SRC) ++ $(call install-file) ++ ++ TARGETS += $(KAEPROVIDER_CONF_DST) ++ ++ endif ++endif ++ ++ ++################################################################################ +diff --git a/make/lib/Lib-jdk.crypto.kaeprovider.gmk b/make/lib/Lib-jdk.crypto.kaeprovider.gmk +new file mode 100644 +index 000000000..516a957d0 +--- /dev/null ++++ b/make/lib/Lib-jdk.crypto.kaeprovider.gmk +@@ -0,0 +1,51 @@ ++# ++# Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++# ++# This code is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License version 2 only, as ++# published by the Free Software Foundation. Oracle designates this ++# particular file as subject to the "Classpath" exception as provided ++# by Oracle in the LICENSE file that accompanied this code. ++# ++# This code is distributed in the hope that it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++# version 2 for more details (a copy is included in the LICENSE file that ++# accompanied this code). ++# ++# You should have received a copy of the GNU General Public License version ++# 2 along with this work; if not, write to the Free Software Foundation, ++# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++# or visit www.oracle.com if you need additional information or have any ++# questions. ++# ++ ++include LibCommon.gmk ++ ++LIBMEMCPY_FILES += \ ++ $(addprefix $(TOPDIR)/src/hotspot/share/runtime/, \ ++ memcpy.cpp \ ++ ) ++ ++################################################################################ ++ ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ $(eval $(call SetupJdkLibrary, BUILD_LIBJ2KAE, \ ++ NAME := j2kae, \ ++ OPTIMIZATION := LOW, \ ++ EXTRA_FILES := $(LIBMEMCPY_FILES), \ ++ CFLAGS := $(CFLAGS_JDKLIB), \ ++ LDFLAGS := $(LDFLAGS_JDKLIB) \ ++ $(call SET_SHARED_LIBRARY_ORIGIN), \ ++ LIBS_unix := $(LIBDL) -lssl -lcrypto, \ ++ )) ++ ++ TARGETS += $(BUILD_LIBJ2KAE) ++ endif ++endif ++ ++################################################################################ +diff --git a/make/nb_native/nbproject/configurations.xml b/make/nb_native/nbproject/configurations.xml +index fb07d54c1..38da09395 100644 +--- a/make/nb_native/nbproject/configurations.xml ++++ b/make/nb_native/nbproject/configurations.xml +@@ -5366,6 +5366,30 @@ + + + ++ ++ ++ ++ ++ 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 ++ ++ ++ ++ + + + +@@ -38406,6 +38430,86 @@ + tool="3" + flavor2="0"> + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + 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/KAEDHKeyAgreement.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyAgreement.java +new file mode 100644 +index 000000000..6986d2548 +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.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.AlgorithmParameterGeneratorSpi; ++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(); ++ ++ 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..429c65fc0 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEDHKeyPairGenerator.java +@@ -0,0 +1,166 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.math.BigInteger; ++import java.util.Map; ++import java.util.concurrent.ConcurrentHashMap; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.KeyPairGeneratorSpi; ++import java.security.SecureRandom; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.KeyPair; ++import java.security.Key; ++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); ++ } ++ ++ 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); ++ } ++ } ++ 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..bb5c8681b +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.security.DigestException; ++import java.security.MessageDigestSpi; ++import java.security.ProviderException; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++/** ++ * KAE Digest ++ */ ++abstract class KAEDigest extends MessageDigestSpi implements Cloneable { ++ ++ public static final class MD5 extends KAEDigest { ++ private static final long initContext = nativeInit("md5"); ++ ++ public MD5() { ++ super("md5", 16, initContext); ++ } ++ } ++ ++ public static final class SM3 extends KAEDigest { ++ private static final long initContext = nativeInit("sm3"); ++ ++ public SM3() { ++ super("sm3", 32, initContext); ++ } ++ } ++ ++ public static final class SHA256 extends KAEDigest { ++ private static final long initContext = nativeInit("sha256"); ++ ++ public SHA256() { ++ super("sha256", 32, initContext); ++ } ++ } ++ ++ public static final class SHA384 extends KAEDigest { ++ private static final long initContext = nativeInit("sha384"); ++ ++ public SHA384() { ++ super("sha384", 48, initContext); ++ } ++ } ++ ++ private final int digestLength; ++ ++ private final String algorithm; ++ private final long initContext; ++ ++ // field for ensuring native memory is freed ++ private DigestContextRef contextRef = null; ++ ++ KAEDigest(String algorithm, int digestLength, long initContext) { ++ this.algorithm = algorithm; ++ this.digestLength = digestLength; ++ this.initContext = initContext; ++ } ++ ++ private static class DigestContextRef extends PhantomReference ++ 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..7a9cc5cc5 +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.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..60fa8183c +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEECKeyPairGenerator.java +@@ -0,0 +1,154 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.ec.ECPrivateKeyImpl; ++import sun.security.ec.ECPublicKeyImpl; ++ ++import java.math.BigInteger; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidParameterException; ++import java.security.InvalidKeyException; ++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.util.HashMap; ++import java.util.Map; ++ ++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..c66fa2ff7 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEHMac.java +@@ -0,0 +1,228 @@ ++/* ++ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import javax.crypto.MacSpi; ++import javax.crypto.SecretKey; ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.nio.ByteBuffer; ++import java.security.*; ++import java.security.spec.AlgorithmParameterSpec; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++public abstract class 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/KAEProvider.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEProvider.java +new file mode 100644 +index 000000000..12fee8861 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAEProvider.java +@@ -0,0 +1,338 @@ ++/* ++ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.io.BufferedWriter; ++import java.io.BufferedInputStream; ++import java.io.File; ++import java.io.FileInputStream; ++import java.io.InputStream; ++import java.io.IOException; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.Paths; ++import java.nio.file.StandardOpenOption; ++import java.util.Date; ++import java.util.Properties; ++import java.security.Provider; ++ ++import static sun.security.util.SecurityConstants.PROVIDER_VER; ++ ++/** ++ * KAE Provider ++ */ ++public class KAEProvider extends Provider { ++ ++ private static final long serialVersionUID = -9077316390050005439L; ++ ++ private static Throwable excp; ++ private static boolean needLog = true; ++ ++ static { ++ Throwable status = null; ++ try { ++ System.loadLibrary("j2kae"); ++ initOpenssl(); ++ } catch (UnsatisfiedLinkError t) { ++ status = t; ++ } catch (RuntimeException e) { ++ status = e; ++ } ++ excp = status; ++ } ++ ++ private void logStart(Throwable excp) { ++ File file = new File(System.getProperty("user.dir"), "kae.log"); ++ Path fpath = file.toPath(); ++ if (!Files.exists(fpath)) { ++ try { ++ file.createNewFile(); ++ } catch (IOException e) { ++ e.printStackTrace(); ++ } ++ } ++ ++ try (BufferedWriter writer = Files.newBufferedWriter(fpath, StandardOpenOption.APPEND)) { ++ if (excp != null) { ++ writer.write(excp.getMessage()); ++ } else { ++ writer.write("KAE Engine was found"); ++ } ++ writer.write(" " + new Date()); ++ writer.newLine(); ++ } catch (IOException e) { ++ e.initCause(excp).printStackTrace(); ++ } ++ KAEProvider.excp = null; // Exception already logged, clean it. ++ } ++ ++ private Properties getProp() { ++ Properties props = new Properties(); ++ String sep = File.separator; ++ File propFile = new File(System.getProperty("java.home") + sep + "conf" + sep + ++ "kaeprovider.conf"); ++ if (propFile.exists()) { ++ try (InputStream is = new BufferedInputStream(new FileInputStream(propFile))) { ++ props.load(is); ++ } catch (IOException e) { ++ e.printStackTrace(); ++ } ++ } ++ return props; ++ } ++ ++ public KAEProvider() { ++ super("KAEProvider", PROVIDER_VER, "KAE provider"); ++ Properties props = getProp(); ++ if (needLog && "true".equalsIgnoreCase(props.getProperty("kae.log"))) { ++ logStart(excp); ++ needLog = false; // Log only once ++ } else { ++ KAEProvider.excp = null; // Ignore exception. ++ } ++ if (!"false".equalsIgnoreCase(props.getProperty("kae.md5"))) { ++ putMD5(); ++ } ++ if (!"false".equalsIgnoreCase(props.getProperty("kae.sha256"))) { ++ putSHA256(); ++ } ++ if (!"false".equalsIgnoreCase(props.getProperty("kae.sha384"))) { ++ putSHA384(); ++ } ++ if (!"false".equalsIgnoreCase(props.getProperty("kae.sm3"))) { ++ putSM3(); ++ } ++ if (!"false".equalsIgnoreCase(props.getProperty("kae.aes"))) { ++ putAES(); ++ } ++ if (!"false".equalsIgnoreCase(props.getProperty("kae.sm4"))) { ++ putSM4(); ++ } ++ if (!"false".equalsIgnoreCase(props.getProperty("kae.hmac"))) { ++ putHMAC(); ++ } ++ if (!"false".equalsIgnoreCase(props.getProperty("kae.rsa"))) { ++ putRSA(); ++ putSignatureRSA(); ++ } ++ if (!"false".equalsIgnoreCase(props.getProperty("kae.dh"))) { ++ putDH(); ++ } ++ if (!"false".equalsIgnoreCase(props.getProperty("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", "com.sun.crypto.provider.AESKeyGenerator"); ++ 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() throws RuntimeException; ++} +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..0935ebb23 +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; ++import sun.security.jca.Providers; ++import sun.security.rsa.RSACore; ++import sun.security.rsa.RSAKeyFactory; ++import sun.security.rsa.RSAPadding; ++import sun.security.util.KeyUtil; ++ ++import javax.crypto.*; ++import javax.crypto.spec.OAEPParameterSpec; ++import javax.crypto.spec.PSource; ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.security.*; ++import java.security.interfaces.RSAKey; ++import java.security.interfaces.RSAPrivateCrtKey; ++import java.security.interfaces.RSAPrivateKey; ++import java.security.interfaces.RSAPublicKey; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.InvalidParameterSpecException; ++import java.security.spec.MGF1ParameterSpec; ++import java.util.Arrays; ++import java.util.Locale; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++ ++/** ++ * RSA cipher implementation. Supports RSA en/decryption and signing/verifying ++ * using both PKCS#1 v1.5 and OAEP (v2.2) paddings and without padding (raw RSA). ++ * Note that raw RSA is supported mostly for completeness and should only be ++ * used in rare cases. ++ *

++ * 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..51d7a95eb +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.rsa.*; ++import sun.security.rsa.RSAUtil.KeyType; ++import sun.security.util.SecurityProviderConstants; ++ ++import java.math.BigInteger; ++import java.security.*; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.RSAKeyGenParameterSpec; ++ ++public abstract class KAERSAKeyPairGenerator extends KeyPairGeneratorSpi { ++ // public exponent to use ++ private BigInteger publicExponent; ++ ++ // size of the key to generate, >= KAERSAKeyFactory.MIN_MODLEN ++ private int keySize; ++ ++ private final KeyType type; ++ ++ private AlgorithmParameterSpec keyParams; ++ ++ ++ KAERSAKeyPairGenerator(KeyType keyType, int keySize) { ++ this.type = keyType; ++ initialize(keySize, null); ++ } ++ ++ // initialize the generator. See JCA doc ++ @Override ++ public void initialize(int keySize, SecureRandom random) { ++ try { ++ initialize(new RSAKeyGenParameterSpec(keySize, ++ RSAKeyGenParameterSpec.F4), null); ++ } catch (InvalidAlgorithmParameterException iape) { ++ throw new InvalidParameterException(iape.getMessage()); ++ } ++ } ++ ++ // second initialize method. See JCA doc ++ @Override ++ public void initialize(AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidAlgorithmParameterException { ++ if (!(params instanceof RSAKeyGenParameterSpec)) { ++ throw new InvalidAlgorithmParameterException ++ ("Params must be instance of RSAKeyGenParameterSpec"); ++ } ++ ++ RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) params; ++ int tmpKeySize = rsaSpec.getKeysize(); ++ BigInteger tmpPublicExponent = rsaSpec.getPublicExponent(); ++ keyParams = rsaSpec.getKeyParams(); ++ ++ if (tmpPublicExponent == null) { ++ tmpPublicExponent = RSAKeyGenParameterSpec.F4; ++ } else { ++ if (tmpPublicExponent.compareTo(RSAKeyGenParameterSpec.F0) < 0) { ++ throw new InvalidAlgorithmParameterException ++ ("Public exponent must be 3 or larger"); ++ } ++ if (tmpPublicExponent.bitLength() > tmpKeySize) { ++ throw new InvalidAlgorithmParameterException ++ ("Public exponent must be smaller than key size"); ++ } ++ } ++ ++ // do not allow unreasonably large key sizes, probably user error ++ try { ++ RSAKeyFactory.checkKeyLengths(tmpKeySize, tmpPublicExponent, ++ 512, 64 * 1024); ++ } catch (InvalidKeyException e) { ++ throw new InvalidAlgorithmParameterException( ++ "Invalid key sizes", e); ++ } ++ ++ this.keySize = tmpKeySize; ++ this.publicExponent = tmpPublicExponent; ++ } ++ ++ // generate the keypair. See JCA doc ++ @Override ++ public KeyPair generateKeyPair() { ++ // get the KAE RSA key Parameters ++ byte[][] params = nativeGenerateKeyPair(keySize, publicExponent.toByteArray()); ++ ++ try { ++ // check KAE RSA key Parameters ++ checkKAERSAParams(params); ++ ++ BigInteger n = new BigInteger(params[0]); ++ BigInteger e = new BigInteger(params[1]); ++ BigInteger d = new BigInteger(params[2]); ++ BigInteger p = new BigInteger(params[3]); ++ BigInteger q = new BigInteger(params[4]); ++ BigInteger pe = new BigInteger(params[5]); ++ BigInteger qe = new BigInteger(params[6]); ++ BigInteger coeff = new BigInteger(params[7]); ++ ++ // public key ++ PublicKey publicKey = RSAPublicKeyImpl.newKey(type, keyParams, n, e); ++ ++ // private key ++ PrivateKey privateKey = RSAPrivateCrtKeyImpl.newKey(type, keyParams, n, e, d, p, q, pe, qe, coeff); ++ ++ return new KeyPair(publicKey, privateKey); ++ } catch (InvalidKeyException ex) { ++ throw new RuntimeException(ex); ++ } ++ } ++ ++ // check KAE RSA key Parameters ++ private void checkKAERSAParams(byte[][] params) throws InvalidKeyException { ++ if (params == null || params.length < 8) { ++ throw new InvalidKeyException("Invalid KAE RSA key Parameter"); ++ } ++ ++ for (int i = 0; i < params.length; i++) { ++ if (params[i] == null) { ++ throw new InvalidKeyException("Invalid KAE RSA key Parameter , params[" + i + "] = null"); ++ } ++ } ++ } ++ ++ public static final class Legacy extends KAERSAKeyPairGenerator { ++ public Legacy() { ++ super(KeyType.RSA, SecurityProviderConstants.DEF_RSA_KEY_SIZE); ++ } ++ } ++ ++ public static final class PSS extends KAERSAKeyPairGenerator { ++ public PSS() { ++ super(KeyType.PSS, SecurityProviderConstants.DEF_RSASSA_PSS_KEY_SIZE); ++ } ++ } ++ ++ // generate key pair ++ static native byte[][] nativeGenerateKeyPair(int keySize, byte[] publicExponent) throws RuntimeException; ++} +diff --git a/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..65c4e0382 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPSSSignature.java +@@ -0,0 +1,713 @@ ++/* ++ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.security.openssl; ++ ++import java.io.IOException; ++import java.lang.reflect.Constructor; ++import java.lang.reflect.InvocationTargetException; ++import java.lang.reflect.Method; ++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") ++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 Method generateAndXorMethod; ++ ++ private static Constructor mgf1Constructor; ++ ++ private static final byte[] EIGHT_BYTES_OF_ZEROS = new byte[8]; ++ ++ private static Exception exception; ++ ++ static { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ @Override ++ public Void run() { ++ try { ++ Class mgf1Class = Class.forName("sun.security.rsa.MGF1"); ++ generateAndXorMethod = mgf1Class.getDeclaredMethod("generateAndXor", ++ byte[].class, int.class, int.class, int.class, byte[].class, int.class); ++ generateAndXorMethod.setAccessible(true); ++ mgf1Constructor = mgf1Class.getDeclaredConstructor(String.class); ++ mgf1Constructor.setAccessible(true); ++ } catch (ClassNotFoundException | NoSuchMethodException e) { ++ exception = e; ++ } ++ return null; ++ } ++ }); ++ } ++ ++ // 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() throws SignatureException { ++ if (exception != null) { ++ throw new SignatureException(exception.getMessage()); ++ } ++ 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 ++ Object mgf1 = mgf1Constructor.newInstance(mgfDigestAlgo); ++ generateAndXorMethod.invoke(mgf1, 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 (IllegalAccessException | InstantiationException | InvocationTargetException e) { ++ 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 { ++ Object mgf1; ++ try { ++ mgf1 = mgf1Constructor.newInstance(mgfDigestAlgo); ++ generateAndXorMethod.invoke(mgf1, em, dbLen, hLen, dbLen, em, 0); ++ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { ++ 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..022271d94 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAERSAPaddingType.java +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.util.Arrays; ++import java.util.Collections; ++import java.util.HashSet; ++import java.util.Set; ++ ++enum KAERSAPaddingType { ++ // raw RSA ++ PKCS1Padding(1, "PKCS1Padding"), ++ ++ // PKCS#1 v1.5 RSA ++ NoPadding(3, "NoPadding"), ++ ++ // PKCS#2 v2.2 OAEP with MGF1 ++ OAEP(4, "OAEP", new HashSet<>( ++ Arrays.asList( ++ "OAEPPADDING", ++ "OAEPWITHMD5ANDMGF1PADDING", ++ "OAEPWITHSHA1ANDMGF1PADDING", ++ "OAEPWITHMD5ANDMGF1PADDING", ++ "OAEPWITHSHA1ANDMGF1PADDING", ++ "OAEPWITHSHA-1ANDMGF1PADDING", ++ "OAEPWITHSHA-224ANDMGF1PADDING", ++ "OAEPWITHSHA-256ANDMGF1PADDING", ++ "OAEPWITHSHA-384ANDMGF1PADDING", ++ "OAEPWITHSHA-512ANDMGF1PADDING", ++ "OAEPWITHSHA-512/224ANDMGF1PADDING", ++ "OAEPWITHSHA-512/256ANDMGF1PADDING")) ++ ), ++ ++ // 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..84893445d +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.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..8f256ffe5 +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import javax.crypto.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..b189bea3a +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESM4Cipher.java +@@ -0,0 +1,188 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.security.InvalidAlgorithmParameterException; ++import java.security.InvalidKeyException; ++import java.security.NoSuchAlgorithmException; ++import java.security.Key; ++import java.util.Locale; ++ ++import javax.crypto.NoSuchPaddingException; ++ ++/* ++ * 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 { ++ ++ 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); ++ } ++ } ++ ++ protected void checkIvBytes(byte[] ivBytes) throws InvalidAlgorithmParameterException { ++ if (ivBytes == null) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: iv is null "); ++ } ++ if (mode == Mode.CTR) { ++ if (ivBytes.length < 8) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: CTR mode requires IV of at least: 8 bytes."); ++ } ++ return; ++ } ++ if (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/KAESymmetricCipherBase.java b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESymmetricCipherBase.java +new file mode 100644 +index 000000000..b2ff94754 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/classes/org/openeuler/security/openssl/KAESymmetricCipherBase.java +@@ -0,0 +1,615 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.jca.JCAUtil; ++ ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.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"); ++ } ++ } ++ } ++} ++ +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..f7093a1f4 +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import javax.crypto.Cipher; ++import javax.crypto.SecretKey; ++import javax.crypto.spec.SecretKeySpec; ++import java.security.*; ++import java.security.spec.InvalidKeySpecException; ++import java.security.spec.PKCS8EncodedKeySpec; ++import java.security.spec.X509EncodedKeySpec; ++import java.util.*; ++ ++class KAEUtils { ++ enum MessageDigestType { ++ MD2("MD2", "md2", 16), ++ MD5("MD5", "md5", 16), ++ SHA1("SHA-1", "sha1", 20, ++ new HashSet<>(Arrays.asList("SHA1", "1.3.14.3.2.26", "OID.1.3.14.3.2.26"))), ++ SHA224("SHA-224", "sha224", 28, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.4", "OID.2.16.840.1.101.3.4.2.4"))), ++ SHA256("SHA-256", "sha256", 32, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1"))), ++ SHA384("SHA-384", "sha384", 48, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2"))), ++ SHA512("SHA-512", "sha512", 64, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3"))), ++ SHA512_224("SHA-512/224", "sha512-224", 28, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.5", "OID.2.16.840.1.101.3.4.2.5"))), ++ SHA_512_256("SHA-512/256", "sha512-256", 32, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.6", "OID.2.16.840.1.101.3.4.2.6"))); ++ ++ final String digestName; ++ final String kaeDigestName; ++ final int digestLen; ++ final Set 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..a48969669 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/conf/security/kaeprovider.conf +@@ -0,0 +1,19 @@ ++# ++# This is the config file for KAEProvider ++# ++# 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 ++ ++# enable KAEProvider log setting ++# kae.log=true +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..fa616ae5f +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_cipher_rsa.c +@@ -0,0 +1,467 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include ++#include ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "org_openeuler_security_openssl_KAERSACipher.h" ++ ++static ENGINE* kaeEngine = NULL; ++ ++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* ++ size_t outLen = 0; ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : 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; ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : 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; ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : 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); ++ } ++} +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..f0e7b0be4 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_digest.c +@@ -0,0 +1,235 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#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; ++ static 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); ++ if ((strcasecmp(algo_utf, "md5") == 0) || (strcasecmp(algo_utf, "sm3") == 0)) { ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : kaeEngine; ++ } else { ++ kaeEngine = NULL; ++ } ++ 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"); ++} +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..f684f6eea +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.c +@@ -0,0 +1,134 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include ++#include "kae_log.h" ++#include "kae_exception.h" ++ ++void KAE_ThrowByName(JNIEnv* env, const char* name, const char* msg) { ++ jclass cls = (*env)->FindClass(env, name); ++ if (cls != 0) { ++ (*env)->ThrowNew(env, cls, msg); ++ (*env)->DeleteLocalRef(env, cls); ++ } ++} ++ ++void KAE_ThrowOOMException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/OutOfMemoryError", msg); ++} ++ ++void KAE_ThrowNullPointerException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/NullPointerException", msg); ++} ++ ++void KAE_ThrowArrayIndexOutOfBoundsException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/ArrayIndexOutOfBoundsException", msg); ++} ++ ++void KAE_ThrowEvpException(JNIEnv* env, int reason, const char* msg, void (* defaultException)(JNIEnv*, const char*)) { ++ switch (reason) { ++ case EVP_R_UNSUPPORTED_ALGORITHM: ++ KAE_ThrowByName(env, "java/security/NoSuchAlgorithmException", msg); ++ break; ++ case EVP_R_MISSING_PARAMETERS: ++ KAE_ThrowByName(env, "java/security/InvalidKeyException", msg); ++ break; ++ case EVP_R_BAD_DECRYPT: ++ 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 reason = ERR_GET_REASON(err); ++ KAE_TRACE("OpenSSL error in %s: err=%lx, lib=%x, reason=%x, file=%s, line=%d, estring=%s, data=%s", msg, err, ++ lib, reason, file, line, estring, (flags & ERR_TXT_STRING) ? data : "(no data)"); ++ ++ switch (lib) { ++ case ERR_LIB_EVP: ++ case ERR_LIB_RSA: ++ KAE_ThrowEvpException(env, reason, estring, defaultException); ++ break; ++ default: ++ defaultException(env, estring); ++ break; ++ } ++ } ++ ++ 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..532953995 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_exception.h +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#ifndef KAE_EXCEPTION_H ++#define KAE_EXCEPTION_H ++ ++#include ++ ++/* 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..7b28fa1fa +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_hmac.c +@@ -0,0 +1,203 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#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; ++ ++ const char* algo = (*env)->GetStringUTFChars(env, algoStr, 0); ++ md = EVPGetDigestByName(env, algo); ++ (*env)->ReleaseStringUTFChars(env, algoStr, algo); ++ if (md == NULL) { ++ KAE_ThrowRuntimeException(env, "algorithm unsupport"); ++ return 0; ++ } ++ ++ // get secret-key ++ key_buffer = malloc(key_len); ++ if (key_buffer == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ return 0; ++ } ++ (*env)->GetByteArrayRegion(env, key, 0, key_len, key_buffer); ++ ++ // create a hmac context ++ ctx = HMAC_CTX_new(); ++ if (ctx == NULL) { ++ KAE_ThrowRuntimeException(env, "Hmac_CTX_new invoked failed"); ++ goto cleanup; ++ } ++ ++ // init hmac context with sc_key and evp_md ++ int result_code = HMAC_Init_ex(ctx, key_buffer, key_len, md, NULL); ++ if (result_code == 0) { ++ KAE_ThrowRuntimeException(env, "Hmac_Init_ex invoked failed"); ++ goto 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", 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 = %d", 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..b1c272411 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_dh.c +@@ -0,0 +1,139 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#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; ++ static ENGINE* kaeEngine = NULL; ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : 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_nativeGenerateSecret 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) ++ free(secret); ++ if (computeKeyRetBn != NULL) ++ BN_free(computeKeyRetBn); ++ ++ return retByteArray; ++} +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..5fc4d68fd +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keyagreement_ecdh.c +@@ -0,0 +1,115 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#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) ++{ ++ 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) { ++ 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); ++ 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. ++ int 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); ++ return javaBytes; ++ ++cleanup: ++ FreeGenerateSecretParam(s, wX, wY, pub, eckey, group, shareKey); ++ return NULL; ++} +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..54dc07edd +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_dh.c +@@ -0,0 +1,132 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#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; ++ static ENGINE* kaeEngine = NULL; ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : 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; ++} +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..5b387d708 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_ec.c +@@ -0,0 +1,508 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#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 = NULL; ++ jobjectArray params = NULL; ++ ++ byteArrayClass = (*env)->FindClass(env, "[B"); ++ 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; ++} +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..d4c9d6ac4 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c +@@ -0,0 +1,167 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include ++#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 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) { ++ static ENGINE* kaeEngine = NULL; ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : 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 ++ for (RSAParamIndex 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; ++} +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..d8d9c7b32 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_log.h +@@ -0,0 +1,33 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#ifndef KAE_LOG_H ++#define KAE_LOG_H ++ ++#ifdef KAE_DEBUG ++#define KAE_TRACE(...) { fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); } ++#else ++#define KAE_TRACE(...) ++#endif ++ ++#endif +diff --git a/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..aa46e737e +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_provider.c +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include ++#include ++#include "kae_exception.h" ++#include "kae_util.h" ++#include "org_openeuler_security_openssl_KAEProvider.h" ++ ++/* ++ * 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) { ++ SSL_load_error_strings(); ++ ERR_load_BIO_strings(); ++ OpenSSL_add_all_algorithms(); ++ ++ // check if KaeEngine holder is already set ++ ENGINE* e = GetKaeEngine(); ++ if (e != NULL) { ++ ENGINE_free(e); ++ e = NULL; ++ } ++ ++ // determine whether KAE is loaded successfully ++ e = ENGINE_by_id("kae"); ++ if (e == NULL) { ++ ERR_clear_error(); ++ KAE_ThrowRuntimeException(env, "kae engine not found"); ++ return; ++ } ++ SetKaeEngine(e); ++} +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..e81dc1406 +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_signature_rsa.c +@@ -0,0 +1,363 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++#include ++#include ++#include ++#include ++#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; ++ 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 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; ++ 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 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..c92574fbd +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_symmetric_cipher.c +@@ -0,0 +1,409 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#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) ++{ ++ if (ivBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, iv, ivBytes, 0); ++ } ++ if (keyBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, key, keyBytes, 0); ++ } ++} ++ ++/* ++ * 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; ++ static ENGINE* kaeEngine = NULL; ++ ++ const char* algo = (*env)->GetStringUTFChars(env, cipherType, 0); ++ if (StartsWith("aes", algo)) { ++ cipher = EVPGetAesCipherByName(env, algo); ++ kaeEngine = NULL; ++ } else { ++ cipher = EVPGetSm4CipherByName(env, algo); ++ kaeEngine = (kaeEngine == NULL) ? GetKaeEngine() : 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); ++ return (jlong)ctx; ++ ++cleanup: ++ if (ctx != NULL) { ++ EVP_CIPHER_CTX_free(ctx); ++ } ++ FreeMemoryFromInit(env, iv, ivBytes, key, keyBytes); ++ 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..7ac3cbe8d +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.c +@@ -0,0 +1,111 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#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; ++} +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..13bd5976d +--- /dev/null ++++ b/src/jdk.crypto.kaeprovider/linux/native/libj2kae/org/openeuler/security/openssl/kae_util.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#ifndef KAE_UTIL_H ++#define KAE_UTIL_H ++ ++#include ++#include ++ ++/* 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 SetKaeEngine(ENGINE* engine); ++ ++ENGINE* GetKaeEngine(); ++ ++#endif +diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups +index 694d078a6..8d171ed04 100644 +--- a/test/jdk/TEST.groups ++++ b/test/jdk/TEST.groups +@@ -235,6 +235,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 8f705abd7..9968dea56 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; +@@ -52,7 +53,14 @@ public class KeyAgreementTest { + String kaAlgo = args[0]; + String kpgAlgo = args[1]; + String provider = args[2]; +- 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); +@@ -87,6 +95,7 @@ public class KeyAgreementTest { + "X9.62 c2tnb239v1", "X9.62 c2tnb239v2", "X9.62 c2tnb239v3", + "X9.62 c2tnb359v1", "X9.62 c2tnb431r1" + ), ++ KAEECDH("secp224r1", "secp256r1", "secp384r1", "secp521r1"), + XDH("X25519", "X448"), + // There is no curve for DiffieHellman + DiffieHellman(new String[]{}); +@@ -98,6 +107,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/DHTest.java b/test/jdk/org/openeuler/security/openssl/DHTest.java +new file mode 100644 +index 000000000..6eb5e7c96 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/DHTest.java +@@ -0,0 +1,130 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++ ++import java.io.Serializable; ++import java.math.BigInteger; ++import java.security.*; ++import java.util.Arrays; ++import java.util.Date; ++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 ++ * @run main DHTest ++ */ ++ ++final class DHTest implements Serializable { ++ private static int bitLength = 8192; ++ private static BigInteger g512; ++ private static BigInteger p512; ++ Throwable t = null; ++ ++ private static volatile Provider sunJceProvider; ++ private static volatile Provider kaeProvider; ++ Date d = new Date(); ++ ++ 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"); ++ ++ DHTest.bitLength = 0; ++ ++ 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!"); ++ } ++ ++ } ++ ++} +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..9c836495b +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/ECDHTest.java +@@ -0,0 +1,117 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++import sun.security.ec.ECPrivateKeyImpl; ++import sun.security.ec.ECPublicKeyImpl; ++ ++import javax.crypto.KeyAgreement; ++import java.lang.reflect.Constructor; ++import java.lang.reflect.InvocationTargetException; ++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; ++ ++/** ++ * @test ++ * @summary Basic test for ECDH ++ * @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); ++ } ++ ++ Class priKeyImpl = Class.forName("sun.security.ec.ECPrivateKeyImpl"); ++ Constructor conPriKeyImpl = priKeyImpl.getDeclaredConstructor(BigInteger.class, ECParameterSpec.class); ++ conPriKeyImpl.setAccessible(true); ++ ECPrivateKeyImpl ecPrivKey = (ECPrivateKeyImpl) conPriKeyImpl.newInstance( ++ new BigInteger("20135071615800221517902437867016717688420688735490569283842831828983"), PARAMS); ++ ++ ECPoint ecPoint = new ECPoint(new BigInteger("9490267631555585552004372465967099662885480699902812460349461311384"), ++ new BigInteger("1974573604976093871117393045089050409882519645527397292712281520811")); ++ Class pubKeyImpl = Class.forName("sun.security.ec.ECPublicKeyImpl"); ++ Constructor conPubKeyImpl = pubKeyImpl.getDeclaredConstructor(ECPoint.class, ECParameterSpec.class); ++ conPubKeyImpl.setAccessible(true); ++ ECPublicKeyImpl ecPublicKey = (ECPublicKeyImpl) conPubKeyImpl.newInstance(ecPoint, PARAMS); ++ ++ 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"); ++ } ++ } ++} +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..181f708ff +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/SM3Test.java +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++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 ++ * @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..4c28dc5b6 +--- /dev/null ++++ b/test/jdk/org/openeuler/security/openssl/SM4Test.java +@@ -0,0 +1,95 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.openeuler.security.openssl.KAEProvider; ++import java.nio.charset.StandardCharsets; ++import java.util.Arrays; ++import java.security.NoSuchAlgorithmException; ++import java.security.Security; ++import javax.crypto.Cipher; ++import javax.crypto.spec.IvParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++ ++/** ++ * @test ++ * @summary Basic test for sm4 ++ * @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}); ++ } ++ ++ 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); ++ } ++ } ++} +diff --git a/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java b/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java +index aee691016..6433416de 100644 +--- a/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java ++++ b/test/jdk/sun/security/jca/PreferredProviderNegativeTest.java +@@ -110,6 +110,8 @@ public class PreferredProviderNegativeTest { + // If OS is solaris, expect OracleUcrypto, otherwise SunJCE + if (System.getProperty("os.name").toLowerCase().contains("sun")) { + expected = "OracleUcrypto"; ++ } else if (Security.getProperty("security.provider.1").equals("KAEProvider")) { ++ expected = "KAEProvider"; + } else { + expected = "SunJCE"; + } +diff --git a/test/jdk/sun/security/krb5/auto/BasicProc.java b/test/jdk/sun/security/krb5/auto/BasicProc.java +index 152db351c..38a2cd4e8 100644 +--- a/test/jdk/sun/security/krb5/auto/BasicProc.java ++++ b/test/jdk/sun/security/krb5/auto/BasicProc.java +@@ -297,7 +297,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 c1be3a50e..8bf84f062 100644 +--- a/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java ++++ b/test/jdk/sun/security/ssl/CipherSuite/DisabledCurve.java +@@ -89,6 +89,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]); + if (disabledName.equals("")) { +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..e075bb039 +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Fork; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import java.security.InvalidKeyException; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.NoSuchAlgorithmException; ++import java.security.Provider; ++import java.security.Security; ++import java.util.concurrent.TimeUnit; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import javax.crypto.NoSuchPaddingException; ++import javax.crypto.spec.SecretKeySpec; ++ ++@Warmup(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS) ++public class AESBenchmark extends BenchmarkBase { ++ ++ @Param({"AES/ECB/PKCS5Padding", "AES/ECB/NoPadding", "AES/CBC/NoPadding", "AES/CBC/PKCS5Padding", "AES/CTR/NoPadding"}) ++ private String algorithm; ++ ++ @Param({"128", "192", "256"}) ++ private int keyLength; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) ++ private int dataSize; ++ ++ private byte[][] encryptedData; ++ private Cipher encryptCipher; ++ private Cipher decryptCipher; ++ ++ @Setup ++ public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, ++ InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { ++ setupProvider(); ++ ++ byte[] keystring = fillSecureRandom(new byte[keyLength / 8]); ++ SecretKeySpec ks = new SecretKeySpec(keystring, "AES"); ++ ++ encryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks); ++ decryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ ++ data = fillRandom(new byte[SET_SIZE][dataSize]); ++ encryptedData = fillEncrypted(data, encryptCipher); ++ } ++ ++ @Benchmark ++ public byte[] encrypt() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return encryptCipher.doFinal(d); ++ } ++ ++ @Benchmark ++ @Fork(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..92eb6a592 +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.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..9aef6dc62 +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openeuler.security.openssl.KAEProvider; ++import org.openjdk.jmh.annotations.BenchmarkMode; ++import org.openjdk.jmh.annotations.Fork; ++import org.openjdk.jmh.annotations.Measurement; ++import org.openjdk.jmh.annotations.Mode; ++import org.openjdk.jmh.annotations.OutputTimeUnit; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Scope; ++import org.openjdk.jmh.annotations.Setup; ++import org.openjdk.jmh.annotations.State; ++import org.openjdk.jmh.annotations.Threads; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import java.security.Provider; ++import java.security.SecureRandom; ++import java.security.Security; ++import java.util.Random; ++import java.util.concurrent.TimeUnit; ++ ++@BenchmarkMode(Mode.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..c204f4ceb +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.bench.security.openssl; ++ ++import 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..f1cd4b641 +--- /dev/null ++++ b/test/micro/org/openeuler/bench/security/openssl/RSASignatureBenchmark.java +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (c) 2021, 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..664650374 +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openeuler.security.openssl.KAEProvider; ++import org.openjdk.jmh.annotations.BenchmarkMode; ++import org.openjdk.jmh.annotations.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..e62e68c4c +--- /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) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openeuler.security.openssl.KAEProvider; ++import org.openjdk.jmh.annotations.BenchmarkMode; ++import org.openjdk.jmh.annotations.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.22.0 + diff --git a/PS-introduce-UsePSRelaxedForwardee-to-enable-using-r.patch b/PS-introduce-UsePSRelaxedForwardee-to-enable-using-r.patch new file mode 100755 index 0000000000000000000000000000000000000000..e510108be4557831636286a330f9a3735368be9f --- /dev/null +++ b/PS-introduce-UsePSRelaxedForwardee-to-enable-using-r.patch @@ -0,0 +1,49 @@ +diff --git a/src/hotspot/share/gc/parallel/parallel_globals.hpp b/src/hotspot/share/gc/parallel/parallel_globals.hpp +index 5461bf04f..75ee84d4f 100644 +--- a/src/hotspot/share/gc/parallel/parallel_globals.hpp ++++ b/src/hotspot/share/gc/parallel/parallel_globals.hpp +@@ -78,6 +78,10 @@ + "Delay in scheduling GC workers (in milliseconds)") \ + \ + product(bool, PSChunkLargeArrays, true, \ +- "Process large arrays in chunks") ++ "Process large arrays in chunks") \ ++ \ ++ experimental(bool, UsePSRelaxedForwardee, false, \ ++ "Use the UsePSRelaxedForwardee to enable ps use relaxed" \ ++ "during young gc copying object") + + #endif // SHARE_GC_PARALLEL_PARALLEL_GLOBALS_HPP +diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +index cc5a4aa98..9bf45f82b 100644 +--- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp ++++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +@@ -218,8 +218,15 @@ inline oop PSPromotionManager::copy_to_survivor_space(oop o) { + Copy::aligned_disjoint_words((HeapWord*)o, (HeapWord*)new_obj, new_obj_size); + + // Now we have to CAS in the header. +- // Make copy visible to threads reading the forwardee. +- if (o->cas_forward_to(new_obj, test_mark, o->klass()->oop_is_gc_leaf()? memory_order_relaxed : memory_order_release)) { ++ // When use relaxed CAS, cann't gurantee new obj visible for other threads accessing forwardee. ++ // As oop_is_gc_leaf is verified for long time without problems, for gc leaf's benefit, we add ++ // UsePSRelaxedForwardee to enable using relaxed CAS rather than delete oop_is_gc_leaf condition directly. ++#ifdef PRODUCT ++ if (o->cas_forward_to(new_obj, test_mark, (UsePSRelaxedForwardee || o->klass()->oop_is_gc_leaf()) ? ++ memory_order_relaxed : memory_order_release)) { ++#else ++ if (o->cas_forward_to(new_obj, test_mark, memory_order_release)) { ++#endif + // We won any races, we "own" this object. + assert(new_obj == o->forwardee(), "Sanity"); + +@@ -275,6 +282,10 @@ inline oop PSPromotionManager::copy_to_survivor_space(oop o) { + + // This code must come after the CAS test, or it will print incorrect + // information. ++ // When UsePSRelaxedForwardee is true or object o is gc leaf, CAS failed threads can't access forwardee's content, ++ // as relaxed CAS cann't gurantee new obj's content visible for these CAS failed threads.The below log output is ++ // dangerous.So we just support UsePSRelaxedForwardee and gc leaf in product. ++ // Everywhere access forwardee's content must be careful. + log_develop_trace(gc, scavenge)("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", + should_scavenge(&new_obj) ? "copying" : "tenuring", + new_obj->klass()->internal_name(), p2i((void *)o), p2i((void *)new_obj), new_obj->size()); diff --git a/Update-algorithm-annotations-for-fill_words.patch b/Update-algorithm-annotations-for-fill_words.patch new file mode 100755 index 0000000000000000000000000000000000000000..35abaf78ecc98ad88df74e311f24f794dd2b3a93 --- /dev/null +++ b/Update-algorithm-annotations-for-fill_words.patch @@ -0,0 +1,65 @@ +From 861eff79eafc35ac88bbeb1b0edb7269c54ac807 Mon Sep 17 00:00:00 2001 +From: miaozhuojun +Date: Wed, 4 Aug 2021 15:22:25 +0800 +Subject: [PATCH 1/8] Update algorithm annotations for fill_words + +Summary: : update algorithm annotations for fill_words +LLT: NA +Patch Type: huawei +Bug url: NA +--- + .../cpu/aarch64/macroAssembler_aarch64.cpp | 28 ++++++++++++++----- + 1 file changed, 21 insertions(+), 7 deletions(-) + +diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +index 60dc92953..1401b8627 100644 +--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp ++++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +@@ -5658,23 +5658,37 @@ void MacroAssembler::fill_words(Register base, Register cnt, Register value) + { + // Algorithm: + // +-// scratch1 = cnt & 7; ++// if (cnt == 0) { ++// return; ++// } ++// if ((p & 8) != 0) { ++// *p++ = v; ++// } ++// ++// scratch1 = cnt & 14; + // cnt -= scratch1; + // p += scratch1; +-// switch (scratch1) { ++// switch (scratch1 / 2) { + // do { +-// cnt -= 8; +-// p[-8] = v; ++// cnt -= 16; ++// p[-16] = v; ++// p[-15] = v; + // case 7: +-// p[-7] = v; ++// p[-14] = v; ++// p[-13] = v; + // case 6: +-// p[-6] = v; ++// p[-12] = v; ++// p[-11] = v; + // // ... + // case 1: ++// p[-2] = v; + // p[-1] = v; + // case 0: +-// p += 8; ++// p += 16; + // } while (cnt); ++// } ++// if ((cnt & 1) == 1) { ++// *p++ = v; + // } + + assert_different_registers(base, cnt, value, rscratch1, rscratch2); +-- +2.22.0 + diff --git a/create-jfr-dump-file-with-pid-or-timestamp-if-specif.patch b/create-jfr-dump-file-with-pid-or-timestamp-if-specif.patch new file mode 100755 index 0000000000000000000000000000000000000000..834dec4068a9baa5b6ef563be0c1af80f97f78f5 --- /dev/null +++ b/create-jfr-dump-file-with-pid-or-timestamp-if-specif.patch @@ -0,0 +1,111 @@ +From fcf556744f9597ddd58c8103bf49bc992401feca Mon Sep 17 00:00:00 2001 +From: hubodao +Date: Sat, 11 Sep 2021 09:47:21 +0800 +Subject: [PATCH 4/8] create jfr dump file with pid or timestamp if specified + +Summary: : create jfr dump file with pid or timestamp if specified +LLT: NA +Patch Type: huawei +Bug url: NA +--- + src/hotspot/share/jfr/dcmd/jfrDcmds.cpp | 16 ++++++++++++++-- + src/hotspot/share/utilities/ostream.cpp | 2 +- + src/hotspot/share/utilities/ostream.hpp | 2 +- + .../jdk/jfr/jcmd/TestJcmdDumpWithFileName.java | 16 ++++++++++++++++ + 4 files changed, 32 insertions(+), 4 deletions(-) + +diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp +index 4aa5c56f3..b1c5df029 100644 +--- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp ++++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp +@@ -230,7 +230,13 @@ void JfrDumpFlightRecordingDCmd::execute(DCmdSource source, TRAPS) { + + jstring filepath = NULL; + if (_filename.is_set() && _filename.value() != NULL) { +- filepath = JfrJavaSupport::new_string(_filename.value(), CHECK); ++ const char* extended_path = make_log_name(_filename.value(), NULL); ++ if (extended_path != NULL) { ++ filepath = JfrJavaSupport::new_string(extended_path, CHECK); ++ FREE_C_HEAP_ARRAY(char, extended_path); ++ } else { ++ filepath = JfrJavaSupport::new_string(_filename.value(), CHECK); ++ } + } + + jobject maxage = NULL; +@@ -398,7 +404,13 @@ void JfrStartFlightRecordingDCmd::execute(DCmdSource source, TRAPS) { + + jstring filename = NULL; + if (_filename.is_set() && _filename.value() != NULL) { +- filename = JfrJavaSupport::new_string(_filename.value(), CHECK); ++ const char *dumpPath = make_log_name(_filename.value(), NULL); ++ if (dumpPath != NULL) { ++ filename = JfrJavaSupport::new_string(dumpPath, CHECK); ++ FREE_C_HEAP_ARRAY(char, dumpPath); ++ } else { ++ filename = JfrJavaSupport::new_string(_filename.value(), CHECK); ++ } + } + + jobject maxage = NULL; +diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp +index eb8ee4de1..0aabe8e8f 100644 +--- a/src/hotspot/share/utilities/ostream.cpp ++++ b/src/hotspot/share/utilities/ostream.cpp +@@ -528,7 +528,7 @@ static const char* make_log_name_internal(const char* log_name, const char* forc + // -XX:DumpLoadedClassList= + // in log_name, %p => pid1234 and + // %t => YYYY-MM-DD_HH-MM-SS +-static const char* make_log_name(const char* log_name, const char* force_directory) { ++const char* make_log_name(const char* log_name, const char* force_directory) { + char timestr[32]; + get_datetime_string(timestr, sizeof(timestr)); + return make_log_name_internal(log_name, force_directory, os::current_process_id(), +diff --git a/src/hotspot/share/utilities/ostream.hpp b/src/hotspot/share/utilities/ostream.hpp +index fe38c2f3e..e2a8a621c 100644 +--- a/src/hotspot/share/utilities/ostream.hpp ++++ b/src/hotspot/share/utilities/ostream.hpp +@@ -309,5 +309,5 @@ class networkStream : public bufferedStream { + }; + + #endif +- ++const char* make_log_name(const char* log_name, const char* force_directory); + #endif // SHARE_VM_UTILITIES_OSTREAM_HPP +diff --git a/test/jdk/jdk/jfr/jcmd/TestJcmdDumpWithFileName.java b/test/jdk/jdk/jfr/jcmd/TestJcmdDumpWithFileName.java +index 691e53174..cead3a0e7 100644 +--- a/test/jdk/jdk/jfr/jcmd/TestJcmdDumpWithFileName.java ++++ b/test/jdk/jdk/jfr/jcmd/TestJcmdDumpWithFileName.java +@@ -47,6 +47,7 @@ public class TestJcmdDumpWithFileName { + testDumpAll(); + testDumpNamed(); + testDumpNamedWithFilename(); ++ testDumpNamedWithFilenameExpansion(); + } + + private static void testDumpAll() throws Exception { +@@ -96,6 +97,21 @@ public class TestJcmdDumpWithFileName { + cleanup(); + } + ++ private static void testDumpNamedWithFilenameExpansion() throws Exception { ++ long pid = ProcessHandle.current().pid(); ++ Path dumpPath = Path.of("dumpPath-%p-%t.jfr").toAbsolutePath(); ++ try (Recording r = new Recording()) { ++ r.setName("testDumpNamedWithFilenameExpansion"); ++ r.setDestination(dumpPath); ++ r.start(); ++ JcmdHelper.jcmd("JFR.dump", "name=testDumpNamedWithFilenameExpansion", "filename=" + dumpPath.toString()); ++ Stream stream = Files.find(Path.of("."), 1, (s, a) -> s.toString() ++ .matches("^.*dumpPath-pid" + pid + ".\\d{4}.\\d{2}.\\d{2}.\\d{2}.\\d{2}.\\d{2}" + ".jfr") && (a.size() > 0L)); ++ Asserts.assertTrue(stream.findAny().isPresent()); ++ } ++ cleanup(); ++ } ++ + private static boolean namedFile(Path dumpFile) throws IOException { + return Files.exists(dumpFile) && (Files.size(dumpFile) > 0); + } +-- +2.22.0 + diff --git a/enhance-the-TimeZone-s-path-solution-on-Euler.patch b/enhance-the-TimeZone-s-path-solution-on-Euler.patch new file mode 100755 index 0000000000000000000000000000000000000000..0bf3b9ce1bac274f2faadd8a5fd827fa70bb669c --- /dev/null +++ b/enhance-the-TimeZone-s-path-solution-on-Euler.patch @@ -0,0 +1,71 @@ +From f7e762f525098e19b0f0e9ea8dc2c4a31cae607a Mon Sep 17 00:00:00 2001 +From: s00478819 +Date: Sat, 11 Sep 2021 11:42:19 +0800 +Subject: [PATCH 6/8] enhance the TimeZone's path solution on Euler + +Summary: : enhance the TimeZone's path solution on Euler +LLT: NA +Patch Type: huawei +Bug url: NA +--- + .../unix/native/libjava/TimeZone_md.c | 33 ++++++++++++++++++- + 1 file changed, 32 insertions(+), 1 deletion(-) + +diff --git a/src/java.base/unix/native/libjava/TimeZone_md.c b/src/java.base/unix/native/libjava/TimeZone_md.c +index bb3ba99d5..0780c3601 100644 +--- a/src/java.base/unix/native/libjava/TimeZone_md.c ++++ b/src/java.base/unix/native/libjava/TimeZone_md.c +@@ -67,10 +67,12 @@ static char *isFileIdentical(char* buf, size_t size, char *pathname); + static const char *ETC_TIMEZONE_FILE = "/etc/timezone"; + static const char *ZONEINFO_DIR = "/usr/share/zoneinfo"; + static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime"; ++static const char *DEFAULT_ZONEINFO_FILE_DIRNAME = "/etc"; + #else + static const char *SYS_INIT_FILE = "/etc/default/init"; + static const char *ZONEINFO_DIR = "/usr/share/lib/zoneinfo"; + static const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime"; ++static const char *DEFAULT_ZONEINFO_FILE_DIRNAME = "/usr/share/lib/zoneinfo"; + #endif /* defined(__linux__) || defined(_ALLBSD_SOURCE) */ + + static const char popularZones[][4] = {"UTC", "GMT"}; +@@ -310,7 +312,36 @@ getPlatformTimeZoneID() + return NULL; + } + linkbuf[len] = '\0'; +- tz = getZoneName(linkbuf); ++ ++ /* linkbuf may be a relative symlink or has more than one characters, like '.' and '/' , ++ * which will cause the function call getZoneName return to an abnormal timeZone name. ++ * For example, linkbuf is "../usr/share/zoneinfo//Asia/Shanghai", then the call of ++ * getZoneName(linkbuf) will get "/Asia/Shanghai", not "Asia/Shanghai". ++ * So we covert it to an absolute path by adding the file's (which is define by macro ++ * DEFAULT_ZONEINFO_FILE) dirname and then call glibc's realpath API to canonicalize ++ * the path. ++ */ ++ char abslinkbuf[2 * (PATH_MAX + 1)]; ++ if (linkbuf[0] != '/') { ++ if (sprintf(abslinkbuf, "%s/%s", DEFAULT_ZONEINFO_FILE_DIRNAME, linkbuf) < 0) { ++ jio_fprintf(stderr, (const char *) "failed to generate absolute path\n"); ++ return NULL; ++ } ++ } else { ++ strncpy(abslinkbuf, linkbuf, len + 1); ++ } ++ ++ /* canonicalize the path */ ++ char resolvedpath[PATH_MAX + 1]; ++ resolvedpath[PATH_MAX] = '\0'; ++ char *path = realpath(abslinkbuf, resolvedpath); ++ if (path == NULL) { ++ jio_fprintf(stderr, (const char *) "failed to get real path, symlink is %s\n", ++ abslinkbuf); ++ return NULL; ++ } ++ ++ tz = getZoneName(resolvedpath); + if (tz != NULL) { + tz = strdup(tz); + return tz; +-- +2.22.0 + diff --git a/openjdk-11.spec b/openjdk-11.spec index 499cb0a30af34c4cd6edad3ceb1852499b6771a0..6397af6fa76c9707f5619b950a852a29d25debe0 100644 --- a/openjdk-11.spec +++ b/openjdk-11.spec @@ -740,7 +740,7 @@ Provides: java-src%{?1} = %{epoch}:%{version}-%{release} Name: java-%{javaver}-%{origin} Version: %{newjavaver}.%{buildver} -Release: 1 +Release: 3 # 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 # also included the epoch in their virtual provides. This created a @@ -856,6 +856,13 @@ Patch74: delete_expired_certificates.patch # 11.0.12 Patch75: 8247691-Incorrect-handling-of-VM-exceptions-in-C1-deopt-stub.patch +Patch76: Update-algorithm-annotations-for-fill_words.patch +Patch77: 8257145-Performance-regression-with-XX-ResizePLAB-af.patch +Patch78: create-jfr-dump-file-with-pid-or-timestamp-if-specif.patch +Patch79: enhance-the-TimeZone-s-path-solution-on-Euler.patch +Patch80: Add-KAE-implementation.patch +Patch81: 8268427-Improve-AlgorithmConstraints-checkAlgorithm-.patch +Patch82: PS-introduce-UsePSRelaxedForwardee-to-enable-using-r.patch BuildRequires: autoconf BuildRequires: alsa-lib-devel @@ -1131,6 +1138,13 @@ pushd %{top_level_dir_name} %patch73 -p1 %patch74 -p1 %patch75 -p1 +%patch76 -p1 +%patch77 -p1 +%patch78 -p1 +%patch79 -p1 +%patch80 -p1 +%patch81 -p1 +%patch82 -p1 popd # openjdk # %patch1000 @@ -1633,6 +1647,17 @@ require "copy_jdk_configs.lua" %changelog +* Sat Sep 18 2021 kuenking111 - 1:11.0.12.7-3 +- add PS-introduce-UsePSRelaxedForwardee-to-enable-using-r.patch + +* Fri Sep 17 2021 kuenking111 - 1:11.0.12.7-2 +- add Update-algorithm-annotations-for-fill_words.patch +- add 8257145-Performance-regression-with-XX-ResizePLAB-af.patch +- add create-jfr-dump-file-with-pid-or-timestamp-if-specif.patch +- add enhance-the-TimeZone-s-path-solution-on-Euler.patch +- add Add-KAE-implementation.patch +- add 8268427-Improve-AlgorithmConstraints-checkAlgorithm-.patch + * Tue Aug 17 2021 eapen - 1:11.0.12.7-1 - add 8247691-Incorrect-handling-of-VM-exceptions-in-C1-deopt-stub.patch