* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "hitls_build.h"
#if defined(HITLS_CRYPTO_EAL) && defined(HITLS_CRYPTO_DRBG)
#include <stdbool.h>
#include <string.h>
#include "crypt_eal_rand.h"
#include "crypt_errno.h"
#include "bsl_errno.h"
#include "bsl_sal.h"
#include "crypt_algid.h"
#include "crypt_drbg.h"
#ifdef HITLS_CRYPTO_MD
#include "eal_md_local.h"
#endif
#ifdef HITLS_CRYPTO_MAC
#include "eal_mac_local.h"
#endif
#ifdef HITLS_CRYPTO_CIPHER
#include "eal_cipher_local.h"
#endif
#include "eal_drbg_local.h"
#include "bsl_err_internal.h"
#include "crypt_types.h"
#include "crypt_utils.h"
#include "crypt_util_rand.h"
#include "crypt_entropy.h"
#include "eal_common.h"
#include "eal_entropy.h"
#include "sal_atomic.h"
#include "crypt_ealinit.h"
#ifdef HITLS_CRYPTO_PROVIDER
#include "crypt_eal_implprovider.h"
#include "crypt_eal_provider.h"
#include "crypt_provider.h"
#endif
#include "bsl_params.h"
#include "crypt_params_key.h"
#ifdef HITLS_CRYPTO_ENTROPY
static EAL_SeedDrbg g_seedDrbg = {HITLS_SEED_DRBG_INIT_RAND_ALG, NULL, NULL, {0}, {0}};
static BSL_SAL_ThreadLockHandle g_seedLock = NULL;
#endif
static CRYPT_EAL_RndCtx *EAL_RandNewDrbg(CRYPT_RAND_AlgId id, CRYPT_RandSeedMethod *seedMeth, void *seedCtx);
#define RETURN_RAND_LOCK(ctx, ret) \
do { \
(ret) = BSL_SAL_ThreadWriteLock(((ctx)->lock)); \
if ((ret) != BSL_SUCCESS) { \
BSL_ERR_PUSH_ERROR((ret)); \
return (ret); \
} \
} while (0)
#define RAND_UNLOCK(ctx) (void)BSL_SAL_ThreadUnlock(((ctx)->lock))
#if defined(HITLS_CRYPTO_RAND_CB)
static CRYPT_EAL_RandFunc g_rndFunc = NULL;
static CRYPT_EAL_RandFuncEx g_rndFuncEx = NULL;
#endif
static int32_t EAL_RandSetMeth(EAL_RandUnitaryMethod *meth, CRYPT_EAL_RndCtx *ctx)
{
EAL_RandUnitaryMethod *temp = BSL_SAL_Dump(meth, sizeof(EAL_RandUnitaryMethod));
if (temp == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return CRYPT_MEM_ALLOC_FAIL;
}
ctx->meth = temp;
return CRYPT_SUCCESS;
}
static void MethFreeCtx(CRYPT_EAL_RndCtx *ctx)
{
EAL_RandUnitaryMethod *meth = ctx->meth;
if (meth != NULL && meth->freeCtx != NULL) {
meth->freeCtx(ctx->ctx);
}
BSL_SAL_FREE(ctx->meth);
return;
}
#ifdef HITLS_CRYPTO_ENTROPY
int32_t EAL_SeedDrbgLockInit(void)
{
if (g_seedLock != NULL) {
return BSL_SUCCESS;
}
return BSL_SAL_ThreadLockNew(&g_seedLock);
}
void EAL_SeedDrbgLockDeInit(void)
{
if (g_seedLock == NULL) {
return;
}
BSL_SAL_ThreadLockFree(g_seedLock);
g_seedLock = NULL;
}
void EAL_SeedDrbgRandDeinit(CRYPT_EAL_RndCtx *rndCtx)
{
if (rndCtx == NULL) {
return;
}
rndCtx->working = false;
MethFreeCtx(rndCtx);
BSL_SAL_ThreadLockFree(rndCtx->lock);
BSL_SAL_FREE(rndCtx);
}
void EAL_SeedDrbgDeinit(bool isDefaultSeed)
{
if (!isDefaultSeed) {
return;
}
(void)BSL_SAL_ThreadWriteLock(g_seedLock);
int val = 0;
BSL_SAL_AtomicDownReferences(&(g_seedDrbg.references), &val);
if (val > 0) {
(void)BSL_SAL_ThreadUnlock(g_seedLock);
return;
}
if (g_seedDrbg.seed != NULL) {
EAL_SeedDrbgRandDeinit(g_seedDrbg.seed);
g_seedDrbg.seed = NULL;
CRYPT_EAL_SeedPoolFree(g_seedDrbg.seedCtx);
g_seedDrbg.seedCtx = NULL;
memset(&(g_seedDrbg.seedMeth), 0, sizeof(g_seedDrbg.seedMeth));
BSL_SAL_ReferencesFree(&(g_seedDrbg.references));
}
(void)BSL_SAL_ThreadUnlock(g_seedLock);
}
#endif
void EAL_RandDeinit(CRYPT_EAL_RndCtx *ctx)
{
if (ctx == NULL) {
return;
}
BSL_SAL_ThreadLockHandle lock = ctx->lock;
ctx->lock = NULL;
if (BSL_SAL_ThreadWriteLock(lock) != BSL_SUCCESS) {
MethFreeCtx(ctx);
BSL_SAL_ThreadLockFree(lock);
#ifdef HITLS_CRYPTO_ENTROPY
EAL_SeedDrbgDeinit(ctx->isDefaultSeed);
#endif
BSL_SAL_Free(ctx);
return;
}
ctx->working = false;
EAL_EVENT_REPORT(CRYPT_EVENT_ZERO, CRYPT_ALGO_RAND, ctx->id, CRYPT_SUCCESS);
MethFreeCtx(ctx);
(void)BSL_SAL_ThreadUnlock(lock);
BSL_SAL_ThreadLockFree(lock);
#ifdef HITLS_CRYPTO_ENTROPY
EAL_SeedDrbgDeinit(ctx->isDefaultSeed);
#endif
BSL_SAL_FREE(ctx);
return;
}
static int32_t CheckRndCtxState(CRYPT_EAL_RndCtx *ctx)
{
if (ctx->working == false) {
EAL_ERR_REPORT(CRYPT_EVENT_ERR, CRYPT_ALGO_RAND, ctx->id, CRYPT_EAL_ERR_RAND_NO_WORKING);
return CRYPT_EAL_ERR_RAND_NO_WORKING;
}
return CRYPT_SUCCESS;
}
#if defined(HITLS_CRYPTO_RAND_CB)
void CRYPT_EAL_SetRandCallBack(CRYPT_EAL_RandFunc func)
{
g_rndFunc = func;
CRYPT_RandRegist(func);
return;
}
void CRYPT_EAL_SetRandCallBackEx(CRYPT_EAL_RandFuncEx func)
{
g_rndFuncEx = func;
CRYPT_RandRegistEx(func);
return;
}
#endif
int32_t EAL_DrbgbytesWithAdin(CRYPT_EAL_RndCtx *ctx, uint8_t *byte, uint32_t len, uint8_t *addin,
uint32_t addinLen)
{
if (ctx == NULL || ctx->meth == NULL || ctx->meth->gen == NULL || byte == NULL || len == 0) {
EAL_ERR_REPORT(CRYPT_EVENT_ERR, CRYPT_ALGO_RAND, CRYPT_RAND_ALGID_MAX, CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
int32_t ret = BSL_SAL_ThreadWriteLock(ctx->lock);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
ret = CheckRndCtxState(ctx);
if (ret != CRYPT_SUCCESS) {
RAND_UNLOCK(ctx);
return ret;
}
ret = ctx->meth->gen(ctx->ctx, byte, len, addin, addinLen, NULL);
EAL_EVENT_REPORT((ret == CRYPT_SUCCESS) ? CRYPT_EVENT_RANDGEN : CRYPT_EVENT_ERR, CRYPT_ALGO_RAND, ctx->id, ret);
RAND_UNLOCK(ctx);
return ret;
}
int32_t EAL_DrbgSeedWithAdin(CRYPT_EAL_RndCtx *ctx, uint8_t *addin, uint32_t addinLen)
{
if (ctx == NULL || ctx->meth == NULL || ctx->meth->reSeed == NULL) {
EAL_ERR_REPORT(CRYPT_EVENT_ERR, CRYPT_ALGO_RAND, CRYPT_RAND_ALGID_MAX, CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
int32_t ret = BSL_SAL_ThreadWriteLock(ctx->lock);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
ret = CheckRndCtxState(ctx);
if (ret != CRYPT_SUCCESS) {
RAND_UNLOCK(ctx);
return ret;
}
ret = ctx->meth->reSeed(ctx->ctx, addin, addinLen, NULL);
if (ret != CRYPT_SUCCESS) {
EAL_ERR_REPORT(CRYPT_EVENT_ERR, CRYPT_ALGO_RAND, ctx->id, ret);
}
RAND_UNLOCK(ctx);
return ret;
}
void EAL_RandDrbgFree(void *ctx)
{
if (ctx == NULL) {
return;
}
DRBG_Ctx *drbg = (DRBG_Ctx *)ctx;
DRBG_Free(drbg);
return;
}
#ifdef HITLS_CRYPTO_ENTROPY
static int32_t GetSeedDrbgEntropy(void *ctx, CRYPT_Data *entropy, uint32_t strength, CRYPT_Range *lenRange)
{
CRYPT_EAL_RndCtx *seed = (CRYPT_EAL_RndCtx *)ctx;
uint32_t strengthBytes = (strength + 7) / 8;
entropy->len = ((strengthBytes > lenRange->min) ? strengthBytes : lenRange->min);
if (entropy->len > lenRange->max) {
BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_RANGE_ERROR);
return CRYPT_ENTROPY_RANGE_ERROR;
}
entropy->data = BSL_SAL_Malloc(entropy->len);
if (entropy->data == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return CRYPT_MEM_ALLOC_FAIL;
}
int32_t ret = EAL_DrbgbytesWithAdin(seed, entropy->data, entropy->len, NULL, 0);
if (ret != CRYPT_SUCCESS) {
BSL_SAL_FREE(entropy->data);
}
return ret;
}
static void CleanSeedDrbgEntropy(void *ctx, CRYPT_Data *entropy)
{
(void)ctx;
BSL_SAL_CleanseData(entropy->data, entropy->len);
BSL_SAL_FREE(entropy->data);
}
void EAL_SeedDrbgEntropyMeth(CRYPT_RandSeedMethod *meth)
{
meth->getEntropy = GetSeedDrbgEntropy;
meth->cleanEntropy = CleanSeedDrbgEntropy;
meth->cleanNonce = CleanSeedDrbgEntropy;
meth->getNonce = GetSeedDrbgEntropy;
}
static int32_t SetSeedDrbgReseedInfo(CRYPT_EAL_RndCtx *rndCtx)
{
int32_t ret;
#if defined(HITLS_CRYPTO_DRBG_GM)
if (g_seedDrbg.id == CRYPT_RAND_SM3 || g_seedDrbg.id == CRYPT_RAND_SM4_CTR_DF) {
uint32_t gmLevel = 2;
ret = rndCtx->meth->ctrl(rndCtx->ctx, CRYPT_CTRL_SET_GM_LEVEL, &gmLevel, sizeof(uint32_t));
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
}
return ret;
}
#endif
uint32_t reseedInterval = DRBG_RESEED_INTERVAL;
ret = rndCtx->meth->ctrl(rndCtx->ctx, CRYPT_CTRL_SET_RESEED_INTERVAL, &reseedInterval, sizeof(uint32_t));
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
}
return ret;
}
int32_t EAL_SeedDrbgInit(EAL_SeedDrbg *seedDrbg)
{
CRYPT_RandSeedMethod seedMethond = {0};
int32_t ret = EAL_SetDefaultEntropyMeth(&seedMethond);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
CRYPT_EAL_SeedPoolCtx *seedPoolCtx = CRYPT_EAL_SeedPoolNew(false);
if (seedPoolCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_NEW_ERROR);
return CRYPT_SEED_POOL_NEW_ERROR;
}
CRYPT_EAL_RndCtx *rndCtx = EAL_RandNewDrbg(seedDrbg->id, &seedMethond, seedPoolCtx);
if (rndCtx == NULL) {
ret = CRYPT_MEM_ALLOC_FAIL;
BSL_ERR_PUSH_ERROR(ret);
goto EXIT;
}
ret = SetSeedDrbgReseedInfo(rndCtx);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
goto EXIT;
}
ret = rndCtx->meth->inst(rndCtx->ctx, NULL, 0, NULL);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
goto EXIT;
}
rndCtx->working = true;
seedDrbg->seed = rndCtx;
seedDrbg->seedMeth = seedMethond;
seedDrbg->seedCtx = seedPoolCtx;
BSL_SAL_ReferencesInit(&(seedDrbg->references));
return CRYPT_SUCCESS;
EXIT:
CRYPT_EAL_SeedPoolFree(seedPoolCtx);
EAL_RandDeinit(rndCtx);
return ret;
}
int32_t EAL_GetDefaultSeed(CRYPT_RandSeedMethod *seedMeth, void **seedCtx)
{
EAL_SeedDrbgEntropyMeth(seedMeth);
(void)BSL_SAL_ThreadWriteLock(g_seedLock);
if (g_seedDrbg.seed != NULL) {
*seedCtx = g_seedDrbg.seed;
int val = 0;
BSL_SAL_AtomicUpReferences(&(g_seedDrbg.references), &val);
(void)BSL_SAL_ThreadUnlock(g_seedLock);
return CRYPT_SUCCESS;
}
int32_t ret = EAL_SeedDrbgInit(&g_seedDrbg);
if (ret != CRYPT_SUCCESS) {
(void)BSL_SAL_ThreadUnlock(g_seedLock);
return CRYPT_EAL_ERR_DRBG_INIT_FAIL;
}
*seedCtx = g_seedDrbg.seed;
(void)BSL_SAL_ThreadUnlock(g_seedLock);
return CRYPT_SUCCESS;
}
#endif
static CRYPT_EAL_RndCtx *EAL_RandNewDrbg(CRYPT_RAND_AlgId id, CRYPT_RandSeedMethod *seedMeth,
void *seedCtx)
{
#ifdef HITLS_CRYPTO_ASM_CHECK
if (CRYPT_ASMCAP_Drbg(id) != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(CRYPT_EAL_ALG_ASM_NOT_SUPPORT);
return NULL;
}
#endif
CRYPT_RandSeedMethod seedMethTmp = {0};
CRYPT_RandSeedMethod *seedMethond = seedMeth;
EAL_RandUnitaryMethod *meth = NULL;
void *seedTmp = NULL;
int32_t ret;
CRYPT_EAL_RndCtx *randCtx = (CRYPT_EAL_RndCtx *)BSL_SAL_Calloc(1, sizeof(CRYPT_EAL_RndCtx));
if (randCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return NULL;
}
randCtx->isDefaultSeed = false;
if (seedMeth == NULL || seedMeth->getEntropy == NULL) {
#ifdef HITLS_CRYPTO_ENTROPY
ret = EAL_GetDefaultSeed(&seedMethTmp, &seedTmp);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
goto ERR;
}
seedCtx = seedTmp;
seedMethond = &seedMethTmp;
randCtx->isDefaultSeed = true;
#else
(void)seedMethTmp;
(void)seedTmp;
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
goto ERR;
#endif
}
meth = EAL_RandGetMethod();
ret = BSL_SAL_ThreadLockNew(&(randCtx->lock));
if (ret != CRYPT_SUCCESS) {
goto ERR;
}
randCtx->isProvider = false;
randCtx->working = false;
randCtx->id = id;
ret = EAL_RandSetMeth(meth, randCtx);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
goto ERR;
}
randCtx->ctx = meth->newCtx(NULL, id, seedMethond, seedCtx);
if (randCtx->ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_EAL_ERR_DRBG_INIT_FAIL);
goto ERR;
}
return randCtx;
ERR:
EAL_RandDeinit(randCtx);
return NULL;
}
#ifdef HITLS_CRYPTO_DRBG
static CRYPT_EAL_RndCtx *g_globalRndCtx = NULL;
static int32_t DrbgParaIsValid(CRYPT_RAND_AlgId id, const CRYPT_RandSeedMethod *seedMeth, const void *seedCtx,
const uint8_t *pers, uint32_t persLen)
{
if (DRBG_GetIdMap(id) == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_EAL_ERR_ALGID);
return CRYPT_EAL_ERR_ALGID;
}
if (seedMeth == NULL && seedCtx != NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
if (pers == NULL && persLen != 0) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
if (seedMeth != NULL && seedMeth->getEntropy == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
return CRYPT_SUCCESS;
}
int32_t CRYPT_EAL_RandInit(CRYPT_RAND_AlgId id, CRYPT_RandSeedMethod *seedMeth, void *seedCtx,
const uint8_t *pers, uint32_t persLen)
{
CRYPT_EAL_RndCtx *ctx = NULL;
if (g_globalRndCtx != NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_EAL_ERR_DRBG_REPEAT_INIT);
return CRYPT_EAL_ERR_DRBG_REPEAT_INIT;
}
int32_t ret = DrbgParaIsValid(id, seedMeth, seedCtx, pers, persLen);
if (ret != CRYPT_SUCCESS) {
return ret;
}
ctx = EAL_RandNewDrbg(id, seedMeth, seedCtx);
if (ctx == NULL) {
EAL_ERR_REPORT(CRYPT_EVENT_ERR, CRYPT_ALGO_RAND, id, CRYPT_EAL_ERR_DRBG_INIT_FAIL);
return CRYPT_EAL_ERR_DRBG_INIT_FAIL;
}
ret = CRYPT_EAL_DrbgInstantiate(ctx, pers, persLen);
if (ret != CRYPT_SUCCESS) {
EAL_RandDeinit(ctx);
return ret;
}
CRYPT_RandRegist(CRYPT_EAL_Randbytes);
g_globalRndCtx = ctx;
return CRYPT_SUCCESS;
}
int32_t CRYPT_EAL_RandbytesWithAdin(uint8_t *byte, uint32_t len, uint8_t *addin, uint32_t addinLen)
{
if (g_globalRndCtx == NULL) {
EAL_ERR_REPORT(CRYPT_EVENT_ERR, CRYPT_ALGO_RAND, CRYPT_RAND_ALGID_MAX, CRYPT_EAL_ERR_GLOBAL_DRBG_NULL);
return CRYPT_EAL_ERR_GLOBAL_DRBG_NULL;
}
return EAL_DrbgbytesWithAdin(g_globalRndCtx, byte, len, addin, addinLen);
}
int32_t CRYPT_EAL_Randbytes(uint8_t *byte, uint32_t len)
{
#if defined(HITLS_CRYPTO_RAND_CB)
if (g_rndFunc != NULL) {
return g_rndFunc(byte, len);
}
#endif
return CRYPT_EAL_RandbytesWithAdin(byte, len, NULL, 0);
}
int32_t CRYPT_EAL_RandSeedWithAdin(uint8_t *addin, uint32_t addinLen)
{
if (g_globalRndCtx == NULL) {
EAL_ERR_REPORT(CRYPT_EVENT_ERR, CRYPT_ALGO_RAND, CRYPT_RAND_ALGID_MAX, CRYPT_EAL_ERR_GLOBAL_DRBG_NULL);
return CRYPT_EAL_ERR_GLOBAL_DRBG_NULL;
}
return EAL_DrbgSeedWithAdin(g_globalRndCtx, addin, addinLen);
}
int32_t CRYPT_EAL_RandSeed(void)
{
return CRYPT_EAL_RandSeedWithAdin(NULL, 0);
}
bool CRYPT_EAL_RandIsValidAlgId(CRYPT_RAND_AlgId id)
{
return (DRBG_GetIdMap(id) != NULL);
}
#endif
int32_t CRYPT_EAL_DrbgInstantiate(CRYPT_EAL_RndCtx *rndCtx, const uint8_t *pers, uint32_t persLen)
{
int32_t ret;
if (rndCtx == NULL || rndCtx->meth == NULL || rndCtx->meth->inst == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
RETURN_RAND_LOCK(rndCtx, ret);
ret = rndCtx->meth->inst(rndCtx->ctx, pers, persLen, NULL);
if (ret != CRYPT_SUCCESS) {
RAND_UNLOCK(rndCtx);
return ret;
}
rndCtx->working = true;
RAND_UNLOCK(rndCtx);
return ret;
}
CRYPT_EAL_RndCtx *CRYPT_EAL_DrbgNew(CRYPT_RAND_AlgId id, CRYPT_RandSeedMethod *seedMeth, void *seedCtx)
{
if (seedMeth == NULL && seedCtx != NULL) {
EAL_ERR_REPORT(CRYPT_EVENT_ERR, CRYPT_ALGO_RAND, id, CRYPT_NULL_INPUT);
return NULL;
}
return EAL_RandNewDrbg(id, seedMeth, seedCtx);
}
int32_t CRYPT_EAL_DrbgSeedWithAdin(CRYPT_EAL_RndCtx *ctx, uint8_t *addin, uint32_t addinLen)
{
return EAL_DrbgSeedWithAdin(ctx, addin, addinLen);
}
int32_t CRYPT_EAL_DrbgSeed(CRYPT_EAL_RndCtx *ctx)
{
return CRYPT_EAL_DrbgSeedWithAdin(ctx, NULL, 0);
}
int32_t CRYPT_EAL_DrbgbytesWithAdin(CRYPT_EAL_RndCtx *ctx, uint8_t *byte, uint32_t len, uint8_t *addin,
uint32_t addinLen)
{
return EAL_DrbgbytesWithAdin(ctx, byte, len, addin, addinLen);
}
int32_t CRYPT_EAL_Drbgbytes(CRYPT_EAL_RndCtx *ctx, uint8_t *byte, uint32_t len)
{
return CRYPT_EAL_DrbgbytesWithAdin(ctx, byte, len, NULL, 0);
}
void CRYPT_EAL_DrbgDeinit(CRYPT_EAL_RndCtx *ctx)
{
EAL_RandDeinit(ctx);
return;
}
CRYPT_EAL_RndCtx *CRYPT_EAL_GetSeedCtx(bool isParentEntropy)
{
if (isParentEntropy) {
#ifdef HITLS_CRYPTO_ENTROPY
return g_seedDrbg.seed;
#else
return NULL;
#endif
}
return g_globalRndCtx;
}
static int32_t GetDRBGWorkingStatus(CRYPT_EAL_RndCtx *ctx, void *val, uint32_t len)
{
RETURN_RET_IF(val == NULL, CRYPT_NULL_INPUT);
RETURN_RET_IF(len != sizeof(uint32_t), CRYPT_INVALID_ARG);
*(uint32_t *)val = (uint32_t)(ctx->working);
return CRYPT_SUCCESS;
}
int32_t CRYPT_EAL_DrbgCtrl(CRYPT_EAL_RndCtx *rndCtx, int32_t opt, void *val, uint32_t len)
{
if (rndCtx == NULL || rndCtx->meth == NULL || rndCtx->meth->ctrl == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
if (opt == CRYPT_CTRL_GET_WORKING_STATUS) {
return GetDRBGWorkingStatus(rndCtx, val, len);
}
int32_t ret;
RETURN_RAND_LOCK(rndCtx, ret);
if (rndCtx->working == true) {
RAND_UNLOCK(rndCtx);
BSL_ERR_PUSH_ERROR(CRYPT_EAL_ERR_RAND_WORKING);
return CRYPT_EAL_ERR_RAND_WORKING;
}
ret = rndCtx->meth->ctrl(rndCtx->ctx, opt, val, len);
RAND_UNLOCK(rndCtx);
return ret;
}
#ifdef HITLS_CRYPTO_PROVIDER
int32_t CRYPT_EAL_SetRandMethod(CRYPT_EAL_RndCtx *ctx, const CRYPT_EAL_Func *funcs)
{
int32_t index = 0;
EAL_RandUnitaryMethod *method = BSL_SAL_Calloc(1, sizeof(EAL_RandUnitaryMethod));
if (method == NULL) {
BSL_ERR_PUSH_ERROR(BSL_MALLOC_FAIL);
return BSL_MALLOC_FAIL;
}
while (funcs[index].id != 0) {
switch (funcs[index].id) {
case CRYPT_EAL_IMPLRAND_DRBGNEWCTX:
method->provNewCtx = funcs[index].func;
break;
case CRYPT_EAL_IMPLRAND_DRBGINST:
method->inst = funcs[index].func;
break;
case CRYPT_EAL_IMPLRAND_DRBGUNINST:
method->unInst = funcs[index].func;
break;
case CRYPT_EAL_IMPLRAND_DRBGGEN:
method->gen = funcs[index].func;
break;
case CRYPT_EAL_IMPLRAND_DRBGRESEED:
method->reSeed = funcs[index].func;
break;
case CRYPT_EAL_IMPLRAND_DRBGCTRL:
method->ctrl = funcs[index].func;
break;
case CRYPT_EAL_IMPLRAND_DRBGFREECTX:
method->freeCtx = funcs[index].func;
break;
default:
BSL_SAL_Free(method);
BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_ERR_UNEXPECTED_IMPL);
return CRYPT_PROVIDER_ERR_UNEXPECTED_IMPL;
}
index++;
}
ctx->meth = method;
return CRYPT_SUCCESS;
}
static CRYPT_EAL_RndCtx *EAL_ProvRandInitDrbg(CRYPT_EAL_LibCtx *libCtx, CRYPT_RAND_AlgId id,
const char *attrName, BSL_Param *param)
{
const CRYPT_EAL_Func *funcs = NULL;
void *provCtx = NULL;
int32_t ret = CRYPT_EAL_ProviderGetFuncs(libCtx, CRYPT_EAL_OPERAID_RAND, id, attrName,
&funcs, &provCtx);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
return NULL;
}
CRYPT_EAL_RndCtx *randCtx = BSL_SAL_Calloc(1, sizeof(CRYPT_EAL_RndCtx));
if (randCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return NULL;
}
ret = BSL_SAL_ThreadLockNew(&(randCtx->lock));
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
BSL_SAL_FREE(randCtx);
return NULL;
}
randCtx->isDefaultSeed = false;
randCtx->isProvider = true;
randCtx->working = false;
randCtx->id = id;
ret = CRYPT_EAL_SetRandMethod(randCtx, funcs);
if (ret != CRYPT_SUCCESS) {
goto ERR;
}
if (randCtx->meth->provNewCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
goto ERR;
}
randCtx->ctx = randCtx->meth->provNewCtx(provCtx, id, param);
if (randCtx->ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_EAL_ERR_DRBG_INIT_FAIL);
goto ERR;
}
return randCtx;
ERR:
BSL_SAL_ThreadLockFree(randCtx->lock);
BSL_SAL_FREE(randCtx->meth);
BSL_SAL_FREE(randCtx);
return NULL;
}
CRYPT_EAL_RndCtx *CRYPT_EAL_ProviderDrbgNewCtx(CRYPT_EAL_LibCtx *libCtx, int32_t algId, const char *attrName,
BSL_Param *param)
{
return EAL_ProvRandInitDrbg(libCtx, algId, attrName, param);
}
int32_t CRYPT_EAL_ProviderRandInitCtxInner(CRYPT_EAL_LibCtx *libCtx, int32_t algId, const char *attrName,
const uint8_t *pers, uint32_t persLen, BSL_Param *param)
{
CRYPT_EAL_RndCtx *ctx = NULL;
CRYPT_EAL_LibCtx *localLibCtx = GetCurrentProviderLibCtx(libCtx);
if (localLibCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_INVALID_LIB_CTX);
return CRYPT_PROVIDER_INVALID_LIB_CTX;
}
if (localLibCtx->drbg != NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_EAL_ERR_DRBG_REPEAT_INIT);
return CRYPT_EAL_ERR_DRBG_REPEAT_INIT;
}
ctx = EAL_ProvRandInitDrbg(libCtx, algId, attrName, param);
if (ctx == NULL) {
EAL_ERR_REPORT(CRYPT_EVENT_ERR, CRYPT_ALGO_RAND, algId, CRYPT_EAL_ERR_DRBG_INIT_FAIL);
return CRYPT_EAL_ERR_DRBG_INIT_FAIL;
}
if (ctx->meth->inst == NULL) {
EAL_RandDeinit(ctx);
return CRYPT_EAL_ERR_DRBG_INIT_FAIL;
}
int32_t ret = ctx->meth->inst(ctx->ctx, pers, persLen, param);
if (ret != CRYPT_SUCCESS) {
EAL_RandDeinit(ctx);
return ret;
}
ctx->working = true;
CRYPT_RandRegist(CRYPT_EAL_Randbytes);
CRYPT_RandRegistEx((CRYPT_EAL_RandFuncEx)CRYPT_EAL_RandbytesEx);
localLibCtx->drbg = ctx;
return CRYPT_SUCCESS;
}
#endif
int32_t CRYPT_EAL_NoProviderRandInitCtxInner(int32_t algId,
const uint8_t *pers, uint32_t persLen, BSL_Param *param)
{
CRYPT_RandSeedMethod seedMeth = {0};
void *seedCtx = NULL;
const BSL_Param *temp = NULL;
int32_t ret;
bool hasEnt = false;
if ((temp = EAL_FindParam(param, CRYPT_PARAM_RAND_SEED_GETENTROPY)) != NULL) {
seedMeth.getEntropy = temp->value;
hasEnt = true;
}
if ((temp = EAL_FindParam(param, CRYPT_PARAM_RAND_SEED_CLEANENTROPY)) != NULL) {
seedMeth.cleanEntropy = temp->value;
hasEnt = true;
}
if ((temp = EAL_FindParam(param, CRYPT_PARAM_RAND_SEED_GETNONCE)) != NULL) {
seedMeth.getNonce = temp->value;
hasEnt = true;
}
if ((temp = EAL_FindParam(param, CRYPT_PARAM_RAND_SEED_CLEANNONCE)) != NULL) {
seedMeth.cleanNonce = temp->value;
hasEnt = true;
}
if ((temp = EAL_FindParam(param, CRYPT_PARAM_RAND_SEEDCTX)) != NULL) {
seedCtx = temp->value;
}
if (hasEnt) {
ret = CRYPT_EAL_RandInit(algId, &seedMeth, seedCtx, pers, persLen);
} else {
ret = CRYPT_EAL_RandInit(algId, NULL, seedCtx, pers, persLen);
}
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
}
return ret;
}
int32_t CRYPT_EAL_ProviderRandInitCtx(CRYPT_EAL_LibCtx *libCtx, int32_t algId, const char *attrName,
const uint8_t *pers, uint32_t persLen, BSL_Param *param)
{
#ifdef HITLS_CRYPTO_PROVIDER
return CRYPT_EAL_ProviderRandInitCtxInner(libCtx, algId, attrName, pers, persLen, param);
#else
(void) libCtx;
(void) attrName;
return CRYPT_EAL_NoProviderRandInitCtxInner(algId, pers, persLen, param);
#endif
}
void CRYPT_EAL_RandDeinitEx(CRYPT_EAL_LibCtx *libCtx)
{
#ifdef HITLS_CRYPTO_PROVIDER
CRYPT_EAL_LibCtx *localLibCtx = libCtx;
if (localLibCtx == NULL) {
localLibCtx = CRYPT_EAL_GetGlobalLibCtx();
}
if (localLibCtx == NULL) {
return;
}
EAL_RandDeinit(localLibCtx->drbg);
localLibCtx->drbg = NULL;
return;
#else
(void) libCtx;
CRYPT_EAL_RandDeinit();
return;
#endif
}
void CRYPT_EAL_RandDeinit(void)
{
EAL_RandDeinit(g_globalRndCtx);
g_globalRndCtx = NULL;
CRYPT_RandRegist(NULL);
return;
}
#ifdef HITLS_CRYPTO_PROVIDER
int32_t CRYPT_EAL_RandbytesWithAdinEx(CRYPT_EAL_LibCtx *libCtx,
uint8_t *byte, uint32_t len, uint8_t *addin, uint32_t addinLen)
{
CRYPT_EAL_LibCtx *localCtx = libCtx;
if (localCtx == NULL) {
localCtx = CRYPT_EAL_GetGlobalLibCtx();
}
if (localCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_INVALID_LIB_CTX);
return CRYPT_PROVIDER_INVALID_LIB_CTX;
}
return EAL_DrbgbytesWithAdin((CRYPT_EAL_RndCtx *)localCtx->drbg, byte, len, addin, addinLen);
}
#endif
int32_t CRYPT_EAL_RandbytesEx(CRYPT_EAL_LibCtx *libCtx, uint8_t *byte, uint32_t len)
{
#ifdef HITLS_CRYPTO_PROVIDER
CRYPT_EAL_LibCtx *localCtx = libCtx;
if (localCtx == NULL) {
localCtx = CRYPT_EAL_GetGlobalLibCtx();
}
if (localCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_INVALID_LIB_CTX);
return CRYPT_PROVIDER_INVALID_LIB_CTX;
}
return EAL_DrbgbytesWithAdin((CRYPT_EAL_RndCtx *)localCtx->drbg, byte, len, NULL, 0);
#else
(void) libCtx;
return CRYPT_EAL_Randbytes(byte, len);
#endif
}
int32_t CRYPT_EAL_RandSeedEx(CRYPT_EAL_LibCtx *libCtx)
{
#ifdef HITLS_CRYPTO_PROVIDER
CRYPT_EAL_LibCtx *tempLibCtx = libCtx;
if (tempLibCtx == NULL) {
tempLibCtx = CRYPT_EAL_GetGlobalLibCtx();
}
if (tempLibCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_INVALID_LIB_CTX);
return CRYPT_PROVIDER_INVALID_LIB_CTX;
}
return EAL_DrbgSeedWithAdin((CRYPT_EAL_RndCtx *)tempLibCtx->drbg, NULL, 0);
#else
(void) libCtx;
return CRYPT_EAL_RandSeed();
#endif
}
#endif