mbedtls | 02 - 伪随机数发生器(ctr_drbg)的配置和使用
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外设:
② 编辑文件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_ */
将配置文件所在目录加入到路径:
选择使用刚刚编写的本实验配置文件:
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. 测试结果
编译,下载,在串口助手中查看运行结果:
按下复位再次运行,比较生成的随机数:
接收精彩文章及资源推送,请订阅我的微信公众号:『mculover666』。
推荐阅读
-
IceScorpion V4.0 流量分析到攻击和防御检测
-
一篇关于深度自适应网络(DAN)的文章--简介
-
了解 HTTP 协议中的多art/表单数据
-
Kubernetes 社区组织和软件工程流程学习
-
蓝桥杯模拟:奇怪的捐款 (dfs)
-
在 Linux 内核中使用 spi 屏幕驱动程序 - fbtft
-
机器学习:基于 Sklearn 和 XGBoost 框架,使用逻辑回归、支持向量机和 XGBClassifier 诊断和预测一个人是否患有自闭症-4。模型训练
-
假作真时真亦假,无为有处有还无"--《红楼梦》中的人生哲理与曹雪芹的独特笔触
-
玩得开心--用 python 分析《三国演义》中的社交网络
-
单独布道的详细解释 (1)