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实例提供了额外的安全性(因为它们的内部状态是独立的)以及在多线程应用程序中更好的可扩展性(因为它们不需要被锁定)。
您需要集成以前不支持的熵源。有关支持将随机性源添加到EVP_RAND的实现细节,请参阅provider-rand(7)。
您需要更改标准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)时将预测抵抗参数设置为1来请求DRBG立即使用新熵进行重新播种。
文档[NIST SP 800-90C]详细描述了预测抵抗请求,并对批准用于提供预测抵抗的熵源施加了严格的条件。预测抵抗请求只能通过从活动熵源获取新熵来满足([NIST SP 800-90C]的第5.5.2节)。用户有责任确保配置了活动熵源并正在使用。
对于三个共享的DRBG(仅限于这些),还有另一种方法可以手动重新播种它们:如果RAND_add(3)被调用并带有一个正随机性参数(或RAND_seed(3)),则这将立即重新播种<primary> DRBG。<public>和<private> DRBG将在其下一个生成调用中检测到这一点并重新播种,从<primary>获取随机性。
此功能已添加以支持以前OpenSSL版本中使用的常见做法,即在调用RAND_bytes()之前调用RAND_add()。
熵输入和附加数据
DRBG区分两种不同的随机输入类型:熵,来自受信任的来源,以及附加输入,用户可以选择添加,并被视为不受信任。不仅可以在重新播种期间添加附加输入,还可以针对每个生成请求添加。
配置随机种子源
在大多数情况下,OpenSSL将自动为其<primary> DRBG的自动播种和重新播种选择合适的种子源。但是,在某些情况下,需要在配置期间使用--with-rand-seed选项显式指定种子源。有关更多信息,请参阅INSTALL说明。还有一些操作系统没有可用的种子源,并且默认情况下会禁用自动重新播种。
以下两部分描述了主DRBG的重新播种过程,具体取决于自动重新播种是否可用。
使用启用的自动播种重新播种主DRBG
无需调用RAND_poll()或RAND_add(),因为DRBG会自动从其源获取必要的熵。但是,这两个调用都是允许的,并且确实会重新播种RNG。
RAND_add()可用于添加两种随机输入,具体取决于随机性参数的值
- randomness == 0
-
随机字节作为附加输入混合到DRBG的当前状态中。混合附加输入不被视为完全重新播种,因此重新播种计数器不会重置。
- randomness > 0
-
如果DRBG已实例化(分别为未实例化或处于错误状态),则随机字节将用作完全重新播种(分别为重新实例化)的熵输入。重新播种所需的随机比特数由DRBG的安全强度决定。目前默认为256位(32字节)。可以提供的随机性少于所需。在这种情况下,缺少的随机性将通过从受信任的熵源获取随机输入来获得。
注意:在FIPS模式下,*不允许*手动重新播种,因为[NIST SP-800-90Ar1]规定熵*不得*由使用应用程序提供以进行实例化(第9.1节)或重新播种(第9.2节)。因此,将忽略随机性参数,并且由RAND_add(3)和RAND_seed(3)调用提供的随机字节将被视为附加数据。
使用禁用的自动播种重新播种主DRBG
调用RAND_poll()将始终失败。
需要调用RAND_add()进行初始播种和定期重新播种。必须提供至少48字节(384位)的随机性,否则DRBG的(重新)播种将失败。这对应于DRBG安全强度的1.5倍。额外的0.5倍用于实例化期间的nonce。
更准确地说,播种所需的字节数取决于DRBG的安全强度,默认为256。
参见
历史
此功能是在OpenSSL 3.0中添加的。
版权
版权所有 2017-2020 OpenSSL项目作者。版权所有。
根据Apache许可证2.0(“许可证”)获得许可。除非符合许可证,否则您不得使用此文件。您可以在源代码分发中的LICENSE文件中或https://www.openssl.org/source/license.html获取副本。