如何使用 STM32 MCU 生成 REAL 随机数?

Posted

技术标签:

【中文标题】如何使用 STM32 MCU 生成 REAL 随机数?【英文标题】:How generate REAL random number using STM32 MCU? 【发布时间】:2013-01-25 15:00:38 【问题描述】:

我正在 keil microvision IDE 中使用 STM32F103E arm cortex-m3 MCU 开展一个项目。 我需要为某些目的生成随机数,但我不想使用标准 c++ 库正在生成的伪随机数,所以我需要一种使用硬件功能生成 REAL 随机数的方法,但我不知道如何我能做到。 任何想法? (我是软件工程师,不是电子专业人士,所以请简单描述一下:P)

【问题讨论】:

你的芯片/板子有硬件RNG吗? 随机数有什么用? 我需要随机数来生成 RSA 密钥。正如Jari所说,F1系列似乎没有RNG,但我想知道有没有办法使用其他硬件功能(例如RTC)来模拟硬件RNG? 我想你可以买一个 TRNG 芯片,你可以与 STM32 上的一个接口进行通信。 【参考方案1】:

这是我刚刚遇到的一个老问题,但我想回答,因为我觉得其他答案都不令人满意。

“我需要随机数来生成 RSA 密钥。”

这意味着 PRNG 例程(经常被错误地称为 RNG,我的小毛病)是不可接受的,并且不会提供所需的安全性。

外部真正的 RNG 是可以接受的,但最优雅的答案是改用 STM32F2xx 或 STM32F4xx 微控制器,它们具有内置的 TRUE 随机数发生器,专门用于此类应用。对于开发,我想你可以使用 thr F1 和任何 PRNG,但是在使用真正的 RNG 之前会有“它有效,让我们运送它”的诱惑,当 RIGHT 组件(当然是 ST F4,我认为自从提出这个问题之前,F2 芯片也已经存在)可用。

由于非技术原因,这个答案可能是不可接受的(芯片已经指定,OP 没有输入所需的功能),但是选择芯片的人应该根据需要的片上外围设备和功能选择它为应用程序。

【讨论】:

【参考方案2】:

如前所述,该芯片没有硬件 RNG。

但你可以自己滚动。通常的方法是测量独立时钟之间的抖动。独立意味着这两个时钟由不同的晶体或 RC 振荡器支持,而不是来自相同的。

我会使用:

SysTick 定时器/计数器源自系统时钟(MHz 范围) kHz 范围的 RC 振荡器之一

在 kHz 范围的 RC 振荡器上设置一个计数器,以每秒为您提供多次中断。在中断处理程序中,您读取 SysTick 计数器的当前值。无论 SysTick 是否用于其他目的(调度),低 5 位左右都是不可预测的。

要从中获取随机数,请使用普通的伪 RNG。使用上面收集的熵来不可预测地改变伪 RNG 的内部状态。对于密钥生成,不要一次读取所有位,而是允许发生几个突变。

对此的攻击是显而易见的:如果攻击者可以测量或控制高达 MHz 精度的 kHz 范围 RC 振荡器,那么随机性就会消失。如果您对此感到担心,请使用智能卡或其他安全协处理器。

【讨论】:

【参考方案3】:

F1 系列似乎没有 RNG(硬件随机数生成器),因此您唯一的选择是使用伪随机数或询问外部输入(有些考虑例如人手随机运动)。您经常使用一些加密库而不是标准 C++ 库来获得更好的伪随机数。

【讨论】:

【参考方案4】:

我发现并测试了另一种效果很好的方法。它可以生成真正的随机 32 位数字,我从未检查过它有多快,每个数字可能需要几毫秒。事情是这样的:

以尽可能快的速度读取嘈杂的内部温度,以产生最大的 ADC 噪声 通过硬件 CRC 生成器运行值,大多数(全部?)STM32 芯片上都可用

重复几次,我发现 8 次给出了很好的随机性。我通过按升序对输出值进行排序并将它们绘制在 excel 中来检查随机性,使用好的随机数会生成一条直线,糟糕的随机性或某些数字的“聚集”立即可见。 这是STM32F03的代码:

uint32_t getTrueRandomNumber(void) 

ADC_InitTypeDef ADC_InitStructure;

//enable ADC1 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

// Initialize ADC 14MHz RC
RCC_ADCCLKConfig(RCC_ADCCLK_HSI14);
RCC_HSI14Cmd(ENABLE);
while (!RCC_GetFlagStatus(RCC_FLAG_HSI14RDY))
    ;

ADC_DeInit(ADC1);
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Backward;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_TRGO; //default
ADC_Init(ADC1, &ADC_InitStructure);

//enable internal channel
ADC_TempSensorCmd(ENABLE);

// Enable ADCperipheral
ADC_Cmd(ADC1, ENABLE);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN) == RESET)
    ;

ADC1->CHSELR = 0; //no channel selected
//Convert the ADC1 temperature sensor, user shortest sample time to generate most noise
ADC_ChannelConfig(ADC1, ADC_Channel_TempSensor, ADC_SampleTime_1_5Cycles);

// Enable CRC clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);

uint8_t i;
for (i = 0; i < 8; i++) 
    //Start ADC1 Software Conversion
    ADC_StartOfConversion(ADC1);
    //wait for conversion complete
    while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)) 
    

    CRC_CalcCRC(ADC_GetConversionValue(ADC1));
    //clear EOC flag
    ADC_ClearFlag(ADC1, ADC_FLAG_EOC);


//disable ADC1 to save power
ADC_Cmd(ADC1, DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, DISABLE);

return CRC_CalcCRC(0xBADA55E5);

【讨论】:

你的方法有缺陷。您无法通过查看输出after 白化 (CRC) 来确定熵源 (ADC) 的质量。此外,输出值的简单直方图只会检测 RNG 中最简单的缺陷。您需要 8 轮才能产生乍看之下甚至 看起来 随机的东西,这表明每个 ADC 样本(如果有的话)获得的熵非常少。因此,如果没有进一步分析,您无法对 RNG 的熵做出任何假设,因此无法将其用于加密密钥生成。

以上是关于如何使用 STM32 MCU 生成 REAL 随机数?的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式MCU开发群资源

如何获取STM32 MCU的唯一ID

从 STM32F401 MCU 向 ESP8266 发送数据并从 ESP8266 向 MCU 获取响应

STM32 MCU 上的 DMA 到 GPIO 的可靠性如何?

为啥 STM32CubeIDE 有 2 个生成的链接器脚本?

请问关于STM32,用yagarto生成的.bin文件,怎样烧录?