欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

mbedtls | 02 - 伪随机数发生器(ctr_drbg)的配置和使用

最编程 2024-03-05 10:47:58
...


mbedtls系列文章

  • ​mbedtls | 01 - 移植mbedtls库到STM32的两种方法​


文章目录


  • ​mbedtls系列文章​
  • ​一、真随机数和伪随机数​

  • ​1. 区别​
  • ​2. 伪随机数生成算法​

  • ​二、自定义熵源接口​

  • ​1. 开启宏定义​
  • ​2. 自定义实现mbedtls_hardware_poll函数​

  • ​三、使用mbedtls CTR_DRBG接口生成随机数​

  • ​1. 宏配置​
  • ​2. API说明​

    • ​2.1. 熵相关(entropy)​
    • ​2.2. ctr_drbg相关​

  • ​3. 编写测试代码​
  • ​4. 调用测试代码​
  • ​5. 测试结果​



一、真随机数和伪随机数

1. 区别

随机数在安全技术中通常被用于生成随机序列(eg. 秘钥),对于一个随机数的生成而言,是否真正的做到“随机”是最重要的。

真随机数通常来源于硬件随机数生成器,每次生成的随机数都是真正的随机数,但是因为物理因素,生成的时间较慢。比如STM32中提供的RNG硬件外设。

伪随机数通常来源于某个生成算法,每次生成的随机数虽然是随机的,但还是遵循生成算法的规则,优点是生成速度较快。比如C库中提供的rand函数,在相同的种子下,其生成的随机数序列相同,所以称之为伪随机数。

所以一般情况下,有一种比较巧妙的办法:将两者结合起来,先使用真随机数生成种子,然后使用伪随机数生成算法,这样既保证了生成速度,又保证了生成的序列是真正的随机数。

对应到 mbedtls 中,将产生真随机数的模块称为真随机数生成器(TRNG),将产生伪随机数的模块称为伪随机数发生器(PRNG)(也叫做确定性随机数生成器,DRBG),其中伪随机数所使用的种子称为熵源(熵池)

2. 伪随机数生成算法

NIST SP 800-90A规范中描述了三种产生伪随机数的算法:


  • Hash_DRBG:使用单向散列算法作为伪随机数生成的基础算法;
  • HMAC_DRBG:使用消息认证码算法作为随机数生成的基础算法;
  • CRT_DRBG:使用分组密码算法的计数器模式作为随机数生成的基础算法(重点)。

CRT_DRBG 可以理解为一个AES加密过程,加密结果为期望随机数序列。

二、自定义熵源接口

mbedtls中可以通过开启宏定义 MBEDTLS_ENTROPY_HARDWARE_ALT 来开启熵源接口,用户可以在熵源接口中实现自己的硬件获取真随机数代码。

1. 开启宏定义

/**
* \def MBEDTLS_ENTROPY_HARDWARE_ALT
*
* Uncomment this macro to let mbed TLS use your own implementation of a
* hardware entropy collector.
*
* Your function must be called \c mbedtls_hardware_poll(), have the same
* prototype as declared in entropy_poll.h, and accept NULL as first argument.
*
* Uncomment to use your own hardware entropy collector.
*/
#define MBEDTLS_ENTROPY_HARDWARE_ALT

2. 自定义实现mbedtls_hardware_poll函数

创建一个新文件用于存放我们编写的该函数实现,这里我创建文件​​entropy_hardware_alt.c​​。

实现时需要包含头文件​​entropy_poll.h​​,其中包含了 mbedtls_hardware_poll() 函数的原型定义:

#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
/**
* \brief Entropy poll callback for a hardware source
*
* \warning This is not provided by mbed TLS!
* See \c MBEDTLS_ENTROPY_HARDWARE_ALT in config.h.
*
* \note This must accept NULL as its first argument.
*/
int mbedtls_hardware_poll( void *data,
unsigned char *output, size_t len, size_t *olen );
#endif

这里我使用之前移植到小熊派开发板的工程,先开启RNG外设,然后使用硬件RNG外设实现该函数。

① 开启硬件RNG外设:

mbedtls | 02 - 伪随机数生成器(ctr_drbg)的配置与使用_#include

② 编辑文件​​entropy_hardware_alt.c​​,实现函数

#include "mbedtls/entropy_poll.h"

#ifdef MBEDTLS_ENTROPY_HARDWARE_ALT

#include "main.h"
#include "string.h"
#include "stm32l4xx_hal.h"
#include "mbedtls/entropy_poll.h"

extern RNG_HandleTypeDef hrng;

int mbedtls_hardware_poll( void *Data, unsigned char *Output, size_t Len, size_t *oLen )
{
uint32_t index;
uint32_t randomValue;

for (index = 0; index < Len/4; index++)
{
if (HAL_RNG_GenerateRandomNumber(&hrng, &randomValue) == HAL_OK)
{
*oLen += 4;
memset(&(Output[index * 4]), (int)randomValue, 4);
}
else
{
Error_Handler();
}
}

return 0;
}

#endif /*MBEDTLS_ENTROPY_HARDWARE_ALT*/

三、使用mbedtls CTR_DRBG接口生成随机数

1. 宏配置

使用mbedtls随机数生成功能需要开启以下宏:

宏定义

功能

MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES

不使用默认熵源(如果已有、要屏蔽该宏)

MBEDTLS_NO_PLATFORM_ENTROPY

不使用系统内置熵源

MBEDTLS_AES_C

使用AES算法

MBEDTLS_ENTROPY_C

使能熵源模块

MBEDTLS_CTR_DRBG_C

使能随机数模块

MBEDTLS_ENTROPY_FORCE_SHA256

使能SHA256算法

MBEDTLS_AES_ROM_TABLES

使能预定义S盒(节约内存空间)

MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES(如果已有、要屏蔽该宏)

/**
* \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
*
* Do not add default entropy sources. These are the platform specific,
* mbedtls_timing_hardclock and HAVEGE based poll functions.
*
* This is useful to have more control over the added entropy sources in an
* application.
*
* Uncomment this macro to prevent loading of default entropy functions.
*/
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES

MBEDTLS_NO_PLATFORM_ENTROPY

/**
* \def MBEDTLS_NO_PLATFORM_ENTROPY
*
* Do not use built-in platform entropy functions.
* This is useful if your platform does not support
* standards like the /dev/urandom or Windows CryptoAPI.
*
* Uncomment this macro to disable the built-in platform entropy functions.
*/
#define MBEDTLS_NO_PLATFORM_ENTROPY

MBEDTLS_AES_C

/**
* \def MBEDTLS_AES_C
*
* Enable the AES block cipher.
*
* Module: library/aes.c
* Caller: library/cipher.c
* library/pem.c
* library/ctr_drbg.c
*
* This module enables the following ciphersuites (if other requisites are
* enabled as well):
* MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
* MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
* MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
* MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
* MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
* MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
* MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
* MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
* MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
* MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
* MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
* MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
* MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
* MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
* MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
* MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
* MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
* MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
* MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
* MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
* MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
* MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
* MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
* MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
* MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
* MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
* MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
* MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
* MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
* MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384
* MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
* MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
* MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA
* MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
* MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
* MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
* MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
* MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA
* MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384
* MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256
* MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA
* MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256
* MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256
* MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA
* MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384
* MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384
* MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA
* MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256
* MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256
* MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA
* MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384
* MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384
* MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA
* MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256
* MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256
* MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA
*
* PEM_PARSE uses AES for decrypting encrypted keys.
*/
#define MBEDTLS_AES_C

MBEDTLS_ENTROPY_C

/**
* \def MBEDTLS_ENTROPY_C
*
* Enable the platform-specific entropy code.
*
* Module: library/entropy.c
* Caller:
*
* Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C
*
* This module provides a generic entropy pool
*/
#define MBEDTLS_ENTROPY_C

MBEDTLS_CTR_DRBG_C

/**
* \def MBEDTLS_CTR_DRBG_C
*
* Enable the CTR_DRBG AES-based random generator.
* The CTR_DRBG generator uses AES-256 by default.
* To use AES-128 instead, enable MBEDTLS_CTR_DRBG_USE_128_BIT_KEY below.
*
* Module: library/ctr_drbg.c
* Caller:
*
* Requires: MBEDTLS_AES_C
*
* This module provides the CTR_DRBG AES random number generator.
*/
#define MBEDTLS_CTR_DRBG_C

MBEDTLS_SHA256_C

/**
* \def MBEDTLS_SHA256_C
*
* Enable the SHA-224 and SHA-256 cryptographic hash algorithms.
*
* Module: library/sha256.c
* Caller: library/entropy.c
* library/md.c
* library/ssl_cli.c
* library/ssl_srv.c
* library/ssl_tls.c
*
* This module adds support for SHA-224 and SHA-256.
* This module is required for the SSL/TLS 1.2 PRF function.
*/
#define MBEDTLS_SHA256_C

MBEDTLS_AES_ROM_TABLES

/**
* \def MBEDTLS_AES_ROM_TABLES
*
* Use precomputed AES tables stored in ROM.
*
* Uncomment this macro to use precomputed AES tables stored in ROM.
* Comment this macro to generate AES tables in RAM at runtime.
*
* Tradeoff: Using precomputed ROM tables reduces RAM usage by ~8kb
* (or ~2kb if \c MBEDTLS_AES_FEWER_TABLES is used) and reduces the
* initialization time before the first AES operation can be performed.
* It comes at the cost of additional ~8kb ROM use (resp. ~2kb if \c
* MBEDTLS_AES_FEWER_TABLES below is used), and potentially degraded
* performance if ROM access is slower than RAM access.
*
* This option is independent of \c MBEDTLS_AES_FEWER_TABLES.
*
*/
#define MBEDTLS_AES_ROM_TABLES

根据以上代码,编写针对本实验的配置文件​​mbedtls_config_ctr_drbg.h​​:

/**
* @brief Minimal configuration for CTR_DRBG Function
* @author mculover666
* @date 2020/09/22
*/

#ifndef _MBEDTLS_CONFIG_CTR_DRBG_H_
#define _MBEDTLS_CONFIG_CTR_DRBG_H_

/* System support */
#define MBEDTLS_HAVE_ASM
//#define MBEDTLS_HAVE_TIME

/* mbed feature support */
#define MBEDTLS_ENTROPY_HARDWARE_ALT
//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
#define MBEDTLS_NO_PLATFORM_ENTROPY

/* mbed modules */
#define MBEDTLS_AES_C
#define MBEDTLS_AES_ROM_TABLES
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_SHA256_C

#include "mbedtls/check_config.h"

#endif /* _MBEDTLS_CONFIG_CTR_DRBG_H_ */

将配置文件所在目录加入到路径:

mbedtls | 02 - 伪随机数生成器(ctr_drbg)的配置与使用_mbedtls_02

选择使用刚刚编写的本实验配置文件:

mbedtls | 02 - 伪随机数生成器(ctr_drbg)的配置与使用_mbedtls_03

2. API说明

2.1. 熵相关(entropy)

① 初始化熵结构体:

/**
* \brief Initialize the context
*
* \param ctx Entropy context to initialize
*/
void mbedtls_entropy_init( mbedtls_entropy_context *ctx );

② 释放熵结构体:

/**
* \brief Free the data in the context
*
* \param ctx Entropy context to free
*/
void mbedtls_entropy_free( mbedtls_entropy_context *ctx );

③ 错误码说明(用于根据返回值判定错误):

#define MBEDTLS_ERR_ENTROPY_SOURCE_FAILED                 -0x003C  /**< Critical entropy source failure. */
#define MBEDTLS_ERR_ENTROPY_MAX_SOURCES -0x003E /**< No more sources can be added. */
#define MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED -0x0040 /**< No sources have been added to poll. */
#define MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE -0x003D /**< No strong sources have been added to poll. */
#define MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR -0x003F /**< Read/write error in file. */

2.2. ctr_drbg相关

① 初始化ctr_drbg结构体:

/**
* \brief This function initializes the CTR_DRBG context,
* and prepares it for mbedtls_ctr_drbg_seed()
* or mbedtls_ctr_drbg_free().
*
* \param ctx The CTR_DRBG context to initialize.
*/
void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );

② 根据个性化字符更新种子:

/**
* - The \p custom string.
*
* \note To achieve the nominal security strength permitted
* by CTR_DRBG, the entropy length must be:
* - at least 16 bytes for a 128-bit strength
* (maximum achievable strength when using AES-128);
* - at least 32 bytes for a 256-bit strength
* (maximum achievable strength when using AES-256).
*
* In addition, if you do not pass a nonce in \p custom,
* the sum of the entropy length
* and the entropy nonce length must be:
* - at least 24 bytes for a 128-bit strength
* (maximum achievable strength when using AES-128);
* - at least 48 bytes for a 256-bit strength
* (maximum achievable strength when using AES-256).
*
* \param ctx The CTR_DRBG context to seed.
* It must have been initialized with
* mbedtls_ctr_drbg_init().
* After a successful call to mbedtls_ctr_drbg_seed(),
* you may not call mbedtls_ctr_drbg_seed() again on
* the same context unless you call
* mbedtls_ctr_drbg_free() and mbedtls_ctr_drbg_init()
* again first.
* \param f_entropy The entropy callback, taking as arguments the
* \p p_entropy context, the buffer to fill, and the
* length of the buffer.
* \p f_entropy is always called with a buffer size
* less than or equal to the entropy length.
* \param p_entropy The entropy context to pass to \p f_entropy.
* \param custom The personalization string.
* This can be \c NULL, in which case the personalization
* string is empty regardless of the value of \p len.
* \param len The length of the personalization string.
* This must be at most
* #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT
* - #MBEDTLS_CTR_DRBG_ENTROPY_LEN.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure.
*/
int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
int (*f_entropy)(void *, unsigned char *, size_t),
void *p_entropy,
const unsigned char *custom,
size_t len );

③ 生成指定长度随机数

/**
* \brief This function uses CTR_DRBG to generate random data.
*
* This function automatically reseeds if the reseed counter is exceeded
* or prediction resistance is enabled.
*
*
* \param p_rng The CTR_DRBG context. This must be a pointer to a
* #mbedtls_ctr_drbg_context structure.
* \param output The buffer to fill.
* \param output_len The length of the buffer in bytes.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or
* #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure.
*/
int mbedtls_ctr_drbg_random( void *p_rng,
unsigned char *output, size_t output_len );


最大生成长度是:MBEDTLS_CTR_DRBG_MAX_REQUEST(1024),如果需要修改的话可以在配置文件中定义该宏。


④ 释放ctr_drbg结构体:

/**
* \brief This function clears CTR_CRBG context data.
*
* \param ctx The CTR_DRBG context to clear.
*/
void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx );

⑤ 错误码:

#define MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED        -0x0034  /**< The entropy source failed. */
#define MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /**< The requested random buffer length is too big. */
#define MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< The input (entropy + additional data) is too large. */
#define MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read or write error in file. */

3. 编写测试代码

编辑文件​​mbedtls_ctr_drbg_test.c​​,编写一个测试随机数生成的函数:

/**
* @brief CTR_DRBG Function demo
* @author mculover666
* @date 2020/09/22
*/

#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif

#if defined(MBEDTLS_CTR_DRBG_C)

#include <stdio.h>
#include "string.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"

int mbedtls_ctr_drbg_test(void)
{
int ret;
uint8_t data_buf[10];

const char *pers = "crbg_test";
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;

/* 1. init entropy structure */
mbedtls_entropy_init(&entropy);

/* 2. init ctr drbg structure */
mbedtls_ctr_drbg_init(&ctr_drbg);

/* 3. update seed with we own interface ported */
printf( "\n . Seeding the random number generator..." );

if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *) pers,
strlen( pers ) ) ) != 0 ) {
printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d(-0x%04x)\n", ret, -ret);
goto exit;
}

printf( " ok\n" );

/* 4. generate random data */
printf( "\n . generate random data..." );


if ( ( ret = mbedtls_ctr_drbg_random(&ctr_drbg, data_buf, sizeof(data_buf) ) ) != 0) {
printf( " failed\n ! mbedtls_ctr_drbg_random returned %d\n", ret );
goto exit;
}
printf( " ok\n" );

printf("random data:[");
for (int i = 0; i < sizeof(data_buf); i++) {
printf("%02x ", data_buf[i]);
}
printf("]\r\n");

exit:

/* 5. release ctr drbg structure */
mbedtls_ctr_drbg_free(&ctr_drbg);

/* 6. release entropy structure*/
mbedtls_entropy_free(&entropy);

return ret;
}

#endif /* MBEDTLS_CTR_DRBG_C */

4. 调用测试代码

在main.c中声明测试函数定义在外部:

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern int mbedtls_ctr_drbg_test(void);
/* USER CODE END 0 */

在main函数中调用drgb生成随机数的测试代码:

/* USER CODE BEGIN 2 */
printf("mbedtls port on BearPi-STM32L431RC board by mculover666\r\n");

/* 1. crt_drbg test */
mbedtls_ctr_drbg_test();

/* USER CODE END 2 */

5. 测试结果

编译,下载,在串口助手中查看运行结果:

mbedtls | 02 - 伪随机数生成器(ctr_drbg)的配置与使用_#include_04

按下复位再次运行,比较生成的随机数:

mbedtls | 02 - 伪随机数生成器(ctr_drbg)的配置与使用_mbedtls_05

接收精彩文章及资源推送,请订阅我的微信公众号:『mculover666』

mbedtls | 02 - 伪随机数生成器(ctr_drbg)的配置与使用_#include_06