为什么在 OpenSSL 1.1 中 ECC 签名验证需要随机数(有时需要很长时间)?
Why does ECC signature verification need random numbers (sometimes taking a long time) in OpenSSL 1.1?
我正在研究 Linux 使用 ECC 证书的启动时 (kinit) 签名检查器,正在切换
从原始 RSA 签名到 CMS 格式的 ECC 签名。在这样做的过程中,我发现
CMS_Verify()
函数停止,直到内核打印 "crng init done",表明它需要 wait for there to be enough system entropy for cryptographically secure random number generation。由于系统中没有其他任何事情发生,因此在 Beaglebone Black 上花费了大约 90 秒。
这让我很吃惊,我原以为证书生成或签名生成需要安全随机数,但在 public 密钥签名验证中没有任何秘密需要保护。那么给出了什么?
(我想通了,但没能在其他地方找到解决方案,所以下面是其他人的答案)。
通过艰苦的 printf 调试过程(我最好的选择是 kinit),我发现基本的 ECC 操作使用随机数来防御边信道攻击。这称为 "blinding" 并通过添加一些不确定性来帮助防止攻击者根据计算花费的时间、缓存未命中、功率峰值等来猜测秘密。
来自 OpenSSL 源代码深处的评论:
/*-
* Computes the multiplicative inverse of a in GF(p), storing the result in r.
* If a is zero (or equivalent), you'll get a EC_R_CANNOT_INVERT error.
* Since we don't have a Mont structure here, SCA hardening is with blinding.
*/
int ec_GFp_simple_field_inv(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
BN_CTX *ctx)
然后该函数继续调用 BN_priv_rand_range()
。
但是在 public 密钥签名验证中没有要保护的秘密。为了解决这个问题,在我的 kinit 中,我只是用一组固定的随机选择数据预播 OpenSSL 随机数生成器,如下所示:
RAND_seed( "\xe5\xe3[...29 other characters...]\x9a", 32 );
如果您的程序使用秘密或生成任何密钥、签名或随机数,请不要这样做。在签名检查 kinit 中它没问题。在一个需要更高安全性的程序中,我可以从片上 RNG 硬件 (/dev/hw_random) 中播种数据,或者在安全存储中保存一些熵(如果有的话),或者将其吸收并等待 crng init完成。
我正在研究 Linux 使用 ECC 证书的启动时 (kinit) 签名检查器,正在切换
从原始 RSA 签名到 CMS 格式的 ECC 签名。在这样做的过程中,我发现
CMS_Verify()
函数停止,直到内核打印 "crng init done",表明它需要 wait for there to be enough system entropy for cryptographically secure random number generation。由于系统中没有其他任何事情发生,因此在 Beaglebone Black 上花费了大约 90 秒。
这让我很吃惊,我原以为证书生成或签名生成需要安全随机数,但在 public 密钥签名验证中没有任何秘密需要保护。那么给出了什么?
(我想通了,但没能在其他地方找到解决方案,所以下面是其他人的答案)。
通过艰苦的 printf 调试过程(我最好的选择是 kinit),我发现基本的 ECC 操作使用随机数来防御边信道攻击。这称为 "blinding" 并通过添加一些不确定性来帮助防止攻击者根据计算花费的时间、缓存未命中、功率峰值等来猜测秘密。
来自 OpenSSL 源代码深处的评论:
/*-
* Computes the multiplicative inverse of a in GF(p), storing the result in r.
* If a is zero (or equivalent), you'll get a EC_R_CANNOT_INVERT error.
* Since we don't have a Mont structure here, SCA hardening is with blinding.
*/
int ec_GFp_simple_field_inv(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
BN_CTX *ctx)
然后该函数继续调用 BN_priv_rand_range()
。
但是在 public 密钥签名验证中没有要保护的秘密。为了解决这个问题,在我的 kinit 中,我只是用一组固定的随机选择数据预播 OpenSSL 随机数生成器,如下所示:
RAND_seed( "\xe5\xe3[...29 other characters...]\x9a", 32 );
如果您的程序使用秘密或生成任何密钥、签名或随机数,请不要这样做。在签名检查 kinit 中它没问题。在一个需要更高安全性的程序中,我可以从片上 RNG 硬件 (/dev/hw_random) 中播种数据,或者在安全存储中保存一些熵(如果有的话),或者将其吸收并等待 crng init完成。