一、概述
因使用真随机数需要硬件支持,在硬件不支持时,我们需要通过软件来实现伪随机数生成器。根据NITS SP 800-90A的推荐,推荐的随机数生成为HASH_DRBG、HMAC_DRBG、CTR_DRBG。本文主要介绍如何通过mbedtls移植实现CTR_DRBG生成随机数。
二、 mbedtls简要介绍
MbedTLS是一个开源、可移植、易使用、可读性高的SSL库,实现了常所用的加解密算法、X.509证书操作以及TLS协议操作。MbedTLS各功能模块独立性高、耦合度低,可以通过配置宏定义进行功能裁剪,非常适合对空间和效率要求高的嵌入式系统。
三、实现
3.1 移植MbedTLS代码
移植自mbedTLS 2.16版本
为实现CTR_DRBG需拷贝如下文件
随后对config.h进行编辑,通过设置宏来选择启用哪些功能
config.h如下
#ifndef MBEDTLS_CONFIG_H
#define MBEDTLS_CONFIG_H
/* AES-256-CBC */
#define MBEDTLS_AES_C
#define MBEDTLS_AES_ROM_TABLES
/* CTR_DRBG*/
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ENTROPY_C
/*是否自定义熵源,若在windows和linux下可注释,则使用默认熵源*/
#define MBEDTLS_NO_PLATFORM_ENTROPY
// SHA-256
#define MBEDTLS_SHA256_C
#endif /* MBEDTLS_CONFIG_H */
common.h如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if defined(MBEDTLS_CONFIG_FILE)
#include MBEDTLS_CONFIG_FILE
#else
#include "mbedtls/config.h"
#endif
3.2 随机数生成器
3.2.1 添加熵源
若在windows和linux平台,mbedtls可使用默认熵源:
- linux:/dev/urandom
- windows:CryptGenRandom
否则,需提供熵源。如下是以时间戳为熵源的示例
int get_clock_for_entropy( void *data,unsigned char *output, size_t len, size_t *olen ) {
time_t now_time;
time(&now_time);
unsigned long timer = now_time;
((void) data);
*olen = 0;
if (len < sizeof(unsigned long))
return (0);
memcpy(output, &timer, sizeof(unsigned long));
*olen = sizeof(unsigned long);
return 0;
}
3.2.2 生成一个随机数
入参:
- random_number:一个unsigned char指针,用于存储最终生成的随机数
- random_length:生成的随机数长度
返回值:
- 0:成功
- -1:播种失败
- -2:随机数生成失败
int generate_one_random_by_ctr_drbg(unsigned char *random_number,size_t random_length){
mbedtls_ctr_drbg_context ctr_drbg_context;
mbedtls_entropy_context entropy_context;
//个性化初始值:用于初始化伪随机数生成器,可设置为任意值
const char *personalization = "RLOSLEFOS-DRBG-11";
memset(random_number,'\0',random_length);
mbedtls_entropy_init(&entropy_context);
mbedtls_ctr_drbg_init(&ctr_drbg_context);
//添加熵源
mbedtls_entropy_add_source(&entropy_context,get_clock_for_entropy,NULL,MBEDTLS_ENTROPY_MIN_PLATFORM,MBEDTLS_ENTROPY_SOURCE_STRONG);
//第一次播种,无TRNG作为种子
int result = mbedtls_ctr_drbg_seed(&ctr_drbg_context, mbedtls_entropy_func, &entropy_context, personalization,
strlen(personalization));
if(result != 0){
//播种失败
return -1;
}
result = mbedtls_ctr_drbg_random(&ctr_drbg_context,random_number,random_length);
if(result != 0 || random_number == NULL){
//随机数生成失败
return -2;
}
mbedtls_entropy_free(&entropy_context);
mbedtls_ctr_drbg_free(&ctr_drbg_context);
return 0;
}
3.2.3 生成多个随机数
3.2.3.1 初始化随机数生成器
int initialize_ctr_drbg(mbedtls_ctr_drbg_context *ctr_drbg_context){
mbedtls_entropy_context entropy_context;
//mbedtls_ctr_drbg_context ctr_drbg_context;
//个性化初始值:用于初始化伪随机数生成器,可设置为任意值
const char *personalization = "RLOSLEFOS-DRBG-11";
mbedtls_entropy_init(&entropy_context);
mbedtls_ctr_drbg_init(ctr_drbg_context);
//第一次播种,无TRNG作为种子
int result = mbedtls_ctr_drbg_seed(ctr_drbg_context, mbedtls_entropy_func, &entropy_context, personalization,
strlen(personalization));
if(result != 0){
//播种失败
return -2;
}
return 0;
}
3.2.3.2 产生一个随机数
每次调用产生一个随机数,若需要N个随机数,则调用N次
int generate_random_by_ctr_drbg(mbedtls_ctr_drbg_context *ctr_drbg_context, unsigned char *random_number){
if(ctr_drbg_context == NULL){
return -1;
}
int result = mbedtls_ctr_drbg_random(ctr_drbg_context,random_number,RANDOM_NUMBER_LENGTH);
if(result != 0){
return -2;
}
return 0;
}
3.2.3.3 清理环境
当使用完成后,需释放相关句柄
void ctr_drbg_free(mbedtls_ctr_drbg_context *ctr_drbg_context){
mbedtls_ctr_drbg_free(ctr_drbg_context);
}
3.3 获取一个随机数
如下即可获取一个32bits的随机数
int main() {
unsigned char random_number[4];
int result = generate_one_random_by_ctr_drbg(random_number,4);
if(result != 0){
printf("get random failed \n");
return -1;
}
printf("random hex:");
for(int t=0;t<4;t++){
printf("%02x", random_number[t]);
}
printf("\n");
return 0;
}