From 3dc5c33293298c37389c9d67b7b509189333d6de Mon Sep 17 00:00:00 2001 From: lcc Date: Fri, 7 Mar 2025 12:25:04 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=97=E6=B3=95=E5=BA=93=E6=94=AF=E6=8C=81sm?= =?UTF-8?q?2=E7=AD=BE=E5=90=8D=E6=95=B0=E6=8D=AE=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: lcc --- common/src/asy_key_params.c | 11 + .../crypto_operation/sm2_ec_signature_data.c | 73 ++++++ frameworks/frameworks.gni | 7 +- frameworks/js/napi/crypto/BUILD.gn | 1 + .../inc/napi_crypto_framework_defines.h | 3 + .../napi/crypto/inc/napi_sm2_ec_signature.h | 40 ++++ frameworks/js/napi/crypto/src/napi_init.cpp | 2 + .../napi/crypto/src/napi_sm2_ec_signature.cpp | 216 ++++++++++++++++++ .../algorithm_parameter/sm2_crypto_params.h | 6 + .../crypto_operation/sm2_ec_signature_data.h | 51 +++++ .../common/inc/openssl_adapter.h | 15 ++ .../common/src/openssl_adapter.c | 30 +++ .../inc/cipher_sm2_ecdsa_signature_openssl.h | 32 +++ .../src/cipher_sm2_ecdsa_signature_openssl.c | 115 ++++++++++ plugin/plugin.gni | 1 + test/unittest/BUILD.gn | 1 + .../sm2/crypto_sm2_ecdsa_signature_test.cpp | 130 +++++++++++ 17 files changed, 732 insertions(+), 2 deletions(-) create mode 100644 frameworks/crypto_operation/sm2_ec_signature_data.c create mode 100644 frameworks/js/napi/crypto/inc/napi_sm2_ec_signature.h create mode 100644 frameworks/js/napi/crypto/src/napi_sm2_ec_signature.cpp create mode 100644 interfaces/inner_api/crypto_operation/sm2_ec_signature_data.h create mode 100644 plugin/openssl_plugin/crypto_operation/cipher/inc/cipher_sm2_ecdsa_signature_openssl.h create mode 100644 plugin/openssl_plugin/crypto_operation/cipher/src/cipher_sm2_ecdsa_signature_openssl.c create mode 100644 test/unittest/src/sm2/crypto_sm2_ecdsa_signature_test.cpp diff --git a/common/src/asy_key_params.c b/common/src/asy_key_params.c index 415ab5a..f103042 100644 --- a/common/src/asy_key_params.c +++ b/common/src/asy_key_params.c @@ -482,3 +482,14 @@ void DestroySm2CipherTextSpec(Sm2CipherTextSpec *spec) HcfFree(spec); } +void DestroySm2EcSignatureSpec(Sm2EcSignatureDataSpec *spec) +{ + if (spec == NULL) { + return; + } + HcfFree(spec->rCoordinate.data); + spec->rCoordinate.data = NULL; + HcfFree(spec->sCoordinate.data); + spec->sCoordinate.data = NULL; + HcfFree(spec); +} diff --git a/frameworks/crypto_operation/sm2_ec_signature_data.c b/frameworks/crypto_operation/sm2_ec_signature_data.c new file mode 100644 index 0000000..deecb09 --- /dev/null +++ b/frameworks/crypto_operation/sm2_ec_signature_data.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sm2_ec_signature_data.h" +#include +#include "cipher_sm2_ecdsa_signature_openssl.h" +#include "log.h" +#include "memory.h" +#include "utils.h" + +static bool CheckSm2EcSignatureDataSpec(Sm2EcSignatureDataSpec *spec) +{ + if (spec == NULL) { + LOGE("Spec is null"); + return false; + } + if ((spec->rCoordinate.data == NULL) || (spec->rCoordinate.len == 0)) { + LOGE("Spec.xCoordinate is null"); + return false; + } + if ((spec->sCoordinate.data == NULL) || (spec->sCoordinate.len == 0)) { + LOGE("Spec.yCoordinate is null"); + return false; + } + return true; +} + +HcfResult HcfGenEcSignatureDataBySpec(Sm2EcSignatureDataSpec *spec, HcfBlob *output) +{ + if (output == NULL) { + LOGE("Invalid param output!"); + return HCF_INVALID_PARAMS; + } + if (!CheckSm2EcSignatureDataSpec(spec)) { + LOGE("Invalid param spec!"); + return HCF_INVALID_PARAMS; + } + HcfResult res = HcfSm2SpecToDerData(spec, output); + if (res != HCF_SUCCESS) { + LOGE("Failed to convert construct to asn1!"); + } + return res; +} + +HcfResult HcfGenEcSignatureSpecByData(HcfBlob *input, Sm2EcSignatureDataSpec **returnSpc) +{ + if (input == NULL) { + LOGE("Invalid param input!"); + return HCF_INVALID_PARAMS; + } + if (returnSpc == NULL) { + LOGE("Invalid param returnSpc!"); + return HCF_INVALID_PARAMS; + } + HcfResult res = HcfDerDataToSm2Spec(input, returnSpc); + if (res != HCF_SUCCESS) { + LOGE("Failed to convert asn1 to construct!"); + return res; + } + return HCF_SUCCESS; +} \ No newline at end of file diff --git a/frameworks/frameworks.gni b/frameworks/frameworks.gni index e5b4de1..8a87bdc 100644 --- a/frameworks/frameworks.gni +++ b/frameworks/frameworks.gni @@ -57,8 +57,11 @@ framework_md_files = [ "${framework_path}/crypto_operation/md.c" ] framework_kdf_files = [ "${framework_path}/crypto_operation/kdf.c" ] -framework_sm2_crypto_util_files = - [ "${framework_path}/crypto_operation/sm2_crypto_util.c" ] +framework_sm2_crypto_util_files = [ + "${framework_path}/crypto_operation/sm2_crypto_util.c", + "${framework_path}/crypto_operation/sm2_ec_signature_data.c" + + ] framework_files = framework_key_agreement_files + framework_signature_files + diff --git a/frameworks/js/napi/crypto/BUILD.gn b/frameworks/js/napi/crypto/BUILD.gn index 33d96ee..629594b 100644 --- a/frameworks/js/napi/crypto/BUILD.gn +++ b/frameworks/js/napi/crypto/BUILD.gn @@ -55,6 +55,7 @@ ohos_shared_library("cryptoframework_napi") { "src/napi_rand.cpp", "src/napi_sign.cpp", "src/napi_sm2_crypto_util.cpp", + "src/napi_sm2_ec_signature.cpp", "src/napi_sym_key.cpp", "src/napi_sym_key_generator.cpp", "src/napi_utils.cpp", diff --git a/frameworks/js/napi/crypto/inc/napi_crypto_framework_defines.h b/frameworks/js/napi/crypto/inc/napi_crypto_framework_defines.h index 5874584..c94bc34 100644 --- a/frameworks/js/napi/crypto/inc/napi_crypto_framework_defines.h +++ b/frameworks/js/napi/crypto/inc/napi_crypto_framework_defines.h @@ -93,6 +93,9 @@ const std::string SM2_UTIL_PARAM_Y_COORDINATE = "yCoordinate"; const std::string SM2_UTIL_PARAM_CIPHER_TEXT_DATA = "cipherTextData"; const std::string SM2_UTIL_PARAM_HASH_DATA = "hashData"; +const std::string SM2_EC_SIGNATURE_PARAM_R = "r"; +const std::string SM2_EC_SIGNATURE_PARAM_S = "s"; + const std::string KDF_PARAMS_SALT = "salt"; const std::string KDF_PARAMS_KEY_SIZE = "keySize"; diff --git a/frameworks/js/napi/crypto/inc/napi_sm2_ec_signature.h b/frameworks/js/napi/crypto/inc/napi_sm2_ec_signature.h new file mode 100644 index 0000000..3bd45ef --- /dev/null +++ b/frameworks/js/napi/crypto/inc/napi_sm2_ec_signature.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HCF_NAPI_SM2_EC_SIGNATURE_H +#define HCF_NAPI_SM2_EC_SIGNATURE_H + +#include + +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "sm2_ec_signature_data.h" + +namespace OHOS { +namespace CryptoFramework { +class NapiSm2EcSignature { +public: + explicit NapiSm2EcSignature(); + ~NapiSm2EcSignature(); + + static napi_value JsGenEcSignatureDataSpec(napi_env env, napi_callback_info info); + static napi_value JsGenEcSignatureData(napi_env env, napi_callback_info info); + static napi_value SignatureUtilsConstructor(napi_env env, napi_callback_info info); + static napi_value SignatureUtilsConstructorClass(napi_env env); + static void DefineNapiSm2EcSignatureJSClass(napi_env env, napi_value exports); +}; +} // namespace CryptoFramework +} // namespace OHOS +#endif diff --git a/frameworks/js/napi/crypto/src/napi_init.cpp b/frameworks/js/napi/crypto/src/napi_init.cpp index b36f0d3..5d9c3cd 100644 --- a/frameworks/js/napi/crypto/src/napi_init.cpp +++ b/frameworks/js/napi/crypto/src/napi_init.cpp @@ -37,6 +37,7 @@ #include "napi_key.h" #include "napi_utils.h" #include "napi_crypto_framework_defines.h" +#include "napi_sm2_ec_signature.h" #include "key.h" #include "asy_key_params.h" @@ -233,6 +234,7 @@ static napi_value ModuleExport(napi_env env, napi_value exports) NapiECCKeyUtil::DefineNapiECCKeyUtilJSClass(env, exports); NapiDHKeyUtil::DefineNapiDHKeyUtilJSClass(env, exports); NapiSm2CryptoUtil::DefineNapiSm2CryptoUtilJSClass(env, exports); + NapiSm2EcSignature::DefineNapiSm2EcSignatureJSClass(env, exports); LOGD("module init end."); return exports; } diff --git a/frameworks/js/napi/crypto/src/napi_sm2_ec_signature.cpp b/frameworks/js/napi/crypto/src/napi_sm2_ec_signature.cpp new file mode 100644 index 0000000..cfefb35 --- /dev/null +++ b/frameworks/js/napi/crypto/src/napi_sm2_ec_signature.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "napi_sm2_ec_signature.h" + +#include +#include "securec.h" +#include "log.h" +#include "memory.h" +#include "napi_crypto_framework_defines.h" +#include "napi_utils.h" + +namespace OHOS { +namespace CryptoFramework { +NapiSm2EcSignature::NapiSm2EcSignature() {} +NapiSm2EcSignature::~NapiSm2EcSignature() {} + +static bool GetSm2EcSignatureDataSpecFromNapiValue(napi_env env, napi_value arg, Sm2EcSignatureDataSpec **returnSpec) +{ + if ((env == nullptr) || (arg == nullptr) || (returnSpec == nullptr)) { + LOGE("Invalid params."); + return false; + } + Sm2EcSignatureDataSpec *tempSpec = static_cast(HcfMalloc(sizeof(Sm2EcSignatureDataSpec), 0)); + if (tempSpec == nullptr) { + LOGE("Malloc failed!"); + return false; + } + napi_value rCoordinate = GetDetailAsyKeySpecValue(env, arg, SM2_EC_SIGNATURE_PARAM_R); + napi_value sCoordinate = GetDetailAsyKeySpecValue(env, arg, SM2_EC_SIGNATURE_PARAM_S); + if ((rCoordinate == nullptr) || (sCoordinate == nullptr)) { + LOGE("Invalid params!"); + DestroySm2EcSignatureSpec(tempSpec); + return false; + } + bool ret = GetBigIntFromNapiValue(env, rCoordinate, &tempSpec->rCoordinate); + if (!ret) { + LOGE("Failed to get valid r coordinate."); + DestroySm2EcSignatureSpec(tempSpec); + return false; + } + ret = GetBigIntFromNapiValue(env, sCoordinate, &tempSpec->sCoordinate); + if (!ret) { + LOGE("Failed to get valid s coordinate."); + DestroySm2EcSignatureSpec(tempSpec); + return false; + } + *returnSpec = tempSpec; + return true; +} + +napi_value NapiSm2EcSignature::JsGenEcSignatureData(napi_env env, napi_callback_info info) +{ + size_t expectedArgc = PARAMS_NUM_ONE; + size_t argc = ARGS_SIZE_ONE; + napi_value argv[ARGS_SIZE_ONE] = { nullptr }; + napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); + if (argc != expectedArgc) { + LOGE("The input args num is invalid."); + napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid.")); + return nullptr; + } + Sm2EcSignatureDataSpec *spec = nullptr; + if (!GetSm2EcSignatureDataSpecFromNapiValue(env, argv[0], &spec)) { + LOGE("Failed to get spec."); + napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get spec.")); + return nullptr; + } + HcfBlob *output = static_cast(HcfMalloc(sizeof(HcfBlob), 0)); + if (output == NULL) { + LOGE("Failed to allocate HcfBlob memory!"); + DestroySm2EcSignatureSpec(spec); + napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "Failed to allocate memory.")); + return nullptr; + } + HcfResult res = HcfGenEcSignatureDataBySpec(spec, output); + if (res != HCF_SUCCESS) { + LOGE("Gen cipher text by spec fail."); + HcfFree(output); + DestroySm2EcSignatureSpec(spec); + napi_throw(env, GenerateBusinessError(env, res, "gen cipher text by spec fail.")); + return nullptr; + } + napi_value instance = ConvertObjectBlobToNapiValue(env, output); + HcfBlobDataFree(output); + HcfFree(output); + DestroySm2EcSignatureSpec(spec); + return instance; +} + +static bool CheckSm2CipherTextSpec(Sm2EcSignatureDataSpec *spec) +{ + if (spec == nullptr) { + LOGE("Invalid spec!"); + return false; + } + if (spec->rCoordinate.data == nullptr || spec->rCoordinate.len == 0) { + LOGE("Invalid rCoordinate!"); + return false; + } + if (spec->sCoordinate.data == nullptr || spec->sCoordinate.len == 0) { + LOGE("Invalid sCoordinate!"); + return false; + } + return true; +} + +static bool BuildSm2CipherTextSpecToNapiValue(napi_env env, Sm2EcSignatureDataSpec *spec, napi_value *instance) +{ + if (!BuildSetNamedProperty(env, &(spec->rCoordinate), SM2_EC_SIGNATURE_PARAM_R.c_str(), instance)) { + LOGE("Build rCoordinate failed!"); + return false; + } + if (!BuildSetNamedProperty(env, &(spec->sCoordinate), SM2_EC_SIGNATURE_PARAM_S.c_str(), instance)) { + LOGE("Build sCoordinate failed!"); + return false; + } + return true; +} + +static napi_value ConvertSm2CipherTextSpecToNapiValue(napi_env env, Sm2EcSignatureDataSpec *spec) +{ + if (!CheckSm2CipherTextSpec(spec)) { + LOGE("Invalid spec!"); + napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Invalid spec!")); + return NapiGetNull(env); + } + napi_value instance; + napi_status status = napi_create_object(env, &instance); + if (status != napi_ok) { + LOGE("Create object failed!"); + napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create object failed!")); + return NapiGetNull(env); + } + if (!BuildSm2CipherTextSpecToNapiValue(env, spec, &instance)) { + LOGE("Build object failed!"); + napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build object failed!")); + return NapiGetNull(env); + } + return instance; +} + +napi_value NapiSm2EcSignature::JsGenEcSignatureDataSpec(napi_env env, napi_callback_info info) +{ + size_t expectedArgc = PARAMS_NUM_ONE; + size_t argc = ARGS_SIZE_ONE; + napi_value argv[ARGS_SIZE_ONE] = { nullptr }; + napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); + if (argc != expectedArgc) { + LOGE("The input args num is invalid."); + napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid.")); + return nullptr; + } + HcfBlob *cipherText = GetBlobFromNapiUint8Arr(env, argv[0]); + if (cipherText == nullptr) { + LOGE("Failed to get cipherText."); + napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get cipherText.")); + return nullptr; + } + Sm2EcSignatureDataSpec *returnSpec = nullptr; + HcfResult res = HcfGenEcSignatureSpecByData(cipherText, &returnSpec); + if (res != HCF_SUCCESS) { + LOGE("Get cipher text spec fail."); + HcfBlobDataFree(cipherText); + HcfFree(cipherText); + napi_throw(env, GenerateBusinessError(env, res, "get cipher text spec fail.")); + return nullptr; + } + napi_value instance = ConvertSm2CipherTextSpecToNapiValue(env, returnSpec); + DestroySm2EcSignatureSpec(returnSpec); + HcfBlobDataFree(cipherText); + HcfFree(cipherText); + return instance; +} + +napi_value NapiSm2EcSignature::SignatureUtilsConstructor(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + size_t argc = ARGS_SIZE_ONE; + napi_value argv[ARGS_SIZE_ONE] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr)); + return thisVar; +} + +napi_value NapiSm2EcSignature::SignatureUtilsConstructorClass(napi_env env) +{ + napi_value cons = nullptr; + napi_property_descriptor clzDes[] = { + DECLARE_NAPI_STATIC_FUNCTION("genEccSignature", NapiSm2EcSignature::JsGenEcSignatureData), + DECLARE_NAPI_STATIC_FUNCTION("genEccSignatureSpec", NapiSm2EcSignature::JsGenEcSignatureDataSpec), + }; + NAPI_CALL(env, napi_define_class(env, "SignatureUtils", NAPI_AUTO_LENGTH, + NapiSm2EcSignature::SignatureUtilsConstructor, + nullptr, sizeof(clzDes) / sizeof(clzDes[0]), clzDes, &cons)); + return cons; +} + +void NapiSm2EcSignature::DefineNapiSm2EcSignatureJSClass(napi_env env, napi_value exports) +{ + napi_set_named_property(env, exports, "SignatureUtils", NapiSm2EcSignature::SignatureUtilsConstructorClass(env)); +} +} // CryptoFramework +} // OHOS + \ No newline at end of file diff --git a/interfaces/inner_api/algorithm_parameter/sm2_crypto_params.h b/interfaces/inner_api/algorithm_parameter/sm2_crypto_params.h index 92db7f4..c322968 100644 --- a/interfaces/inner_api/algorithm_parameter/sm2_crypto_params.h +++ b/interfaces/inner_api/algorithm_parameter/sm2_crypto_params.h @@ -26,11 +26,17 @@ typedef struct Sm2CipherTextSpec { HcfBlob hashData; } Sm2CipherTextSpec; +typedef struct Sm2EcSignatureDataSpec { + HcfBigInteger rCoordinate; + HcfBigInteger sCoordinate; +} Sm2EcSignatureDataSpec; + #ifdef __cplusplus extern "C" { #endif void DestroySm2CipherTextSpec(Sm2CipherTextSpec *spec); +void DestroySm2EcSignatureSpec(Sm2EcSignatureDataSpec *spec); #ifdef __cplusplus } diff --git a/interfaces/inner_api/crypto_operation/sm2_ec_signature_data.h b/interfaces/inner_api/crypto_operation/sm2_ec_signature_data.h new file mode 100644 index 0000000..d1b4c6b --- /dev/null +++ b/interfaces/inner_api/crypto_operation/sm2_ec_signature_data.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HCF_SM2_CRYPTO_UTIL_H +#define HCF_SM2_CRYPTO_UTIL_H + +#include "result.h" +#include "sm2_crypto_params.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Generate the SM2 ciphertext in ASN.1 format according to the specific data. + * + * @param spec - indicates the EC signature data spec.. + * @param output - indicates the signature data in DER format. + * @return Returns the status code of the execution. + * @since 20 + * @version 1.0 + */ +HcfResult HcfGenEcSignatureDataBySpec(Sm2EcSignatureDataSpec *spec, HcfBlob *output); +/** + * @brief Get the specific data from the SM2 ciphertext in ASN.1 format. + * + * @param input - indicates the signature data in DER format. + * @param returnSpc - indicates the EC signature data spec.. + * @return Returns the status code of the execution. + * @since 20 + * @version 1.0 + */ +HcfResult HcfGenEcSignatureSpecByData(HcfBlob *input, Sm2EcSignatureDataSpec **returnSpc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/plugin/openssl_plugin/common/inc/openssl_adapter.h b/plugin/openssl_plugin/common/inc/openssl_adapter.h index 1affe17..aa04ac5 100644 --- a/plugin/openssl_plugin/common/inc/openssl_adapter.h +++ b/plugin/openssl_plugin/common/inc/openssl_adapter.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -365,6 +366,20 @@ struct Sm2CipherTextSt { ASN1_OCTET_STRING *c2; }; +typedef struct ECDSA_SIG_st ECDSA_SIG; +struct ECDSA_SIG_st { + BIGNUM *r; + BIGNUM *s; +}; + + +ECDSA_SIG *OpensslEcdsaSigNew(); +ECDSA_SIG *OpensslD2iSm2EcdsaSig(const unsigned char **inputData, int dataLen); +int OpensslI2dSm2EcdsaSig(ECDSA_SIG *sm2Text, unsigned char **returnData); +void OpensslSm2EcdsaSigFree(ECDSA_SIG *sm2Text); +const BIGNUM *OpensslEcdsaSigGet0r(const ECDSA_SIG *sig); +const BIGNUM *OpensslEcdsaSigGet0s(const ECDSA_SIG *sig); + void OpensslSm2CipherTextFree(struct Sm2CipherTextSt *sm2Text); struct Sm2CipherTextSt *OpensslD2iSm2CipherText(const uint8_t *ciphertext, size_t cipherTextLen); void OpensslAsn1OctetStringFree(ASN1_OCTET_STRING *field); diff --git a/plugin/openssl_plugin/common/src/openssl_adapter.c b/plugin/openssl_plugin/common/src/openssl_adapter.c index 81c0851..5db610d 100644 --- a/plugin/openssl_plugin/common/src/openssl_adapter.c +++ b/plugin/openssl_plugin/common/src/openssl_adapter.c @@ -1408,6 +1408,36 @@ const unsigned char *OpensslAsn1StringGet0Data(ASN1_OCTET_STRING *p) return ASN1_STRING_get0_data(p); } +ECDSA_SIG *OpensslEcdsaSigNew() +{ + return ECDSA_SIG_new(); +} + +ECDSA_SIG *OpensslD2iSm2EcdsaSig(const unsigned char **inputData, int dataLen) +{ + return d2i_ECDSA_SIG(NULL, inputData, dataLen); +} + +int OpensslI2dSm2EcdsaSig(ECDSA_SIG *sm2Text, unsigned char **returnData) +{ + return i2d_ECDSA_SIG(sm2Text, returnData); +} + +void OpensslSm2EcdsaSigFree(ECDSA_SIG *sm2Text) +{ + return ECDSA_SIG_free(sm2Text); +} + +const BIGNUM *OpensslEcdsaSigGet0r(const ECDSA_SIG *sig) +{ + return ECDSA_SIG_get0_r(sig); +} + +const BIGNUM *OpensslEcdsaSigGet0s(const ECDSA_SIG *sig) +{ + return ECDSA_SIG_get0_s(sig); +} + OSSL_PARAM_BLD *OpensslOsslParamBldNew(void) { return OSSL_PARAM_BLD_new(); diff --git a/plugin/openssl_plugin/crypto_operation/cipher/inc/cipher_sm2_ecdsa_signature_openssl.h b/plugin/openssl_plugin/crypto_operation/cipher/inc/cipher_sm2_ecdsa_signature_openssl.h new file mode 100644 index 0000000..a75cd17 --- /dev/null +++ b/plugin/openssl_plugin/crypto_operation/cipher/inc/cipher_sm2_ecdsa_signature_openssl.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HCF_CIPHER_SM2_ECDSA_SIGNATURE_OPENSSL_H +#define HCF_CIPHER_SM2_ECDSA_SIGNATURE_OPENSSL_H + +#include "sm2_crypto_params.h" +#include "result.h" + +#ifdef __cplusplus +extern "C" { +#endif + +HcfResult HcfSm2SpecToDerData(Sm2EcSignatureDataSpec *spec, HcfBlob *output); +HcfResult HcfDerDataToSm2Spec(HcfBlob *input, Sm2EcSignatureDataSpec **returnSpec); + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/plugin/openssl_plugin/crypto_operation/cipher/src/cipher_sm2_ecdsa_signature_openssl.c b/plugin/openssl_plugin/crypto_operation/cipher/src/cipher_sm2_ecdsa_signature_openssl.c new file mode 100644 index 0000000..e892d14 --- /dev/null +++ b/plugin/openssl_plugin/crypto_operation/cipher/src/cipher_sm2_ecdsa_signature_openssl.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cipher_sm2_ecdsa_signature_openssl.h" +#include +#include +#include "log.h" +#include "memory.h" +#include "openssl_adapter.h" +#include "openssl_common.h" +#include "securec.h" +#include "utils.h" + +static HcfResult BuildSm2Ciphertext(const Sm2EcSignatureDataSpec *spec, ECDSA_SIG *sm2Text) +{ + if (BigIntegerToBigNum(&(spec->rCoordinate), &(sm2Text->r)) != HCF_SUCCESS) { + LOGE("Build r failed."); + return HCF_ERR_CRYPTO_OPERATION; + } + if (BigIntegerToBigNum(&(spec->sCoordinate), &(sm2Text->s)) != HCF_SUCCESS) { + LOGE("Build s failed."); + return HCF_ERR_CRYPTO_OPERATION; + } + return HCF_SUCCESS; +} + +HcfResult HcfSm2SpecToDerData(Sm2EcSignatureDataSpec *spec, HcfBlob *output) +{ + if (spec == NULL || output == NULL) { + LOGE("Invalid params"); + return HCF_INVALID_PARAMS; + } + ECDSA_SIG *sig = OpensslEcdsaSigNew(); + HcfResult res = BuildSm2Ciphertext(spec, sig); + if (res != HCF_SUCCESS) { + OpensslSm2EcdsaSigFree(sig); + LOGE("SM2 build SM2Ciphertext fail"); + return res; + } + unsigned char *returnData = NULL; + int returnDataLen = OpensslI2dSm2EcdsaSig(sig, &returnData); + OpensslSm2EcdsaSigFree(sig); + if (returnData == NULL || returnDataLen < 0) { + LOGE("SM2 openssl [i2d_SM2_Ciphertext] error"); + HcfPrintOpensslError(); + return HCF_ERR_CRYPTO_OPERATION; + } + output->data = returnData; + output->len = (size_t)returnDataLen; + return HCF_SUCCESS; +} + +static HcfResult BuildSm2EcdsaSigSpec(ECDSA_SIG *sig, Sm2EcSignatureDataSpec *tempSpec) +{ + const BIGNUM *r = OpensslEcdsaSigGet0r(sig); + const BIGNUM *s = OpensslEcdsaSigGet0s(sig); + if (r == NULL || s == NULL) { + LOGE("get r or s failed"); + return HCF_ERR_CRYPTO_OPERATION; + } + if (BigNumToBigInteger(r, &(tempSpec->rCoordinate)) != HCF_SUCCESS) { + LOGE("BigNumToBigInteger rCoordinate failed."); + return HCF_ERR_CRYPTO_OPERATION; + } + if (BigNumToBigInteger(s, &(tempSpec->sCoordinate)) != HCF_SUCCESS) { + LOGE("BigNumToBigInteger sCoordinate failed."); + return HCF_ERR_CRYPTO_OPERATION; + } + return HCF_SUCCESS; +} + +HcfResult HcfDerDataToSm2Spec(HcfBlob *input, Sm2EcSignatureDataSpec **returnSpec) +{ + if (input == NULL || returnSpec == NULL) { + LOGE("Invalid signature params"); + return HCF_INVALID_PARAMS; + } + + Sm2EcSignatureDataSpec *tempSpec = (Sm2EcSignatureDataSpec *)(HcfMalloc(sizeof(Sm2EcSignatureDataSpec), 0)); + if (tempSpec == NULL) { + LOGE("Failed to allocate Sm2EcSignatureDataSpec memory"); + return HCF_ERR_MALLOC; + } + const unsigned char *data = (const unsigned char *)input->data; + ECDSA_SIG *sig = OpensslD2iSm2EcdsaSig(&data, (int)input->len); + if (sig == NULL) { + LOGE("SM2 build SM2Ciphertext fail"); + DestroySm2EcSignatureSpec(tempSpec); + OpensslSm2EcdsaSigFree(sig); + return HCF_ERR_CRYPTO_OPERATION; + } + HcfResult res = BuildSm2EcdsaSigSpec(sig, tempSpec); + if (res != HCF_SUCCESS) { + LOGE("SM2 build SM2ECDSA sig spec fail"); + DestroySm2EcSignatureSpec(tempSpec); + OpensslSm2EcdsaSigFree(sig); + return res; + } + + *returnSpec = tempSpec; + OpensslSm2EcdsaSigFree(sig); + return HCF_SUCCESS; +} \ No newline at end of file diff --git a/plugin/plugin.gni b/plugin/plugin.gni index 9785bad..b95ff88 100644 --- a/plugin/plugin.gni +++ b/plugin/plugin.gni @@ -76,6 +76,7 @@ plugin_cipher_files = [ "${plugin_path}/openssl_plugin/crypto_operation/cipher/src/cipher_sm4_openssl.c", "${plugin_path}/openssl_plugin/crypto_operation/cipher/src/cipher_sm2_openssl.c", "${plugin_path}/openssl_plugin/crypto_operation/cipher/src/cipher_sm2_crypto_util_openssl.c", + "${plugin_path}/openssl_plugin/crypto_operation/cipher/src/cipher_sm2_ecdsa_signature_openssl.c", ] plugin_hmac_files = diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 199c985..76653ee 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -127,6 +127,7 @@ ohos_unittest("crypto_framework_test") { "src/sm2/crypto_sm2_asy_key_generator_by_spec_sub_test.cpp", "src/sm2/crypto_sm2_asy_key_generator_by_spec_test.cpp", "src/sm2/crypto_sm2_util_test.cpp", + "src/sm2/crypto_sm2_ecdsa_signature_test.cpp" ] sources += framework_files + plugin_files diff --git a/test/unittest/src/sm2/crypto_sm2_ecdsa_signature_test.cpp b/test/unittest/src/sm2/crypto_sm2_ecdsa_signature_test.cpp new file mode 100644 index 0000000..85b6acd --- /dev/null +++ b/test/unittest/src/sm2/crypto_sm2_ecdsa_signature_test.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "securec.h" +#include "blob.h" +#include "cipher_sm2_ecdsa_signature_openssl.h" +#include "sm2_crypto_util.h" +#include "sm2_crypto_params.h" +#include "log.h" +#include "memory.h" +#include "cstring" + +using namespace std; +using namespace testing::ext; + +namespace { +class CryptoSm2EcdsaSignature : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void CryptoSm2EcdsaSignature::SetUp() {} +void CryptoSm2EcdsaSignature::TearDown() {} +void CryptoSm2EcdsaSignature::SetUpTestCase() {} +void CryptoSm2EcdsaSignature::TearDownTestCase() {} + +static unsigned char g_rCoordinate[] = { + 107, 93, 198, 247, 119, 18, 40, 110, 90, 156, 193, 158, 205, 113, 170, 128, 146, 109, 75, 17, 181, 109, 110, + 91, 149, 5, 110, 233, 209, 78, 229, 96 +}; + +static unsigned char g_sCoordinate[] = { + 45, 153, 88, 82, 104, 221, 226, 43, 174, 21, 122, 248, 5, 232, 105, 41, 92, 95, 102, 224, 216, 149, 85, 236, + 110, 6, 64, 188, 149, 70, 70, 183 +}; + +HcfResult ConstructCorrectSm2Spec(Sm2EcSignatureDataSpec **spec) +{ + Sm2EcSignatureDataSpec *tempSpec = + static_cast(HcfMalloc(sizeof(Sm2EcSignatureDataSpec), 0)); + if (tempSpec == nullptr) { + return HCF_ERR_MALLOC; + } + tempSpec->rCoordinate.data = g_rCoordinate; + tempSpec->rCoordinate.len = sizeof(g_sCoordinate); + tempSpec->sCoordinate.data = g_sCoordinate; + tempSpec->sCoordinate.len = sizeof(g_sCoordinate); + *spec = tempSpec; + return HCF_SUCCESS; +} + +HWTEST_F(CryptoSm2EcdsaSignature, HcfSm2SpecToDerDataAndBack, TestSize.Level0) +{ + Sm2EcSignatureDataSpec *spec = nullptr; + ASSERT_EQ(ConstructCorrectSm2Spec(&spec), HCF_SUCCESS); + + // Convert SM2 spec to DER data + HcfBlob derOutput = { .data = nullptr, .len = 0 }; + EXPECT_EQ(HcfSm2SpecToDerData(spec, &derOutput), HCF_SUCCESS); + EXPECT_NE(derOutput.data, nullptr); + EXPECT_GT(derOutput.len, 0); + + // Convert DER data back to SM2 spec + Sm2EcSignatureDataSpec *returnSpec = nullptr; + EXPECT_EQ(HcfDerDataToSm2Spec(&derOutput, &returnSpec), HCF_SUCCESS); + EXPECT_NE(returnSpec, nullptr); + + // Validate the converted spec matches the original + EXPECT_EQ(returnSpec->rCoordinate.len, spec->rCoordinate.len); + EXPECT_EQ(memcmp(returnSpec->rCoordinate.data, spec->rCoordinate.data, spec->rCoordinate.len), 0); + EXPECT_EQ(returnSpec->sCoordinate.len, spec->sCoordinate.len); + EXPECT_EQ(memcmp(returnSpec->sCoordinate.data, spec->sCoordinate.data, spec->sCoordinate.len), 0); + + // Free allocated resources + HcfBlobDataFree(&derOutput); + DestroySm2EcSignatureSpec(returnSpec); + HcfFree(spec); +} + +HWTEST_F(CryptoSm2EcdsaSignature, HcfSm2SpecToDerData_NullInput, TestSize.Level0) +{ + HcfBlob derOutput = { .data = nullptr, .len = 0 }; + EXPECT_EQ(HcfSm2SpecToDerData(nullptr, &derOutput), HCF_INVALID_PARAMS); +} + +HWTEST_F(CryptoSm2EcdsaSignature, HcfSm2SpecToDerData_NullOutput, TestSize.Level0) +{ + Sm2EcSignatureDataSpec *spec = nullptr; + ASSERT_EQ(ConstructCorrectSm2Spec(&spec), HCF_SUCCESS); + EXPECT_EQ(HcfSm2SpecToDerData(spec, nullptr), HCF_INVALID_PARAMS); + HcfFree(spec); +} + +HWTEST_F(CryptoSm2EcdsaSignature, HcfDerDataToSm2Spec_NullInput, TestSize.Level0) +{ + Sm2EcSignatureDataSpec *returnSpec = nullptr; + EXPECT_EQ(HcfDerDataToSm2Spec(nullptr, &returnSpec), HCF_INVALID_PARAMS); +} + +HWTEST_F(CryptoSm2EcdsaSignature, HcfDerDataToSm2Spec_NullOutput, TestSize.Level0) +{ + HcfBlob derInput = { .data = g_rCoordinate, .len = sizeof(g_rCoordinate) }; + EXPECT_EQ(HcfDerDataToSm2Spec(&derInput, nullptr), HCF_INVALID_PARAMS); +} + +HWTEST_F(CryptoSm2EcdsaSignature, HcfDerDataToSm2Spec_InvalidData, TestSize.Level0) +{ + unsigned char invalidData[] = { 0x00, 0x01, 0x02, 0x03 }; + HcfBlob derInput = { .data = invalidData, .len = sizeof(invalidData) }; + Sm2EcSignatureDataSpec *returnSpec = nullptr; + EXPECT_EQ(HcfDerDataToSm2Spec(&derInput, &returnSpec), HCF_ERR_CRYPTO_OPERATION); +} + +} \ No newline at end of file -- Gitee