mbedTLS移植CTR_DRBG随机数算法

发布时间 2023-12-11 18:55:06作者: 辛勤搬砖的门卫

一、概述

因使用真随机数需要硬件支持,在硬件不支持时,我们需要通过软件来实现伪随机数生成器。根据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需拷贝如下文件
image

随后对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可使用默认熵源:

  1. linux:/dev/urandom
  2. 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 生成一个随机数

入参:

  1. random_number:一个unsigned char指针,用于存储最终生成的随机数
  2. random_length:生成的随机数长度

返回值:

  1. 0:成功
  2. -1:播种失败
  3. -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;
}

image