EVP_RAND
名稱
EVP_RAND - 隨機位元產生器
語法
#include <openssl/evp.h>
#include <rand.h>
說明
OpenSSL RAND 預設方法基於 EVP_RAND 類別,提供非決定性輸入給其他密碼演算法。
RAND API 是「前端」,供應用程式開發人員取得隨機位元;而 EVP_RAND API 則作為「後端」,將前者與作業系統的熵來源連接起來,並提供決定性隨機位元產生器 (DRBG) 及其組態參數。DRBG 是一種特定類型的密碼安全偽隨機數產生器 (CSPRNG),說明見 [NIST SP 800-90A Rev. 1]。
免責聲明
除非您對隨機產生器有非常具體的要求,否則通常不需要直接使用 EVP_RAND API。取得隨機位元的常見方法是使用 RAND_bytes(3) 或 RAND_priv_bytes(3),另請參閱 RAND(7)。
常見使用案例
以下列舉此類特殊使用案例的常見範例
您想要使用自己的私人 DRBG 執行個體。僅由單一執行緒存取的多個 DRBG 執行個體可提供額外的安全性(因為它們的內部狀態是獨立的),並在多執行緒應用程式中提供更好的可擴充性(因為它們不需要鎖定)。
您需要整合先前不支援的熵來源。請參閱 provider-rand(7),以取得支援將隨機性來源新增至 EVP_RAND 的實作詳細資料。
您需要變更 OpenSSL RAND 標準實作的預設設定,以符合特定要求。
EVP_RAND 連鎖
EVP_RAND 執行個體可以用作另一個 EVP_RAND 執行個體的熵來源,前提是它本身可以存取有效的熵來源。作為熵來源的 EVP_RAND 執行個體稱為「父項」,另一個執行個體稱為「子項」。通常,子項會是 DRBG,因為子項成為熵來源沒有意義。
這稱為連鎖。連鎖的 EVP_RAND 執行個體是透過將父項 EVP_RAND_CTX 的指標傳遞為 EVP_RAND_CTX_new() 呼叫的引數而建立的。可以建立連續兩個以上的 DRBG 連鎖。也可以使用任何 EVP_RAND_CTX 類別作為父項,但只有即時熵來源可以忽略其父項並不用它。
三個共用 DRBG 執行個體
目前有三個共用 DRBG 執行個體,分別是 <primary>、<public> 和 <private> DRBG。<primary> DRBG 是單一全球執行個體,而 <public> 和 <private> DRBG 則會在每個執行緒中建立,並透過執行緒本機儲存空間存取。
預設情況下,函式 RAND_bytes(3) 和 RAND_priv_bytes(3) 分別使用執行緒本機的 <public> 和 <private> DRBG 執行個體。
<primary> DRBG 執行個體
<primary> DRBG 並非由應用程式直接使用,僅用於重新播送其他兩個 DRBG 執行個體。它會從作業系統的熵來源取得隨機性,或使用先前透過 RAND_add(3) 加入的隨機性來重新播送自身。
<public> DRBG 執行個體
此執行個體預設由 RAND_bytes(3) 使用。
<private> DRBG 執行個體
此執行個體預設由 RAND_priv_bytes(3) 使用。
鎖定
<primary> DRBG 旨在讓其子 DRBG 執行個體在重新播送時同時存取。必要的鎖定會在內部進行。透過 EVP_RAND 介面直接存取 <primary> DRBG 並非 執行緒安全。<public> 和 <private> DRBG 是執行緒本機的,亦即每個執行緒都有各自的執行個體。因此,它們可以透過 EVP_RAND 介面安全地存取,無需鎖定。
可以使用 RAND_get0_primary()、RAND_get0_public() 和 RAND_get0_private() 分別取得這些 DRBG 執行個體的指標。請注意,不允許將執行緒本機 DRBG 執行個體的指標儲存在變數或其他記憶體位置,因為多個執行緒會存取並使用這些位置。
應用程式建立的所有其他 DRBG 執行個體都不支援鎖定,因為它們旨在由單一執行緒使用。建議為每個執行緒建立個別的 DRBG 執行個體,而非讓不同的執行緒同時存取單一 DRBG 執行個體。將 <primary> DRBG 用作不同執行緒上多個 DRBG 執行個體的熵來源是執行緒安全的,因為 DRBG 執行個體會自動鎖定 <primary> DRBG 以取得隨機輸入。
整體概觀
下圖概述了 DRBG 執行個體如何協同運作並被使用的概況。
+--------------------+
| os entropy sources |
+--------------------+
|
v +-----------------------------+
RAND_add() ==> <primary> <-| shared DRBG (with locking) |
/ \ +-----------------------------+
/ \ +---------------------------+
<public> <private> <- | per-thread DRBG instances |
| | +---------------------------+
v v
RAND_bytes() RAND_priv_bytes()
| ^
| |
+------------------+ +------------------------------------+
| general purpose | | used for secrets like session keys |
| random generator | | and private keys for certificates |
+------------------+ +------------------------------------+
取得隨機位元組的通常方式是呼叫 RAND_bytes(...) 或 RAND_priv_bytes(...)。這些呼叫大致等於分別呼叫 EVP_RAND_generate(<public>, ...) 和 EVP_RAND_generate(<private>, ...)。
重新播種
DRBG 執行個體會自動播種,從其熵源中提取隨機輸入。熵源可以是受信任的操作系統熵源,或是有權存取此類來源的另一個 DRBG。
在預先定義的產生請求次數後,會發生自動重新播種。受信任熵源的選擇會在建置時使用 --with-rand-seed 選項進行設定。下列各節會更詳細地說明重新播種程序。
自動重新播種
在滿足產生請求 (EVP_RAND_generate(3)) 之前,如果符合下列其中一個條件,DRBG 會自動重新播種
- DRBG 尚未執行個體化 (= 播種) 或已取消執行個體化。
- 自上次重新播種以來,產生請求的次數超過某個閾值,即所謂的 reseed_interval。可以透過將 reseed_interval 設為 0 來停用此行為。
- 自上次重新播種以來經過的時間超過某個時間區間,即所謂的 reseed_time_interval。可以透過將 reseed_time_interval 設為 0 來停用此行為。
- DRBG 處於錯誤狀態。
注意:如果在 DRBG 播種或重新播種時熵源發生故障,就會進入錯誤狀態。最後一個案例確保 DRBG 在熵源再次可用時自動從錯誤中復原。
手動重新播種
除了自動重新播種之外,呼叫者可以在呼叫 EVP_RAND_generate(3) 時將 prediction resistance 參數設為 1,以使用新的熵請求 DRBG 立即重新播種。
文件 [NIST SP 800-90C] 詳細說明預測阻抗請求,並對核准提供預測阻抗的熵源施加嚴格的條件。只有從即時熵源提取新的熵才能滿足預測阻抗請求 ([NIST SP 800-90C] 的第 5.5.2 節)。使用者必須確保已設定並正在使用即時熵源。
對於三個共用 DRBG(僅限於這些 DRBG),還有另一種手動重新播種的方式:如果 RAND_add(3) 被呼叫,並帶有正向的 randomness 參數(或 RAND_seed(3)),這會立即重新播種 <primary> DRBG。<public> 和 <private> DRBG 會在它們的下一個產生呼叫中偵測到這一點,並重新播種,從 <primary> 提取隨機性。
最後一項功能已新增,以支援在呼叫 RAND_bytes() 之前呼叫 RAND_add() 的常見做法,並用於以前的 OpenSSL 版本。
熵輸入和附加資料
DRBG 區分兩種不同類型的隨機輸入:來自受信任來源的 entropy,以及使用者可以選擇性地新增且被視為不受信任的 additional input。不僅在重新播種時,也可以在每個產生請求中新增 additional input。
設定亂數種子來源
在多數情況下,OpenSSL 會自動選擇適合的種子來源,用於自動播種及重新播種其<primary> DRBG。然而,在某些情況下,需要在組態期間使用 --with-rand-seed 選項,明確指定種子來源。如需更多資訊,請參閱 INSTALL 說明。此外,也有一些作業系統沒有種子來源,且預設會停用自動重新播種。
以下兩個區段說明主要 DRBG 的重新播種程序,視自動重新播種是否可用而定。
在啟用自動播種的情況下重新播種主要 DRBG
不需要呼叫 RAND_poll() 或 RAND_add(),因為 DRBG 會自動從其來源取得必要的熵。然而,這兩個呼叫都是允許的,而且會重新播種 RNG。
RAND_add() 可用於新增兩種隨機輸入,視 randomness 參數的值而定
- randomness == 0
-
隨機位元組會混合為額外的輸入,進入 DRBG 的目前狀態。混合額外的輸入不被視為完整的重新播種,因此重新播種計數器不會重設。
- randomness > 0
-
如果 DRBG 已實例化(或未實例化或處於錯誤狀態),隨機位元組會用作完整重新播種(或重新實例化)的熵輸入。重新播種所需的隨機位元數由 DRBG 的安全性強度決定。目前預設為 256 位元(32 位元組)。可以提供少於所需的隨機性。在這種情況下,會從受信任的熵來源取得遺失的隨機性。
注意:在 FIPS 模式中*不允許*手動重新播種,因為 [NIST SP-800-90Ar1] 規定實例化(第 9.1 節)或重新播種(第 9.2 節)的熵*不得*由使用應用程式提供。因此,會忽略 randomness 參數,而 RAND_add(3) 和 RAND_seed(3) 呼叫提供的隨機位元組會視為額外資料。
在停用自動播種的情況下重新播種主要 DRBG
呼叫 RAND_poll() 永遠會失敗。
需要呼叫 RAND_add() 進行初始播種和定期重新播種。至少必須提供 48 位元組(384 位元)的隨機性,否則 DRBG 的(重新)播種會失敗。這相當於 DRBG 安全性強度的 1.5 倍。額外的 0.5 倍用於實例化期間的隨機數。
更精確地說,播種所需的位元組數取決於 DRBG 的安全性強度,預設設定為 256。
另請參閱
歷史
此功能在 OpenSSL 3.0 中新增。
版權
版權所有 2017-2020 OpenSSL 專案作者。保留所有權利。
在 Apache 授權條款 2.0(「授權條款」)下授權。您不得使用此檔案,除非符合授權條款。您可以在原始程式碼散佈中的 LICENSE 檔案或 https://www.openssl.org/source/license.html 取得副本。