2013-02-10 21 views
3

我正在keil microvision IDE中使用STM32F103E arm cortex-m3 MCU開發項目。
我需要爲某些目的生成隨機數,但我不想使用標準C++庫生成的僞隨機數,所以我需要一種方法來使用硬件功能生成REAL隨機數,但我不知道我該怎麼做。
有什麼想法? (我是軟件工程師&不是電子專業人員,所以請簡單描述一下:P)如何使用STM32 MCU生成REAL隨機數?

+1

貴芯片/電路板有硬件RNG? – Mat 2013-02-10 09:45:40

+0

你需要什麼隨機數? – starblue 2013-02-10 09:50:00

+0

我需要用於RSA密鑰生成的隨機數字。正如Jari所說,似乎F1系列沒有RNG,但我想知道是否有任何方法可以使用其他硬件功能(例如RTC)來模擬硬件RNG? – 2013-02-10 10:30:07

回答

4

正如指出的那樣,該芯片沒有硬件RNG。

但你可以推出自己的。通常的做法是測量獨立時鐘之間的抖動。獨立意味着這兩個時鐘由不同的基準或RC振盪器支持,而不是來自相同的。

我會使用:

    從系統時鐘(MHz範圍內)
  • 其中千赫範圍RC振盪器

設置一個計數器在千赫衍生

  • 系統定時器的定時器/計數器範圍的RC振盪器每秒給你一次中斷。在中斷處理程序中,您可以讀取SysTick計數器的當前值。無論SysTick是否被用於其他目的(調度),低5位左右都是不可預測的。

    要從中得到隨機數,請使用正常的僞RNG。使用上面收集的熵來不可預測地改變僞RNG的內部狀態。對於密鑰生成,不要一次讀取所有位,但允許發生幾個突變。

    對此的攻擊是顯而易見的:如果攻擊者可以測量或控制kHz範圍的RC振盪器達到MHz精度,則隨機性會消失。如果您擔心這一點,請使用智能卡或其他安全協處理器。

  • 4

    F1系列似乎沒有RNG(硬件隨機數發生器),所以你唯一的選擇是使用僞隨機數或詢問外部輸入(有些人認爲例如人的手部動作是隨機的)。你通常使用一些加密庫而不是標準C++庫來獲得更好的僞隨機數。

    8

    這是一個老問題,我剛剛碰到,但我想回答,因爲我沒有找到其他答案令人滿意。

    「我需要用於RSA密鑰生成的隨機數字。」

    這意味着PRNG例程(通常被錯誤地稱爲RNG,我的寵物)是UNACCEPTABLE,並且不會提供所需的安全性。

    一個外部真正的RNG是可以接受的,但最優雅的答案是切換到一個STM32F2xx或STM32F4xx微控制器,它有一個內置的TRUE隨機數發生器,專門用於這種應用。對於開發,我想你可以使用thr F1和任何PRNG,但是在使用真正的RNG之前,會出現「它工作,讓我們發貨」的誘惑,當RIGHT組件(當然是ST F4,我認爲在問這個問題之前,F2芯片也已經存在了)。由於非技術原因(該芯片已經被指定,OP沒有對所需功能的輸入),這個答案可能是不可接受的,但是選擇芯片的人應該根據片上外設和功能選擇它應用程序需要。

    2

    我發現並測試了另一種方法,效果很好。它可以生成真正的隨機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); 
    

    }

    +1

    你的方法有缺陷。在白化(CRC)之後,您無法通過查看輸出*來確定熵源(ADC)的質量。此外,輸出值的簡單直方圖只會檢測RNG中最簡單的缺陷。事實上,你需要8輪產生的東西,即使*看起來隨機乍一看錶明,你得到很小的熵每個ADC樣本,如果有的話。因此,沒有進一步的分析,你不能對RNG的熵做任何假設,因此不能用它來生成密碼密鑰。 – JimmyB 2017-01-10 14:13:05