關於隨機數測試,有兩份比較經常使用的標準,一份是國密局的隨機數檢測規範,一份是NIST的測試標準算法
國密局標準參看GB/T 32915,NIST標準能夠參看 https://nvlpubs.nist.gov/nistpubs/legacy/sp/nistspecialpublication800-22r1a.pdfdom
二者大致上一致,存在幾個用例的區別,另外NIST除了統計P值總數,還統計P值的分佈函數
NIST還提供了一個測試程序,能夠從這裏獲取 https://csrc.nist.gov/projects/random-bit-generation/documentation-and-software測試
隨機數特性加密
一個理想的隨機二進制比特流,可由一個徹底"公正無偏"的經過拋擲正反面獲得,其中正面記爲0,反面記爲1。每一擲獲得0和1的機率都是確切的1/2。並且每一次的結果之間都相互獨立,即先前的結果不會對將來的結果產生影響設計
使用像「公正硬幣」這樣的理想隨機數發生器是不實際的,可是這樣一個理想的發生器產生的輸出能夠做爲咱們測試評估其餘隨機數發生器的基準。code
加密應用的隨機數須要不可預測。對於僞隨機數發生器,在不知道種子的狀況下,就算知道先前的隨機數序列也應該沒法預測接下來輸出,也即前向不可預測性。同時後向不可預測性也是要求的,即沒法經過已知的產生的值,得出種子。server
因爲僞隨機數算法每每已知,確保前向不可預測性,在獲得種子的方法上須要注意,種子自己要不可預測。ssl
產生方法ci
RNG(隨機數發生器)
使用熵源和熵蒸餾函數。其中熵蒸餾函數用來克服熵源的任何非隨機性缺陷。熵源通常基於物理現象由硬件產生,獲得真隨機數。特別地,像咱們即將評估的量子隨機數發生器,就是利用了半導體的量子效應。
RNG產生的結果能夠直接做爲隨機數使用,但前提是已經知足了嚴格的隨機性標準。也能夠將獲得的結果再餵給PRNG,或者將幾個PNRG的結果進行結合,以提升隨機數的隨機性。
PRNG(僞隨機數發生器)
提供輸入的種子,經過數值運算,獲得僞隨機數。僞隨機數發生器的輸出是種子的一個肯定性結果,即餵給相同的種子的狀況下輸出永遠同樣。這也是爲何稱之爲「僞隨機數」的緣由。因此輸入的種子自己須要知足隨機性和不可預測性。
僞隨機發生器便於重現,產生速度快,有其自身的優勢。
測試
隨機數的測試,基於隨機性假設設計測試用例進行統計性的驗證。每個統計測試用例用來驗證一個特定的假設。根據測試的統計結果決定是假設成立仍是不成立。在隨機性假設下,統計量會知足一個參考分佈,從這個參考分佈上肯定一個臨界值(好比99%)。測試的時候,將測試結果同這個臨界值進行比較,若是經過小於臨界值則認爲假設成立,反之則認爲不成立。
考慮到假設不成立自己的機率很小,須要測試多個樣本(至少在alpha值倒數的量級),經過統計全部樣本的結果,最終決定測試是否經過。
可能的統計測試是無窮的,評估任何一種特定的pattern是否存在。沒有那個有窮的測試集合是完備的,因此在測試結果的解釋上要謹慎。
頻數檢測
目的是檢測待測試二進制序列中,「0」和「1」 數目是否近似相等。若是是,則認爲序列是隨機的。
塊內頻數檢測
目的是肯定在待測序列中,全部非重疊的長度爲M位的塊內的「0」和「1」的數目是否表現爲隨機分佈。若是是,則序列是隨機的。
遊程檢測
目的是肯定待測序列中,總的遊程數目是否如真隨機序列指望的那樣。若是是,則序列是隨機的。
塊內最長遊程檢測
目的是肯定待測序列中,最長「1」遊程的長度是否與真隨機序列中最長「1」遊程的長度近似一致。若是是,則序列是隨機的。
矩陣秩檢測
目的是檢測待測序列中,固定長度子序列的線性相關性。若是線性相關性較小,則序列是隨機的。
離散傅里葉變換檢測
目的是經過檢測待測序列的週期性質,並與真隨機序列週期性質相比較,經過它們之間的偏離程度來肯定待測序列隨機性。若是偏離程度較小,序列是隨機的。(超過95%閾值的峯數是否顯著異於5%)
非重疊模板匹配檢測
目的是檢測待測序列中,子序列是否與太多的非重疊模板相匹配。太多就意味着待測序列是非隨機的。
重疊模板匹配檢測
目的是統計待測序列中,特定長度的連續「1」的數目,是否與真隨機序列的狀況偏離太大。太大是非隨機的。
通用統計檢測
目的是檢測待測序列是否能在信息不丟失的狀況下被明顯壓縮。一個不可被明顯壓縮的序列是隨機的。(匹配pattern(壓縮序列長度相關的度量)之間的比特數)
線性複雜度檢測
目的是肯定待測序列是否足夠複雜,若是是,則序列是隨機的。
重疊子序列檢測
目的是肯定待測序列全部可能的m位比特的組合子串出現的次數是否與真隨機序列中的狀況近似相同,若是是,則序列是隨機的。每一個pattern的機率相等
近似熵檢測
目的是經過比較m位比特串與m+1位比特串在待測序列中出現的頻度,再與正態分佈的序列中的狀況相對比,從而肯定隨機性。
累加和檢測
目的肯定待測序列中的部分和是否太大或過小。太大或過小都是非隨機的。
隨機遊走檢測
目的是肯定在一次隨機遊走過程當中,某個特定狀態出現的次數爲K的cycle個數是否遠遠超過真隨機序列中的狀況。若是是,則序列是非隨機的。
隨機遊走變量檢測
目的是檢測待測序列中,某一特定狀態在一個遊走過程當中出現的總次數與真隨機序列的偏離程度。若是偏離程度較大,則序列是非隨機的。
>如下幾個國密特有
遊程分佈檢測
目的是肯定待測序列中,遊程的分佈狀況是或否與真隨機序列近似。若是偏離程度較大,則序列是非隨機的。
撲克檢測
目的是檢測待測序列中,子序列是否與太多的非重疊模板相匹配。太多就意味着待測序列是非隨機的
二元推導檢測
將初始序列中相鄰兩比特依次作異或操做獲得新序列,這樣在第k次二元推導的序列中0和1的數量是否接近一致。若是與真隨機序列相比接近,則認爲是隨機的。
自相關檢測
檢測待測序列與將其自身邏輯左移d位後的新序列的關聯程度,若是關聯程度與真隨機序列相比偏高,則認爲是非隨機的。
準備測試數據
使用待測的(僞)隨機數發生器,產生足夠長度的隨機數序列。(樣本參數見附錄)
在NIST的測試源碼中,添加4個國密特有的測試用例
撲克測試,遊程分佈測試,二元推導測試,自相關測試
編譯源碼獲得測試程序
在sts-2.1.2目錄下make便可
運行測試程序,選擇待測試數據,按照NIST測試用例和測試參數進行設置
$ ./assess 1000000
測試結束以後,分析測試結果,看是否知足預期要求
運行測試程序,選擇待測試數據,按照國密規範選擇對應測試用例,並進行參數設置
$ ./assess 1000000
測試結果以後,分析測試結果,看是否知足預期要求
經過測試的樣本比例(NIST標準)
根據樣本總個數和顯著性水平,計算斷定用例經過的最小樣本個數
對於樣本數爲1000,顯著性水平爲0.01的狀況,經過的比例須要在0.98以上
即1000的樣本須要有980個經過。
P值均勻分佈(僅NIST)
對每一個測試樣本的P值結果,按照0.1的區間間隔進行數量統計,計算P值統計結果的P值。
若是最終的P值大於0.0001,則認爲是均勻分佈的。
序號 | 檢測項目 | 國密參數 | NIST參數 |
---|---|---|---|
1 | 塊內頻數測試 | m=100 | m=128 |
2 | 撲克測試(國密) | m=4; m=8 | / |
3 | 重疊子序列測試 | m=2; m=5 | m=16 |
4 | 塊內最長遊程測試 | m=10000 | m=10000 |
5 | 二元推導測試(國密) | k=3; k=7 | / |
6 | 自相關測試(國密) | d=1, 2, 8, 16 | / |
7 | 矩陣秩測試 | M=Q=32 | M=Q=32 |
8 | 近似熵測試 | m=2; m=5 | m=10 |
9 | 線性複雜度測試 | m=500 | m=500 |
10 | 非重疊模板測試(NIST) | / | m=9 |
11 | 重疊模板測試(NIST) | / | m=9 |
12 | 通用測試 | L=7,Q=1280 | L=7,Q=1280 |
顯著性水平α=0.01
參數 | 值 |
---|---|
樣本長度 | 10^6 bits |
樣本個數 | 1000 |
openssl隨機數樣本生成方法(1.0.2o)
openssl rand -out data.openssl 1000000000
用C語言中rand函數生成隨機數樣本(glibc版本2.27)
./c_rand 1024 data.c_rand 1000000000
其中c_rand程序的源碼c_rand.c以下
#include <stdlib.h> #include <stdio.h> #define buffer 1024 int main(int argc, char *argv[]) { int j, r, nbytes; unsigned int seed; FILE* fp = NULL; size_t res = 0; if (argc != 4) { fprintf(stderr, "Usage: %s <seed> <rand_file> <nbytes>\n", argv[0]); return -1; } seed = atoi(argv[1]); nbytes = atoi(argv[3]); srand(seed); unsigned char* out = new unsigned char[buffer]; unsigned char* cur = out; if (!(fp = fopen(argv[2], "wb"))) { printf("file %s open fail!", argv[2]); delete[] out; return -1; } for (j=0;j<nbytes; ++j) { r = rand()%256; *cur++ = *((unsigned char*)(&r)); if((!(( j + 1 ) % buffer)) || ( j + 1 == nbytes)) { size_t num = j % buffer + 1; res = fwrite(out, 1, num, fp); if (res != num) { fclose(fp); delete[] out; printf("file %s write fail!", argv[2]); return -1; } cur = out; } } fclose(fp); delete[] out; return 0; }
採集握手中ClientHello隨機數
生成隨機數命令:
openssl s_server -engine ./engine.so -cert test/rsa-ext.pem -key test/rsa.key -CAfile ca/rsa-ca.pem -www -accept 8888 ./ssl -h 192.168.1.10 -p 8888 -s 128000000 -f binary -o data.handshake -m tls1_2
採集硬件加密卡生成的隨機數樣本
前置條件:完成硬件安裝,驅動安裝,編譯openssl 引擎獲得engine.so
openssl rand -engine ./engine.so -out data.cryptocard 1000000000