OpenSSL

密碼學和 SSL/TLS 工具包

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。

另請參閱

RAND(7)EVP_RAND(3)

歷史

此功能在 OpenSSL 3.0 中新增。

版權所有 2017-2020 OpenSSL 專案作者。保留所有權利。

在 Apache 授權條款 2.0(「授權條款」)下授權。您不得使用此檔案,除非符合授權條款。您可以在原始程式碼散佈中的 LICENSE 檔案或 https://www.openssl.org/source/license.html 取得副本。