diff --git a/bundle.json b/bundle.json index 61860f688ee0fd643e659a6774ca7563f93b01a8..d856010262df3e4f9d1290bd89275d623fdc8bd1 100644 --- a/bundle.json +++ b/bundle.json @@ -41,7 +41,8 @@ "napi", "openssl", "bounds_checking_function", - "runtime_core" + "runtime_core", + "huks" ], "third_party": [] }, diff --git a/frameworks/crypto_operation/rand.c b/frameworks/crypto_operation/rand.c index e998f87ada87d6c51e39a5380281e7e8ea3b6beb..758829851d055d22f28c632501a5d28ad789476a 100644 --- a/frameworks/crypto_operation/rand.c +++ b/frameworks/crypto_operation/rand.c @@ -114,6 +114,20 @@ static HcfResult SetSeed(HcfRand *self, HcfBlob *seed) return HCF_SUCCESS; } +static HcfResult EnableHardwareEntropy(HcfRand *self) +{ + if (self == NULL) { + LOGE("The input self ptr is NULL!"); + return HCF_ERR_PARAMETER_CHECK_FAILED; + } + if (!HcfIsClassMatch((HcfObjectBase *)self, GetRandClass())) { + LOGE("Class is not match."); + return HCF_ERR_PARAMETER_CHECK_FAILED; + } + return ((HcfRandImpl *)self)->spiObj->engineEnableHardwareEntropy( + ((HcfRandImpl *)self)->spiObj); +} + static void HcfRandDestroy(HcfObjectBase *self) { if (self == NULL) { @@ -163,6 +177,7 @@ HcfResult HcfRandCreate(HcfRand **random) returnRandApi->base.generateRandom = GenerateRandom; returnRandApi->base.getAlgoName = GetAlgoName; returnRandApi->base.setSeed = SetSeed; + returnRandApi->base.enableHardwareEntropy = EnableHardwareEntropy; returnRandApi->spiObj = spiObj; *random = (HcfRand *)returnRandApi; return HCF_SUCCESS; diff --git a/frameworks/js/jsi/inc/jsi_api.h b/frameworks/js/jsi/inc/jsi_api.h index 723492524fde0ddf9bcb7828bc034479f64ad000..46d18613e94b51aa30eba33074a63dbd0403d9c9 100644 --- a/frameworks/js/jsi/inc/jsi_api.h +++ b/frameworks/js/jsi/inc/jsi_api.h @@ -42,7 +42,7 @@ private: static JSIValue GenerateRandom(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum); static JSIValue GenerateRandomSync(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum); static JSIValue SetSeed(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum); - + static JSIValue EnableHardwareEntropy(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum); static void MdDestroy(void); static void RandomDestroy(void); }; diff --git a/frameworks/js/jsi/src/jsi_rand.cpp b/frameworks/js/jsi/src/jsi_rand.cpp index 0997234414e796d7420bb66e807b900b953cf920..870b4538fdafdf02ba5f00e83ef1f44d57b3fd49 100644 --- a/frameworks/js/jsi/src/jsi_rand.cpp +++ b/frameworks/js/jsi/src/jsi_rand.cpp @@ -49,12 +49,14 @@ JSIValue CryptoFrameworkLiteModule::CreateRandom(const JSIValue thisVal, const J JSIValue generateRandom = JSI::CreateFunction(GenerateRandom); JSIValue generateRandomSync = JSI::CreateFunction(GenerateRandomSync); JSIValue setSeed = JSI::CreateFunction(SetSeed); + JSIValue enableHardwareEntropy = JSI::CreateFunction(EnableHardwareEntropy); JSI::SetNamedProperty(serviceObj, "generateRandom", generateRandom); JSI::SetNamedProperty(serviceObj, "generateRandomSync", generateRandomSync); JSI::SetNamedProperty(serviceObj, "setSeed", setSeed); + JSI::SetNamedProperty(serviceObj, "enableHardwareEntropy", enableHardwareEntropy); JSI::SetNumberProperty(serviceObj, "randObj", (double)(uint32_t)randObj); - JSI::ReleaseValueList(generateRandom, generateRandomSync, setSeed, ARGS_END); + JSI::ReleaseValueList(generateRandom, generateRandomSync, setSeed, enableHardwareEntropy, ARGS_END); return serviceObj; } @@ -154,6 +156,14 @@ JSIValue CryptoFrameworkLiteModule::SetSeed(const JSIValue thisVal, const JSIVal return ThrowErrorCodeResult(HCF_SUCCESS); } +JSIValue CryptoFrameworkLiteModule::EnableHardwareEntropy(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum) +{ + (void)argsNum; + (void)thisVal; + (void)args; + return ThrowErrorCodeResult(HCF_NOT_SUPPORT); +} + void CryptoFrameworkLiteModule::RandomDestroy(void) { ListDestroy(JSI_ALG_RAND); diff --git a/frameworks/js/napi/crypto/inc/napi_rand.h b/frameworks/js/napi/crypto/inc/napi_rand.h index c7595b9ce5462258e317bf1dd090dccc509c9edf..73e5febbbceced862cf8177ba66e7272dba32ba2 100644 --- a/frameworks/js/napi/crypto/inc/napi_rand.h +++ b/frameworks/js/napi/crypto/inc/napi_rand.h @@ -41,6 +41,7 @@ public: static napi_value JsGenerateRandom(napi_env env, napi_callback_info info); static napi_value JsGenerateRandomSync(napi_env env, napi_callback_info info); static napi_value JsSetSeed(napi_env env, napi_callback_info info); + static napi_value JsEnableHardwareEntropy(napi_env env, napi_callback_info info); private: HcfRand *randObj_ = nullptr; diff --git a/frameworks/js/napi/crypto/src/napi_rand.cpp b/frameworks/js/napi/crypto/src/napi_rand.cpp index 36d163ace2f559ed4d77479eda2066ba61fe1e55..c59d72e6d7916ff1683523da995934af007ced6a 100644 --- a/frameworks/js/napi/crypto/src/napi_rand.cpp +++ b/frameworks/js/napi/crypto/src/napi_rand.cpp @@ -347,6 +347,32 @@ napi_value NapiRand::JsSetSeed(napi_env env, napi_callback_info info) return thisVar; } +napi_value NapiRand::JsEnableHardwareEntropy(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr); + NapiRand *napiRand = nullptr; + napi_status status = napi_unwrap(env, thisVar, reinterpret_cast(&napiRand)); + if (status != napi_ok || napiRand == nullptr) { + napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "failed to unwrap NapiRand obj!")); + LOGE("failed to unwrap NapiRand obj!"); + return nullptr; + } + HcfRand *rand = napiRand->GetRand(); + if (rand == nullptr) { + napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "fail to get rand obj!")); + LOGE("fail to get rand obj!"); + return nullptr; + } + HcfResult res = rand->enableHardwareEntropy(rand); + if (res != HCF_SUCCESS) { + napi_throw(env, GenerateBusinessError(env, res, "enable hardware entropy failed.")); + LOGE("enable hardware entropy failed."); + return nullptr; + } + return thisVar; +} + napi_value NapiRand::JsGetAlgorithm(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; @@ -427,6 +453,7 @@ void NapiRand::DefineRandJSClass(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("generateRandom", NapiRand::JsGenerateRandom), DECLARE_NAPI_FUNCTION("generateRandomSync", NapiRand::JsGenerateRandomSync), DECLARE_NAPI_FUNCTION("setSeed", NapiRand::JsSetSeed), + DECLARE_NAPI_FUNCTION("enableHardwareEntropy", NapiRand::JsEnableHardwareEntropy), {.utf8name = "algName", .getter = NapiRand::JsGetAlgorithm}, }; napi_value constructor = nullptr; diff --git a/frameworks/native/src/crypto_rand.c b/frameworks/native/src/crypto_rand.c index 2f8dd873b07a51636be6ac257a67d63c90ee5146..53cb92c4f2a6c697d774822202dc25a005ab93e3 100644 --- a/frameworks/native/src/crypto_rand.c +++ b/frameworks/native/src/crypto_rand.c @@ -31,6 +31,8 @@ typedef struct OH_CryptoRand { HcfResult (*generateRandom)(HcfRand *self, int32_t numBytes, HcfBlob *random); HcfResult (*setSeed)(HcfRand *self, HcfBlob *seed); + + HcfResult (*enableHardwareEntropy)(HcfRand *self); } OH_CryptoRand; OH_Crypto_ErrCode OH_CryptoRand_Create(OH_CryptoRand **ctx) @@ -68,6 +70,15 @@ OH_Crypto_ErrCode OH_CryptoRand_SetSeed(OH_CryptoRand *ctx, Crypto_DataBlob *see return GetOhCryptoErrCodeNew(ret); } +OH_Crypto_ErrCode OH_CryptoRand_EnableHardwareEntropy(OH_CryptoRand *ctx) +{ + if ((ctx == NULL) || (ctx->enableHardwareEntropy == NULL)) { + return CRYPTO_PARAMETER_CHECK_FAILED; + } + HcfResult ret = ctx->enableHardwareEntropy((HcfRand *)ctx); + return GetOhCryptoErrCodeNew(ret); +} + void OH_CryptoRand_Destroy(OH_CryptoRand *ctx) { HcfObjDestroy((HcfRand *)ctx); diff --git a/frameworks/spi/rand_spi.h b/frameworks/spi/rand_spi.h index 166950f6b876dc85ecc864567f38f9a26513b94e..60c0d26d7b2e32ae1771e1f6d97f935e19fc0b9b 100644 --- a/frameworks/spi/rand_spi.h +++ b/frameworks/spi/rand_spi.h @@ -34,6 +34,8 @@ struct HcfRandSpi { HcfResult (*engineGenerateRandom)(HcfRandSpi *self, int32_t numBytes, HcfBlob *random); void (*engineSetSeed)(HcfRandSpi *self, HcfBlob *seed); + + HcfResult (*engineEnableHardwareEntropy)(HcfRandSpi *self); }; #endif \ No newline at end of file diff --git a/interfaces/inner_api/crypto_operation/rand.h b/interfaces/inner_api/crypto_operation/rand.h index 2f1c77f18f1c06c51b7e9b7fa54272fa15670d13..f801b17276fcc42f021e99b7d2cfcc701db8ce4b 100644 --- a/interfaces/inner_api/crypto_operation/rand.h +++ b/interfaces/inner_api/crypto_operation/rand.h @@ -32,6 +32,8 @@ struct HcfRand { HcfResult (*generateRandom)(HcfRand *self, int32_t numBytes, HcfBlob *random); HcfResult (*setSeed)(HcfRand *self, HcfBlob *seed); + + HcfResult (*enableHardwareEntropy)(HcfRand *self); }; #ifdef __cplusplus diff --git a/interfaces/kits/native/include/crypto_rand.h b/interfaces/kits/native/include/crypto_rand.h index 1e9a4f8e017aaaae3d68c722704b4ef00bfb1acd..9bb878c8158c259a1984d776cee174046454f207 100644 --- a/interfaces/kits/native/include/crypto_rand.h +++ b/interfaces/kits/native/include/crypto_rand.h @@ -98,6 +98,19 @@ const char *OH_CryptoRand_GetAlgoName(OH_CryptoRand *ctx); */ OH_Crypto_ErrCode OH_CryptoRand_SetSeed(OH_CryptoRand *ctx, Crypto_DataBlob *seed); +/** + * @brief Enables hardware entropy for the random number generator context. + * + * @param ctx Indicates the random number generator context. + * @return {@link OH_Crypto_ErrCode#CRYPTO_SUCCESS} 0 - If the operation is successful. + * {@link OH_Crypto_ErrCode#CRYPTO_NOT_SUPPORTED} 801 - If the operation is not supported. + * {@link OH_Crypto_ErrCode#CRYPTO_MEMORY_ERROR} 17620001 - If memory operation failed. + * {@link OH_Crypto_ErrCode#CRYPTO_PARAMETER_CHECK_FAILED} 17620003 - If parameter check failed. + * {@link OH_Crypto_ErrCode#CRYPTO_OPERTION_ERROR} 17630001 - If crypto operation failed. + * @since 21 + */ +OH_Crypto_ErrCode OH_CryptoRand_EnableHardwareEntropy(OH_CryptoRand *ctx); + /** * @brief Destroys the random number generator context. * diff --git a/plugin/BUILD.gn b/plugin/BUILD.gn index db5207f5cd0b111047d244af5972086dcf751c91..99a924274db0fff173d26094f12d73b647e17351 100644 --- a/plugin/BUILD.gn +++ b/plugin/BUILD.gn @@ -57,6 +57,7 @@ if (os_level == "standard") { external_deps = [ "c_utils:utils", "hilog:libhilog", + "huks:libhukssdk", "openssl:libcrypto_shared", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] diff --git a/plugin/openssl_plugin/common/inc/openssl_adapter.h b/plugin/openssl_plugin/common/inc/openssl_adapter.h index f830458b651c148fc5bff7698b0ba99dd219b8b3..fd7563386daa7c38d49e3d01a8ba7259c5be90e6 100644 --- a/plugin/openssl_plugin/common/inc/openssl_adapter.h +++ b/plugin/openssl_plugin/common/inc/openssl_adapter.h @@ -231,7 +231,8 @@ int OpensslBioWrite(BIO *b, const void *data, int dlen); int OpensslBioRead(BIO *b, void *data, int dlen); void OpensslBioFreeAll(BIO *a); -int OpensslRandPrivBytes(unsigned char *buf, int num); +int OpensslRandPrivBytesEx(OSSL_LIB_CTX *libCtx, unsigned char *buf, size_t num); +int OpensslRandSetSeedSourceType(OSSL_LIB_CTX *libCtx, const char *name, const char *proPq); void OpensslRandSeed(const void *buf, int num); const EVP_MD *OpensslEvpSha1(void); diff --git a/plugin/openssl_plugin/common/src/openssl_adapter.c b/plugin/openssl_plugin/common/src/openssl_adapter.c index f4ec918e71f389bc50f8ff5498fefd36844d05f0..1e6bbaed3ed159a69ba2c9e49a506b8989746f44 100644 --- a/plugin/openssl_plugin/common/src/openssl_adapter.c +++ b/plugin/openssl_plugin/common/src/openssl_adapter.c @@ -854,9 +854,14 @@ void OpensslBioFreeAll(BIO *a) BIO_free_all(a); } -int OpensslRandPrivBytes(unsigned char *buf, int num) +int OpensslRandPrivBytesEx(OSSL_LIB_CTX *libCtx, unsigned char *buf, size_t num) { - return RAND_priv_bytes(buf, num); + return RAND_priv_bytes_ex(libCtx, buf, num, 0); +} + +int OpensslRandSetSeedSourceType(OSSL_LIB_CTX *libCtx, const char *name, const char *proPq) +{ + return RAND_set_seed_source_type(libCtx, name, proPq); } void OpensslRandSeed(const void *buf, int num) diff --git a/plugin/openssl_plugin/crypto_operation/rand/inc/rand_hks_provider.h b/plugin/openssl_plugin/crypto_operation/rand/inc/rand_hks_provider.h new file mode 100644 index 0000000000000000000000000000000000000000..2544c9e786cba89c286324462f8f9d3813f45a5a --- /dev/null +++ b/plugin/openssl_plugin/crypto_operation/rand/inc/rand_hks_provider.h @@ -0,0 +1,27 @@ +/* + * 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_RAND_HKS_PROVIDER_H +#define HCF_RAND_HKS_PROVIDER_H + +#include +#include + +#define CRYPTO_SEED_PROVIDER "provider=crypto-hw" + +int32_t HcfCryptoLoadSeedProvider(OSSL_LIB_CTX *libCtx, OSSL_PROVIDER **seedProvider); +void HcfCryptoUnloadSeedProvider(OSSL_PROVIDER *seedProvider); + +#endif \ No newline at end of file diff --git a/plugin/openssl_plugin/crypto_operation/rand/src/rand_hks_provider.c b/plugin/openssl_plugin/crypto_operation/rand/src/rand_hks_provider.c new file mode 100644 index 0000000000000000000000000000000000000000..f7420c8a12f1eb4c1ad00dac023634e51933f996 --- /dev/null +++ b/plugin/openssl_plugin/crypto_operation/rand/src/rand_hks_provider.c @@ -0,0 +1,255 @@ +/* + * 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 "rand_hks_provider.h" +#include +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "memory.h" +#include "hks_api.h" + +#define MAX_REQUESTS 128 +#define STRENGTH 1024 +#define ENTROPY_RATE 7 +#define INCREASE_OFFSET 7 +#define HCF_OPENSSL_SUCCESS 1 +#define HCF_OPENSSL_FAILURE 0 + +typedef struct { + void *provCtx; + int state; +} CryptoProSeedSrc; + +static void *CryptoSeedSrcNew(void *provCtx, void *parent, const OSSL_DISPATCH *parentDispatch) +{ + (void)parentDispatch; + + if (parent != NULL) { + LOGE("parent is NULL"); + return NULL; + } + + CryptoProSeedSrc *seedSrc = (CryptoProSeedSrc *)HcfMalloc(sizeof(CryptoProSeedSrc), 0); + if (seedSrc == NULL) { + LOGE("Failed to allocate memory for seedSrc"); + return NULL; + } + + seedSrc->provCtx = provCtx; + seedSrc->state = EVP_RAND_STATE_UNINITIALISED; + + return seedSrc; +} + +static void CryptoSeedSrcFree(void *seedSrc) +{ + HcfFree(seedSrc); +} + +static int CryptoSeedSrcInstantiate(void *vSeed, unsigned int strength, int predictionResistance, + const unsigned char *pStr, uint32_t pStrLen, ossl_unused const OSSL_PARAM params[]) +{ + (void)strength; + (void)predictionResistance; + (void)pStr; + (void)pStrLen; + CryptoProSeedSrc *seedSrc = (CryptoProSeedSrc *)vSeed; + seedSrc->state = EVP_RAND_STATE_READY; + return HCF_OPENSSL_SUCCESS; +} + +static int CryptoSeedSrcUninstantiate(void *vSeed) +{ + CryptoProSeedSrc *seedSrc = (CryptoProSeedSrc *)vSeed; + seedSrc->state = EVP_RAND_STATE_UNINITIALISED; + return HCF_OPENSSL_SUCCESS; +} + +static int CryptoSeedSrcGenerate(void *vSeed, unsigned char *out, size_t outLen, unsigned int strength, + ossl_unused int predictionResistance, ossl_unused const unsigned char *addIn, size_t addInLen) +{ + (void)strength; + CryptoProSeedSrc *seedSrc = (CryptoProSeedSrc *)vSeed; + if (seedSrc->state != EVP_RAND_STATE_READY) { + LOGE("seedSrc is not ready"); + return HCF_OPENSSL_FAILURE; + } + + struct HksBlob randomBlob; + randomBlob.data = out; + randomBlob.size = (uint32_t)outLen; + int32_t result = HksGenerateRandom(NULL, &randomBlob); + if (result != 0) { + LOGE("HksGenerateRandom failed with error: %d", result); + return HCF_OPENSSL_FAILURE; + } + return HCF_OPENSSL_SUCCESS; +} + +static int CryptoSeedSrcReseed(void *vSeed, ossl_unused int predictionResistance, ossl_unused const unsigned char *ent, + ossl_unused size_t entLen, ossl_unused const unsigned char *addIn, ossl_unused size_t addInLen) +{ + CryptoProSeedSrc *seedSrc = (CryptoProSeedSrc *)vSeed; + if (seedSrc->state != EVP_RAND_STATE_READY) { + LOGE("seedSrc is not ready"); + return HCF_OPENSSL_FAILURE; + } + return HCF_OPENSSL_SUCCESS; +} + +static int CryptoSeedSrcGetCtxParams(void *vSeed, OSSL_PARAM params[]) +{ + CryptoProSeedSrc *seedSrc = (CryptoProSeedSrc *)vSeed; + OSSL_PARAM *p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST); + if (p != NULL && !OSSL_PARAM_set_size_t(p, MAX_REQUESTS)) { + LOGE("Failed to set max requests"); + return HCF_OPENSSL_FAILURE; + } + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH); + if (p != NULL && !OSSL_PARAM_set_size_t(p, STRENGTH)) { + LOGE("Failed to set strength"); + return HCF_OPENSSL_FAILURE; + } + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE); + if (p != NULL && !OSSL_PARAM_set_int(p, seedSrc->state)) { + LOGE("Failed to set state"); + return HCF_OPENSSL_FAILURE; + } + return HCF_OPENSSL_SUCCESS; +} + +static const OSSL_PARAM *CryptoSeedSrcGettableCtxParams(ossl_unused void *vSeed, ossl_unused void *provCtx) +{ + static const OSSL_PARAM params[] = { + OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL), + OSSL_PARAM_uint(OSSL_RAND_PARAM_MAX_REQUEST, NULL), + OSSL_PARAM_uint(OSSL_RAND_PARAM_STATE, NULL), + OSSL_PARAM_END + }; + return params; +} + +static int CryptoSeedSrcVerifyZeroization(ossl_unused void *vSeed) +{ + return HCF_OPENSSL_SUCCESS; +} + +static size_t CryptoSeedSrcGetSeed(void *vSeed, unsigned char **pOut, int entropy, size_t minLen, size_t maxLen, + int predictionResistance, const unsigned char *addIn, size_t addInLen) +{ + size_t bytesNeeded = entropy >= 0 ? ((size_t)entropy + INCREASE_OFFSET) / ENTROPY_RATE : 0; + if (bytesNeeded < minLen) { + bytesNeeded = minLen; + } + if (bytesNeeded > maxLen) { + LOGE("bytesNeeded is greater than maxLen"); + return 0; + } + unsigned char *p = (unsigned char *)HcfMalloc(bytesNeeded, 0); + if (p == NULL) { + LOGE("Failed to allocate memory for p"); + return 0; + } + if (CryptoSeedSrcGenerate(vSeed, p, bytesNeeded, 0, predictionResistance, addIn, addInLen) != 0) { + *pOut = p; + return bytesNeeded; + } + HcfFree(p); + return 0; +} + +static void CryptoSeedSrcClearSeed(ossl_unused void *vdrbg, unsigned char *out, size_t outLen) +{ + HcfFree(out); +} + +OSSL_DISPATCH g_cryptoOsslSeedRrcFunctions[] = { + { OSSL_FUNC_RAND_NEWCTX, (void (*)(void))CryptoSeedSrcNew }, + { OSSL_FUNC_RAND_FREECTX, (void (*)(void))CryptoSeedSrcFree }, + { OSSL_FUNC_RAND_INSTANTIATE, (void (*)(void))CryptoSeedSrcInstantiate }, + { OSSL_FUNC_RAND_UNINSTANTIATE, (void (*)(void))CryptoSeedSrcUninstantiate }, + { OSSL_FUNC_RAND_GENERATE, (void (*)(void))CryptoSeedSrcGenerate }, + { OSSL_FUNC_RAND_RESEED, (void (*)(void))CryptoSeedSrcReseed }, + { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void (*)(void))CryptoSeedSrcGetCtxParams }, + { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, (void (*)(void))CryptoSeedSrcGettableCtxParams }, + { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, (void (*)(void))CryptoSeedSrcVerifyZeroization }, + { OSSL_FUNC_RAND_GET_SEED, (void (*)(void))CryptoSeedSrcGetSeed }, + { OSSL_FUNC_RAND_CLEAR_SEED, (void (*)(void))CryptoSeedSrcClearSeed }, + { 0, NULL } +}; + +static const OSSL_ALGORITHM g_gmSeedRrc[] = { + { "HW-SEED-SRC", CRYPTO_SEED_PROVIDER, g_cryptoOsslSeedRrcFunctions, NULL}, + { NULL, NULL, NULL, NULL } +}; + +static const OSSL_ALGORITHM *CryptoSeedSrcRandSeedQuery(ossl_unused void *provCtx, int operationId, int *noCache) +{ + *noCache = 0; + if (operationId == OSSL_OP_RAND) { + return g_gmSeedRrc; + } + + return NULL; +} + +static const OSSL_DISPATCH RandSeedMethod[] = { + { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))CryptoSeedSrcRandSeedQuery }, + { 0, NULL } +}; + +static int CryptoSeedSrcSeedProviderInit(ossl_unused const OSSL_CORE_HANDLE *handle, + ossl_unused const OSSL_DISPATCH *in, const OSSL_DISPATCH **out, ossl_unused void **provCtx) +{ + *out = RandSeedMethod; + return HCF_OPENSSL_SUCCESS; +} + +int32_t HcfCryptoLoadSeedProvider(OSSL_LIB_CTX *libCtx, OSSL_PROVIDER **seedProvider) +{ + if (libCtx == NULL) { + LOGE("Invalid parameters"); + return HCF_OPENSSL_FAILURE; + } + + if (OSSL_PROVIDER_add_builtin(libCtx, CRYPTO_SEED_PROVIDER, CryptoSeedSrcSeedProviderInit) != 1) { + LOGE("Failed to add seed provider"); + return HCF_OPENSSL_FAILURE; + } + + *seedProvider = OSSL_PROVIDER_try_load(libCtx, CRYPTO_SEED_PROVIDER, 1); + if (*seedProvider == NULL) { + LOGE("Failed to load seed provider"); + return HCF_OPENSSL_FAILURE; + } + + return HCF_OPENSSL_SUCCESS; +} + +void HcfCryptoUnloadSeedProvider(OSSL_PROVIDER *seedProvider) +{ + if (seedProvider == NULL) { + return; + } + (void)OSSL_PROVIDER_unload(seedProvider); + seedProvider = NULL; +} diff --git a/plugin/openssl_plugin/crypto_operation/rand/src/rand_openssl.c b/plugin/openssl_plugin/crypto_operation/rand/src/rand_openssl.c index 78bb9691d9df582a6166a0fe03d9d4fa77112d35..da26a59eb33810ace8f52d62e3210a85593b891a 100644 --- a/plugin/openssl_plugin/crypto_operation/rand/src/rand_openssl.c +++ b/plugin/openssl_plugin/crypto_operation/rand/src/rand_openssl.c @@ -21,9 +21,13 @@ #include "log.h" #include "memory.h" #include "utils.h" +#include "rand_hks_provider.h" typedef struct { HcfRandSpi base; + bool isHardwareEntropyEnabled; + OSSL_LIB_CTX *libCtx; + OSSL_PROVIDER *seedProvider; } HcfRandSpiImpl; static const char *GetRandOpenSSLClass(void) @@ -33,32 +37,83 @@ static const char *GetRandOpenSSLClass(void) static HcfResult OpensslGenerateRandom(HcfRandSpi *self, int32_t numBytes, HcfBlob *random) { - if ((self == NULL) || (random == NULL)) { + if ((self == NULL) || (random == NULL) || (numBytes <= 0)) { LOGE("Invalid params!"); return HCF_INVALID_PARAMS; } - if (numBytes <= 0) { - LOGE("Invalid numBytes!"); - return HCF_INVALID_PARAMS; - } + random->data = (uint8_t *)HcfMalloc(numBytes, 0); if (random->data == NULL) { LOGE("Failed to allocate random->data memory!"); return HCF_ERR_MALLOC; } - int32_t ret = OpensslRandPrivBytes(random->data, numBytes); + + HcfRandSpiImpl *impl = (HcfRandSpiImpl *)self; + OSSL_LIB_CTX *libCtx = impl->isHardwareEntropyEnabled ? impl->libCtx : NULL; + + if (impl->isHardwareEntropyEnabled && impl->libCtx == NULL) { + LOGE("Hardware entropy enabled but libCtx is NULL"); + HcfBlobDataFree(random); + return HCF_ERR_PARAMETER_CHECK_FAILED; + } + + int32_t ret = OpensslRandPrivBytesEx(libCtx, random->data, numBytes); if (ret != HCF_OPENSSL_SUCCESS) { - LOGD("[error] RAND_bytes return error!"); - HcfFree(random->data); - random->data = NULL; - HcfPrintOpensslError(); + LOGE("Failed to generate random bytes with %s entropy", + impl->isHardwareEntropyEnabled ? "hardware" : "software"); + if (!impl->isHardwareEntropyEnabled) { + HcfPrintOpensslError(); + } + HcfBlobDataFree(random); return HCF_ERR_CRYPTO_OPERATION; } - + LOGD("Successfully generated %d random bytes with %s entropy", + numBytes, impl->isHardwareEntropyEnabled ? "hardware" : "software"); random->len = numBytes; return HCF_SUCCESS; } +static HcfResult EnableHardwareEntropy(HcfRandSpi *self) +{ + if (self == NULL) { + LOGE("Invalid input parameter."); + return HCF_ERR_PARAMETER_CHECK_FAILED; + } + + HcfRandSpiImpl *impl = (HcfRandSpiImpl *)self; + if (impl->isHardwareEntropyEnabled) { + LOGI("Hardware entropy is already enabled"); + return HCF_SUCCESS; + } + + impl->libCtx = OSSL_LIB_CTX_new(); + if (impl->libCtx == NULL) { + LOGE("Failed to create OSSL_LIB_CTX"); + return HCF_ERR_CRYPTO_OPERATION; + } + impl->seedProvider = NULL; + int32_t ret = HcfCryptoLoadSeedProvider(impl->libCtx, &impl->seedProvider); + if (ret != HCF_OPENSSL_SUCCESS) { + LOGE("Failed to load seed provider"); + OSSL_LIB_CTX_free(impl->libCtx); + impl->libCtx = NULL; + return HCF_ERR_CRYPTO_OPERATION; + } + + ret = OpensslRandSetSeedSourceType(impl->libCtx, "HW-SEED-SRC", CRYPTO_SEED_PROVIDER); + if (ret != HCF_OPENSSL_SUCCESS) { + LOGE("Failed to set seed source type"); + OSSL_LIB_CTX_free(impl->libCtx); + impl->libCtx = NULL; + HcfCryptoUnloadSeedProvider(impl->seedProvider); + return HCF_ERR_CRYPTO_OPERATION; + } + + impl->isHardwareEntropyEnabled = true; + LOGD("Hardware entropy enabled successfully"); + return HCF_SUCCESS; +} + static const char *GetRandAlgoName(HcfRandSpi *self) { if (self == NULL) { @@ -93,6 +148,16 @@ static void DestroyRandOpenssl(HcfObjectBase *self) LOGE("Class is not match."); return; } + + HcfRandSpiImpl *impl = (HcfRandSpiImpl *)self; + if (impl->isHardwareEntropyEnabled && impl->libCtx != NULL) { + OSSL_LIB_CTX_free(impl->libCtx); + impl->libCtx = NULL; + LOGD("Hardware entropy resources cleaned up"); + } + if (impl->seedProvider != NULL) { + HcfCryptoUnloadSeedProvider(impl->seedProvider); + } HcfFree(self); } @@ -112,6 +177,10 @@ HcfResult HcfRandSpiCreate(HcfRandSpi **spiObj) returnSpiImpl->base.engineGenerateRandom = OpensslGenerateRandom; returnSpiImpl->base.engineSetSeed = OpensslSetSeed; returnSpiImpl->base.engineGetAlgoName = GetRandAlgoName; + returnSpiImpl->base.engineEnableHardwareEntropy = EnableHardwareEntropy; + returnSpiImpl->isHardwareEntropyEnabled = false; + returnSpiImpl->libCtx = NULL; + returnSpiImpl->seedProvider = NULL; *spiObj = (HcfRandSpi *)returnSpiImpl; return HCF_SUCCESS; } \ No newline at end of file diff --git a/plugin/openssl_plugin/key/sym_key_generator/src/sym_key_openssl.c b/plugin/openssl_plugin/key/sym_key_generator/src/sym_key_openssl.c index ab72bfad9ec75fb187f9cec6a56db395931f67a4..a7713f3be47be8c3dee965573b8dbe2d154f9b5a 100644 --- a/plugin/openssl_plugin/key/sym_key_generator/src/sym_key_openssl.c +++ b/plugin/openssl_plugin/key/sym_key_generator/src/sym_key_openssl.c @@ -122,7 +122,7 @@ static HcfResult RandomSymmKey(int32_t keyLen, HcfBlob *symmKey) LOGE("keyMaterial malloc failed!"); return HCF_ERR_MALLOC; } - int ret = OpensslRandPrivBytes(keyMaterial, keyLen); + int ret = OpensslRandPrivBytesEx(NULL, keyMaterial, keyLen); if (ret != HCF_OPENSSL_SUCCESS) { LOGD("[error] RAND_bytes failed!"); HcfPrintOpensslError(); diff --git a/plugin/plugin.gni b/plugin/plugin.gni index c952c6e247f194b712d8e33716113ab06d54b8b6..87194ef19aaf3f9a3da646b99ee171708693bbda 100644 --- a/plugin/plugin.gni +++ b/plugin/plugin.gni @@ -82,8 +82,10 @@ plugin_cipher_files = [ plugin_hmac_files = [ "${plugin_path}/openssl_plugin/crypto_operation/hmac/src/mac_openssl.c" ] -plugin_rand_files = - [ "${plugin_path}/openssl_plugin/crypto_operation/rand/src/rand_openssl.c" ] +plugin_rand_files = [ + "${plugin_path}/openssl_plugin/crypto_operation/rand/src/rand_openssl.c", + "${plugin_path}/openssl_plugin/crypto_operation/rand/src/rand_hks_provider.c", +] plugin_md_files = [ "${plugin_path}/openssl_plugin/crypto_operation/md/src/md_openssl.c" ] diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index dc9bfb0e771a23daae63e04980fa6b2a83d61087..c12d1a0ceb626d9a771f9a6c77d479d2b3b21d6f 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -175,6 +175,7 @@ ohos_unittest("crypto_framework_test") { "bounds_checking_function:libsec_shared", "c_utils:utils", "hilog:libhilog", + "huks:libhukssdk", "openssl:libcrypto_shared", ] } diff --git a/test/unittest/src/crypto_rand_hardware_test.cpp b/test/unittest/src/crypto_rand_hardware_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00f47cd9460a790566d49bf99c9f0775500ebfb8 --- /dev/null +++ b/test/unittest/src/crypto_rand_hardware_test.cpp @@ -0,0 +1,150 @@ +/* + * 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 "rand.h" +#include "rand_openssl.h" + +#include "log.h" +#include "memory.h" + +using namespace std; +using namespace testing::ext; + +namespace { +class CryptoRandHardWareTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void CryptoRandHardWareTest::SetUpTestCase() {} +void CryptoRandHardWareTest::TearDownTestCase() {} + +void CryptoRandHardWareTest::SetUp() // add init here, this will be called before test. +{ +} + +void CryptoRandHardWareTest::TearDown() // add destroy here, this will be called when test case done. +{ +} + +HWTEST_F(CryptoRandHardWareTest, CryptoFrameworkRandGenerateTest001, TestSize.Level0) +{ + // create a rand obj + HcfRand *randObj = nullptr; + HcfResult ret = HcfRandCreate(&randObj); + ASSERT_EQ(ret, HCF_SUCCESS); + // preset params + int32_t randomLen = 0; + ret = randObj->enableHardwareEntropy(randObj); + EXPECT_EQ(ret, HCF_SUCCESS); + // define randomBlob and seedBlob + struct HcfBlob randomBlob = {0}; + // test generate random with length 0 + ret = randObj->generateRandom(randObj, randomLen, &randomBlob); + EXPECT_NE(ret, HCF_SUCCESS); + HcfObjDestroy(randObj); +} + +HWTEST_F(CryptoRandHardWareTest, CryptoFrameworkRandGenerateTest002, TestSize.Level0) +{ + // create a rand obj + HcfRand *randObj = nullptr; + HcfResult ret = HcfRandCreate(&randObj); + ASSERT_EQ(ret, HCF_SUCCESS); + ret = randObj->enableHardwareEntropy(randObj); + EXPECT_EQ(ret, HCF_SUCCESS); + // preset params + int32_t randomLen = 32; + // define randomBlob and seedBlob + struct HcfBlob randomBlob = {0}; + // test generate random + ret = randObj->generateRandom(randObj, randomLen, &randomBlob); + EXPECT_EQ(ret, HCF_SUCCESS); + // destroy the API obj and blob data + HcfBlobDataClearAndFree(&randomBlob); + HcfObjDestroy(randObj); +} + +HWTEST_F(CryptoRandHardWareTest, CryptoFrameworkRandGenerateTest003, TestSize.Level0) +{ + // create a rand obj + HcfRand *randObj = nullptr; + HcfResult ret = HcfRandCreate(&randObj); + ASSERT_EQ(ret, HCF_SUCCESS); + ret = randObj->enableHardwareEntropy(randObj); + EXPECT_EQ(ret, HCF_SUCCESS); + // preset params + int32_t randomLen = INT_MAX; + // define randomBlob and seedBlob + struct HcfBlob randomBlob = {0}; + // test generate random + (void)randObj->generateRandom(randObj, randomLen, &randomBlob); + // destroy the API obj and blob data + HcfBlobDataClearAndFree(&randomBlob); + HcfObjDestroy(randObj); +} + +HWTEST_F(CryptoRandHardWareTest, CryptoFrameworkSetSeedTest002, TestSize.Level0) +{ + // create a rand obj + HcfRand *randObj = nullptr; + HcfResult ret = HcfRandCreate(&randObj); + ASSERT_EQ(ret, HCF_SUCCESS); + ret = randObj->enableHardwareEntropy(randObj); + EXPECT_EQ(ret, HCF_SUCCESS); + // preset params + int32_t seedLen = 32; + // define randomBlob and seedBlob + struct HcfBlob seedBlob = { .data = nullptr, .len = 0 }; + // test generate seed + ret = randObj->generateRandom(randObj, seedLen, &seedBlob); + EXPECT_EQ(ret, HCF_SUCCESS); + // test set seed + ret = randObj->setSeed(randObj, &seedBlob); + EXPECT_EQ(ret, HCF_SUCCESS); + // destroy the API obj and blob data + HcfBlobDataClearAndFree(&seedBlob); + HcfObjDestroy(randObj); +} + +HWTEST_F(CryptoRandHardWareTest, CryptoFrameworkSetSeedTest003, TestSize.Level0) +{ + // create a rand obj + HcfRand *randObj = nullptr; + HcfResult ret = HcfRandCreate(&randObj); + ASSERT_EQ(ret, HCF_SUCCESS); + ret = randObj->enableHardwareEntropy(randObj); + EXPECT_EQ(ret, HCF_SUCCESS); + // preset params + int32_t seedLen = 1000; + // define randomBlob and seedBlob + struct HcfBlob seedBlob = { .data = nullptr, .len = 0 }; + // test generate seed + ret = randObj->generateRandom(randObj, seedLen, &seedBlob); + EXPECT_EQ(ret, HCF_SUCCESS); + // test set seed + ret = randObj->setSeed(randObj, &seedBlob); + EXPECT_EQ(ret, HCF_SUCCESS); + // destroy the API obj and blob data + HcfBlobDataClearAndFree(&seedBlob); + HcfObjDestroy(randObj); +} +} \ No newline at end of file diff --git a/test/unittest/src/openssl_adapter_mock.c b/test/unittest/src/openssl_adapter_mock.c index 3d18180a19e56d09c65756510646c713a9db7b5a..e37d960b516be2f1c7af90915031b8a24bac79d3 100644 --- a/test/unittest/src/openssl_adapter_mock.c +++ b/test/unittest/src/openssl_adapter_mock.c @@ -1234,12 +1234,20 @@ void OpensslBioFreeAll(BIO *a) } } -int OpensslRandPrivBytes(unsigned char *buf, int num) +int OpensslRandPrivBytesEx(OSSL_LIB_CTX *libCtx, unsigned char *buf, size_t num) { if (IsNeedMock()) { return -1; } - return RAND_priv_bytes(buf, num); + return RAND_priv_bytes_ex(libCtx, buf, num, 0); +} + +int OpensslRandSetSeedSourceType(OSSL_LIB_CTX *libCtx, const char *name, const char *propq) +{ + if (IsNeedMock()) { + return -1; + } + return RAND_set_seed_source_type(libCtx, name, propq); } void OpensslRandSeed(const void *buf, int num)