1. 什么是安全的隨機數?
在安全應用場景,隨機數應該使用安全的隨機數。密碼學意義上的安全隨機數,要求必須保證其不可預測性。
2. 怎么得到安全的隨機數
可以直接使用真隨機數產生器產生的隨機數。或者使用真隨機數產生器產生的隨機數做種子,輸入密碼學安全的偽隨機數產生器產生密碼學安全隨機數。
非物理真隨機數產生器有:
- Linux操作系統的/dev/random設備接口
- Windows操作系統的CryptGenRandom接口
密碼學安全的偽隨機數產生器,包括JDK的java.security.SecureRandom等。
本文主要討論SecureRandom。
3. SecureRandom最佳實踐
3.1 基本用法
java.security.SecureRandom基本用法:
byte[] values = new byte[128]; SecureRandom random = new SecureRandom(); random.nextBytes(values);
3.2 關於種子的設置
要保證得到安全的隨機數,需要使用真隨機數產生器產生的隨機數做種子。
可能的不當用法:
byte[] salt = new byte[128]; SecureRandom secureRandom = new SecureRandom(); secureRandom.setSeed(System.currentTimeMillis()); //使用系統時間作為種子 secureRandom.nextBytes(salt);
此處指定了當前系統時間作為種子,替代系統默認隨機源。如果同一毫秒連續調用,則得到的隨機數則是相同的。
小結:不要自己指定種子。應當使用系統隨機源。
系統默認的隨機源是什么?
這取決於$JAVA_HOME/jre/lib/security/java.security配置中的securerandom.source屬性。例如jdk1.8中該配置為:
securerandom.source=file:/dev/random
使用無參構造函數實例化SecureRandom,在大多數系統中,默認的算法是“nativePRNG”,從/dev/random獲取隨機數。
3.3 熵源不足時阻塞問題
概念回顧:
- "熵值":即是隨機值的不確定性度量值。
"熵源":即是隨機數的來源。
"熵輸入":是偽隨機數產生器描述從熵源獲取的bit串,用來產生種子。
"種子":即是輸入到偽隨機數產生器用於初始化的bit串。
問題描述
在Linux系統中,/dev/random是系統提供的安全隨機數接口。當通過/dev/random讀取隨機數的速度可以為產品所接受時,可以直接使用/dev/random讀取的隨機數。
有時無法滿足產品對隨機數的使用要求,熵源不足時存在阻塞,會導致得到隨機數的速度太慢。
在讀取時,/dev/random設備會返回小於熵池噪聲總數的隨機字節。/dev/random可生成高隨機性的公鑰或一次性密碼本。若熵池空了,對/dev/random的讀操作將會被阻塞,直到收集到了足夠的環境噪聲為止。
解決方法
提高系統隨機數產生器產生隨機數速度的一種方法:
- 采用haveged守護進程增加系統熵池熵值以提高/dev/random讀取隨機數的速度。
4. 小結
- SecureRandom的使用可以采用無參構造方法實例化,無需手動設置種子。
- 如果出現了熵源不足獲取隨機數阻塞的問題,再進一步優化即可。
- 不是安全場景的隨機數,使用Random就好。