7

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

4

4 回答 4

14

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

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

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

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

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

于 2014-10-10T19:14:55.383 回答
10

正如所指出的,该芯片没有硬件 RNG。

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

我会使用:

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

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

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

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

于 2013-02-10T11:13:27.753 回答
4

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

于 2013-02-10T10:06:22.243 回答
3

我发现并测试了另一种方法,效果很好。它可以生成真正的随机 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);

}

于 2015-10-11T16:47:48.450 回答