* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2012-2020. All rights reserved.
* Description: The random number generation module can be used in the security field,
* and it is implemented by referring to the good practices that the company has reviewed.
* Author: @CompanyNameTag
* Create: 2018-5-15
*/
#include "sha256/sha256.h"
#include "sec_random.h"
#if !CHIP_WS63 && !CHIP_WS53
#include "systick.h"
#include "securec.h"
#if defined(BUILD_APPLICATION_STANDARD) && !defined(LITEOS_ONETRACK)
#ifdef __LITEOS__
#include "los_hwi.h"
#endif
#else
#include "rtc.h"
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
static hrand_ctx g_ctx;
static uint32_t g_u_last_rand = 0;
Function implementation
*****************************************************************************/
void get_source_bytes(uint8_t *data, uint32_t len);
void get_source_bytes(uint8_t *data, uint32_t len)
{
uint32_t i;
uint32_t ul_delta = 0;
errno_t ret = EOK;
uint32_t ul_count = (len + 3) / 4;
for (i = 0; i < ul_count; i++) {
ul_delta = (uint32_t)uapi_systick_get_us();
#if defined(BUILD_APPLICATION_STANDARD) && !defined(LITEOS_ONETRACK)
ul_delta ^= osIntContGet();
#else
ul_delta ^= uapi_rtc_int_cnt_record_get(RTC_0);
#endif
if (i < ul_count - 1) {
ret = memcpy_s(data + i * 4, HASH_DIGEST_LENGTH - i * 4, (void *)&ul_delta, 4);
} else {
ret = memcpy_s(data + i * 4, HASH_DIGEST_LENGTH - i * 4, (void *)&ul_delta, len - i * 4);
}
if (ret != EOK) {
continue;
}
}
}
static void get_constinfo(uint8_t *buf, const uint8_t max_buf_len)
{
UNUSED(max_buf_len);
uint8_t auc_out_buf[SHA256_HASH_SIZE] = { 0 };
uint32_t u_last_rand = g_u_last_rand;
errno_t ret = EOK;
if (u_last_rand == 0) {
ret = memcpy_s(buf, DEFAULT_CONST_LEN, (uint8_t *)DEFAULT_CONST, DEFAULT_CONST_LEN);
} else {
sha256_hash((uint8_t *)(uintptr_t)u_last_rand, sizeof(u_last_rand), auc_out_buf, SHA256_HASH_SIZE);
ret = memcpy_s(buf, DEFAULT_CONST_LEN, auc_out_buf, DEFAULT_CONST_LEN);
}
if (ret != EOK) {
UNUSED(ret);
}
}
static void hrand_bytes(hrand_ctx *ctx, uint8_t *output, uint32_t output_len)
{
sha256_context_t hash;
uint8_t one = 1;
uint8_t two = 2;
uint8_t temp[HASH_DIGEST_LENGTH] = { 0 };
errno_t ret = EOK;
get_source_bytes(temp, 16);
sha256_init(&hash);
SHA256Update(&hash, &one, 1);
SHA256Update(&hash, temp, 16);
SHA256Update(&hash, ctx->v, POOL_LEN);
SHA256Update(&hash, ctx->c, POOL_LEN);
sha256_final(&hash, ctx->v, POOL_LEN);
if (output != NULL && output_len > 0) {
sha256_init(&hash);
SHA256Update(&hash, &two, 1);
SHA256Update(&hash, ctx->v, POOL_LEN);
sha256_final(&hash, temp, HASH_DIGEST_LENGTH);
output_len = (output_len > HASH_DIGEST_LENGTH) ? HASH_DIGEST_LENGTH : output_len;
ret = memcpy_s(output, output_len, temp, output_len);
if (ret != EOK) {
return;
}
g_u_last_rand = (uintptr_t)ctx->v;
}
}
static void hrand_init(hrand_ctx *ctx)
{
sha256_context_t hash;
uint8_t zero = 0;
uint8_t constbuf[DEFAULT_CONST_LEN] = { 0 };
get_constinfo(constbuf, sizeof(constbuf));
sha256_init(&hash);
SHA256Update(&hash, "Init", 4);
SHA256Update(&hash, constbuf, DEFAULT_CONST_LEN);
sha256_final(&hash, ctx->v, POOL_LEN);
sha256_init(&hash);
SHA256Update(&hash, &zero, 1);
SHA256Update(&hash, ctx->v, POOL_LEN);
sha256_final(&hash, ctx->c, POOL_LEN);
(void)hrand_bytes(ctx, 0, 0);
(void)hrand_bytes(ctx, 0, 0);
(void)hrand_bytes(ctx, 0, 0);
(void)hrand_bytes(ctx, 0, 0);
}
static uint32_t hrand_uint(hrand_ctx *ctx)
{
uint32_t ret = 0;
hrand_bytes(ctx, (uint8_t *)&ret, sizeof(ret));
return ret;
}
void init_rand(void)
{
hrand_init(&g_ctx);
}
uint32_t sec_rand(void)
{
uint32_t ret = hrand_uint(&g_ctx);
return ret;
}
uint32_t nsec_rand(void)
{
return (g_u_last_rand ^ ((uint32_t)(uapi_systick_get_us() + (uint32_t)rand())));
}
void sec_rand_bytes(uint8_t *output, uint32_t output_len)
{
hrand_bytes(&g_ctx, output, output_len);
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif