隨機數生成
根據wikipedia:Random number generation詞條的定義:
- 隨機數生成器(random number generator, RNG)是用於生成數字/符號序列的計算設備或物理設備。其生成的序列應當看起來是隨機的,不含任何規律性特徵。
生成隨機數據對某些應用至關重要。隨機數據可用於生成密碼學密鑰(密鑰可用於靜態數據加密)、安全地擦除磁碟、運行軟體接入點等用途。
Linux內核內置的隨機數生成器可生成密碼學安全的偽隨機數據。其從多種來源搜集熵,用於隨機數生成。熵的來源包括硬體隨機數生成器、中斷、CPU抖動熵(CPU-based jitterentropy),不依賴單一來源。熵將通過BLAKE2s 密碼學哈希函數提取,並用作一組ChaCha20密碼學隨機數生成器(Cryptographic Random Number Generator, CRNG)的種子。最終的隨機數據由ChaCha20密碼學隨機數生成器生成。內核在運行時將不斷搜集熵值,並周期性地更新隨機數生成器的種子。
若要在用戶空間訪問內核內置隨機數生成器,可使用內核提供的三個接口:
- getrandom(2)系統調用
/dev/random/dev/urandom
在過去,一般認為/dev/random生成的隨機數隨機性比/dev/urandom的好。然而,隨著內核的更新,/dev/random和/dev/urandom的行為越來越相似。甚至,在目前的x86-64系統上,它們的行為是完全相同的。由於Arch Linux只支持x86-64架構,因此可以說在Arch Linux中,兩者的行為是相同的。(這是由於所有x86-64 CPU都支持RDTSC 指令,因而總是可以使用CPU抖動熵算法搜集熵值;此外,大多數x86-64 CPU還支持RDRAND指令,可用於隨機數生成。)
對於其它架構(特別是不支持快速周期計數器(fast cycle counter)的架構),/dev/random與/dev/urandom仍有區別:在內核認為密碼學隨機數生成器完成初始化之前,/dev/random將阻塞,而/dev/urandom不阻塞。因此,在通常情況下,應用若要生成長期使用的密碼學密鑰,仍應當依照傳統,使用/dev/random,或直接使用getrandom(2)系統調用(其默認行為與/dev/random相似)。
注意,由於/dev/random只保證生成密碼學安全的隨機數據(已經能滿足所有現實需求),而不再保證生成「真」隨機數據,從其中讀取數據不再會消耗內核熵池中的熵,/proc/sys/kernel/random/entropy_avail的內容應當始終是256(ChaCha20密鑰的比特長度)。因此,若看到認為256「太低」,需要手動提高該值的過時文檔,不必採取相應操作。
不需要密碼學安全隨機數的應用程式可以使用非密碼學隨機數生成器,例如 random(3)。
對於需要密碼學安全隨機數的應用程式,在現在,使用內核內置的隨機數生成器即可,一般無需使用其它方式。曾經,內核的隨機數生成器生成速度較慢,且沒有使用許多本可以使用的熵源。但現在,經過改進,其使用了更多的熵源,在x86-64架構上吞吐量能達到大約400 MB/s。即使在需要非常高吞吐量的場景中(例如,安全地擦除磁碟),也可以直接使用/dev/urandom。
對於如下情況,可能需要使用其它方式,而不是直接使用內核隨機數生成器:
- 在某些特定情況下,應用程式需要獲取密碼學安全隨機數,且要求非常高的吞吐量/非常低的延遲(以至於不能容忍系統調用的開銷)。此時可以使用運行在用戶空間密碼學安全隨機數生成器。要保證安全性,應當使用內核隨機數生成器生成的隨機數作為用戶空間生成器的種子, 並考慮種子的更新問題。
- 某些應用的工作環境中已有用戶空間密碼學安全隨機數生成器,且提供了完善的使用該生成器生成隨機數的API。例如,若應用程式使用了OpenSSL,則可以使用其RAND_bytes(3)函數;若應用程式使用Java編寫,則可以使用
java.security.SecureRandom。一般而言,這些API底層的用戶空間密碼學安全隨機數生成器將自動使用內核隨機數生成器生成的隨機數作為種子。
- 需要使用內核未包含的額外熵源。例如,Haveged可通過抖動熵(jitterentropy)生成隨機數。若可能,不應使用額外的熵源完全替代內核的隨機數生成器,而應當與內核隨機數生成器共同使用,為用戶空間密碼學安全隨機數生成器提供種子。此外,也可以將高熵數據寫入
/dev/random,寫入的數據最終將影響內核隨機數生成器(由於內核密碼學安全隨機數生成器的更新機制,可能需要至多60秒才能生效)。需要注意,內核默認已經使用RDSEED等其它硬體隨機數源作為熵源。
- Kernel RNG improvements:
- random: replace non-blocking pool with a Chacha20-based CRNG - introduced the ChaCha20 CRNG (2016)
- random: try to actively add entropy rather than passively wait for it - made CPU-based jitterentropy be used as a fallback (2019)
-
Removing the Linux /dev/random blocking pool - made
/dev/randomuse a CRNG, just like/dev/urandom, and not try to provide "true" randomness (2020) - Random number generator enhancements for Linux 5.17 and 5.18 (2022)
- random: use simpler fast key erasure flow on per-cpu keys - simplified and optimized the CRNG design (2022)
- random: do not pretend to handle premature next security model - made new entropy be used more quickly (2022)
-
random: opportunistically initialize on /dev/urandom reads - made
/dev/urandomas safe as/dev/randomon x86 (2022)
- Randomness - A popular science article explaining different RNGs
- ENT - A simple program for testing random sequences (entropy, Chi square test, Monte Carlo, correlation, etc.)
- An Analysis of OpenSSL's Random Number Generator - Paper on RNG reseeding risks in OpenSSL functionality