如何安全地生成隨機數
使用 urandom
使用 urandom!使用 urandom!使用 urandom!
使用 urandom!使用 urandom!使用 urandom!
但對於密碼學密鑰呢?
仍然使用 urandom。
為什麼不是 SecureRandom、OpenSSL、havaged 或者 c 語言實現呢?
這些是用戶空間的 CSPRNG(偽隨機數生成器)。你應該用內核的 CSPRNG,因為:
- 內核可以訪問原始設備熵。
- 它可以確保不在應用程序之間共享相同的狀態。
- 一個好的內核 CSPRNG,像 FreeBSD 中的,也可以保證它播種之前不給你隨機數據。
研究過去十年中的隨機失敗案例,你會看到一連串的用戶空間的隨機失敗案例。Debian 的 OpenSSH 崩潰?用戶空間隨機!安卓的比特幣錢包重複 ECDSA 隨機 k 值?用戶空間隨機!可預測洗牌的賭博網站?用戶空間隨機!
用戶空間的生成器幾乎總是依賴於內核的生成器。即使它們不這樣做,整個系統的安全性也會確保如此。但用戶空間的 CSPRNG 不會增加防禦深度;相反,它會產生兩個單點故障。
手冊頁不是說使用 /dev/random 嘛?
這個稍後詳述,保留你的意見。你應該忽略掉手冊頁。不要使用 /dev/random
。/dev/random
和 /dev/urandom
之間的區別是 Unix 設計缺陷。手冊頁不想承認這一點,因此它產生了一個並不存在的安全顧慮。把 random(4)
中的密碼學上的建議當作傳說,繼續你的生活吧。
但是如果我需要的是真隨機值,而非偽隨機值呢?
urandom 和 /dev/random
提供的是同一類型的隨機。與流行的觀念相反,/dev/random
不提供「真正的隨機」。從密碼學上來說,你通常不需要「真正的隨機」。
urandom 和 /dev/random
都基於一個簡單的想法。它們的設計與流密碼的設計密切相關:一個小秘密被延伸到不可預測值的不確定流中。 這裡的秘密是「熵」,而流是「輸出」。
只在 Linux 上 /dev/random
和 urandom 仍然有意義上的不同。Linux 內核的 CSPRNG 定期進行密鑰更新(通過收集更多的熵)。但是 /dev/random
也試圖跟蹤內核池中剩餘的熵,並且如果它沒有足夠的剩餘熵時,偶爾也會罷工。這種設計和我所說的一樣蠢;這與基於「密鑰流」中剩下多少「密鑰」的 AES-CTR 設計類似。
如果你使用 /dev/random
而非 urandom,那麼當 Linux 對自己的 RNG(隨機數生成器)如何工作感到困惑時,你的程序將不可預測地(或者如果你是攻擊者,非常可預測地)掛起。使用 /dev/random
會使你的程序不太穩定,但這不會讓你在密碼學上更安全。
這是個缺陷,對嗎?
不是,但存在一個你可能想要了解的 Linux 內核 bug,即使這並不能改變你應該使用哪一個 RNG。
在 Linux 上,如果你的軟體在引導時立即運行,或者這個操作系統你剛剛安裝好,那麼你的代碼可能會與 RNG 發生競爭。這很糟糕,因為如果你贏了競爭,那麼你可能會在一段時間內從 urandom 獲得可預測的輸出。這是 Linux 中的一個 bug,如果你正在為 Linux 嵌入式設備構建平台級代碼,那你需要了解它。
在 Linux 上,這確實是 urandom(而不是 /dev/random
)的問題。這也是 Linux 內核中的錯誤。 但它也容易在用戶空間中修復:在引導時,明確地為 urandom 提供種子。長期以來,大多數 Linux 發行版都是這麼做的。但不要切換到不同的 CSPRNG。
在其它操作系統上呢?
FreeBSD 和 OS X 消除了 urandom 和 /dev/random
之間的區別;這兩個設備的行為是相同的。不幸的是,手冊頁在解釋為什麼這樣做上乾的很糟糕,並延續了 Linux 上 urandom 可怕的神話。
無論你使用 /dev/random
還是 urandom,FreeBSD 的內核加密 RNG 都不會停擺。 除非它沒有被提供種子,在這種情況下,這兩者都會停擺。與 Linux 不同,這種行為是有道理的。Linux 應該採用它。但是,如果你是一名應用程序開發人員,這對你幾乎沒有什麼影響:Linux、FreeBSD、iOS,無論什麼:使用 urandom 吧。
太長了,懶得看
直接使用 urandom 吧。
結語
現在,在嘗試檢測
/dev/urandom
之前,SecureRandom.random_bytes 會嘗試檢測要使用的 OpenSSL。 我認為這應該反過來。在這兩種情況下,你只需要將隨機位元組進行解壓,所以 SecureRandom 可以跳過中間人(和第二個故障點),如果可用的話可以直接與/dev/urandom
進行交互。
總結:
/dev/urandom
不適合用來直接生成會話密鑰和頻繁生成其他應用程序級隨機數據。GNU/Linux 上的 random(4) 手冊所述......
感謝 Matthew Green、 Nate Lawson、 Sean Devlin、 Coda Hale 和 Alex Balducci 閱讀了本文草稿。公正警告:Matthew 只是大多同意我的觀點。
via: https://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
作者:Thomas & Erin Ptacek 譯者:kimii 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive