「隨機」對資安真的很重要! 藏在 CPU 的「真·隨機數產生器」
| | | 1 | |
先看兩則因隨機性不足導致資安破防的新聞:
- 自然人憑證被爆有安全漏洞! by iThome
研究驗證比對兩百多萬筆自然人憑證公錀發現:其中有 103 個金鑰共用質數,可用數學算式及電腦分析,剩下 81 筆可以其他方式解析。

- 爱沙尼亚因加密缺陷紧急取消76万张电子身份证
德國晶片製造商英飛凌 (Infineon) 的金鑰程式庫在生成 RSA 公私金鑰時,為加速運算效率採用一種特殊質數生成演算法,此種演算法生成的 RSA 質數缺乏足夠隨機性與熵,導致能用 Coppersmith 因數分解攻擊快速計算出私密金鑰,導致有缺陷的 2048 位元私鑰只需 140.8 CPU -年即可破解(參考),為此,愛沙尼亞政府撤銷了 76 萬張數位身分證。
不懂密碼學沒關係,只需知道一件事:加密跟簽章的安全性源自數學難題,而數學難題的關鍵常基於正確答案是一組隨機產生的超大數字或超長資料,可能的範圍超大,猜不到也無從預測或推算,只剩靠暴力破解一途。由於答案選項比全宇宙的原子還多,一個個試到地老天荒也試不完。由此可知,若挑選答案的方法不夠隨機,會讓攻擊者有機會預測推算,或可以縮小猜測範圍,便會讓加密或簽章安全性大打折扣,以上兩起事件的爆炸點都在於隨機數不夠隨機。
有鑑於此,資安規範對隨機數品質有嚴格要求,要求絕對隨機,不可能用任何方法預測。資安規範的權威機構 - NIST (美國國家標準暨技術研究院) 對隨機數生成器 (RNG) 便有一套嚴謹且完整的規範體系,稱為 NIST SP 800-90 系列,分別是:
- SP 800-90A:確定性隨機位元生成器 (DRBG),定義了如何將一個種子 (Seed) 擴展成大量隨機數,主流演算法包含 Hash_DRBG、HMAC_DRBG 與 CTR_DRBG
- SP 800-90B:熵源 (Entropy Sources),規範硬體與物理的隨機來源,必須有雜訊源 (Noise Source)、數位化過程,以及健康檢測 (Health Testing,確認不會輸出相同數字,並監控特定數字出現機率是否異常偏高)
- SP 800-90C:隨機位元生成器 (RBG) 結構,定義如何將 90A 與 90B 組裝起來。共有兩種模式 RBG2 (以硬體熵源當種子,餵給 DRBG 演算法產出一連串隨機數)、RBG3 (每一次輸出都混合新的硬體熵,Full Entropy,適用對資安有超高要求的場合)
註:「熵」(Entropy) 是個重要但有點深奧的科學術語,這裡只需理解成「越難預測、越隨機的事情,它的熵越高」就夠了。
在資安與密碼學應用中,有以下常見的熵源:
- 熱雜訊 (Thermal Noise):偵測電晶體中電子的無規律熱運動產生的微小電壓波動
- 時脈抖動 (Clock Jitter):依據兩個振盪器間的微小相位差產生隨機性
- 中斷時間 (Interrupt Timings):鍵盤輸入、滑鼠點擊、磁碟存取 (I/O) 發生時點的精確時間
- 硬碟搜尋時間:機械硬碟在讀取資料時的微小延遲
- 網路封包抖動 (Network Jitter):網路封包到達的間隔時間
- 大氣雜訊 (Atmospheric Noise):接收自然大氣中的無線電雜訊,著名的 random.org 便是用大氣噪聲生成亂數的網站
- 放射性衰變 (Radioactive Decay):利用不穩定原子核衰變的時間點,這是目前已知最完美的真隨機源
- 光子極化 (Photon Polarization):利用量子力學中的光子行為來生成隨機位元
- 視覺雜訊:著名範例是 Cloudflare 的「熔岩燈牆」(Lava Lamps),拍攝幾百個熔岩燈隨機漂浮的畫面,將像素資訊轉化為隨機種子

而在電腦系統中,最簡便可靠且隨手可得的熵源非熱雜訊莫屬,電腦可以沒有鍵盤沒有硬碟沒有網路,更甭提另外買設備收大氣雜訊、偵測原子核衰變跟光子行為,但一定有電晶體。Intel 從 2012 年開始在 CPU 實作硬體隨機數生成器,提供 RDRAND (取得隨機數) 與 RDSEED (取得種子) 兩種指令,而 AMD 也在 2015 年跟進。時至今日,幾乎每顆 CPU 都有內建硬體隨機數產生器,我們只需寫幾行程式,就能用 C 語言呼叫低階指令取得符合 NIST 標準的高品質隨機數,確保資安演算法達到應有的安全強度。更多時侯,我們使用更高階的密碼學程式庫,底層也是以它們為基礎。
補充完知識,最後寫幾行程式試取幾個「真·隨機數」結束這回合。
Linux GCC 有 -mrdrnd 編譯參數及 immintrin.h 方便呼叫 CPU 的硬體隨機數產生器,為求簡化我在 Winodws 用 WSL 測試。
先安裝 C/C++ 編譯工具:
sudo apt update && sudo apt upgrade -y
sudo apt install build-essential gdb cmake ninja-build -y
寫幾行 C++ 程式:
#include <iostream>
#include <immintrin.h>
int main() {
unsigned long long val;
if (_rdrand64_step(&val)) {
std::cout << "真 • 隨機數: " << val << std::endl;
} else {
std::cout << "硬體不支援或失敗" << std::endl;
}
return 0;
}
開始前可用 cat /proc/cpuinfo 觀察 CPU 是否支援 RDRAND:

使用 g++ -mrdrnd test_drng.cpp -o test_drng 編譯後執行,測試成功!

Comments
# by 小黑
這題有點硬