RSA 2048 密钥对生成:通过 openssl 0.5s 通过 gpg 30s,为什么不同?

hum*_*ace 9 gpg random openssl

RSA 2048 密钥对生成:通过 openssl 0.5s 通过 gpg 30s,为什么不同 有几个程序可以生成 RSA 公钥/私钥对

例如,GnuPG/OpenPGP 有一个 wizzard 通过

gpg --gen-key

OpenSSL 可以使用这些命令行生成密钥对

openssl genrsa -out testkey.private 2048
openssl rsa -in testkey.private -pubout -out testkey.public

对于同样的事情,即生成一个密钥对 RSA 2048 位,我可以在同一台机器上感知到非常不同的时间。

openssl在大约 0.5 秒内生成一个密钥对大约
gpg需要 30 甚至广告“移动鼠标以生成随机性/熵”

能解释一下区别吗?我知道 gpg 比创建 RSA 密钥还要多一些,但我确实选择了选项 (4)

请选择您想要的密钥类型:
   (1) RSA 和 RSA(默认)
   (2) DSA 和 Elgamal
   (3) DSA(仅签名)
   (4) RSA(仅签名)
你的选择?

因此,真正生成的唯一东西是 2048 位 RSA 密钥对。然而时差却是惊人的 30 秒?

在我看来,要么 gpg 浪费了不必要的时间,要么 OpenSSL 没有等待足够的时间,因此创建了不安全的密钥。

我的问题是什么可以解释这种差异?

更新

RSA 创建必须将一些随机性作为输入。因此,为了确保快速的 openssl 不仅仅是使用一些存储的随机性的结果,我多次批量运行它

time bash -c "for i in {1..50}; do openssl genrsa -out /dev/null 2048 ; done;"

这产生

真正的 0m16.577s
用户 0m16.309s
系统 0m0.092s

也就是说,对于 50 个 2048 位 RSA 密钥(我假设需要大量的熵/随机性),openssl 仍然只需要 16 秒。因此,我在这里的假设是必须打破 openssl 的“答案”。毕竟我不信任我的 Linux(一个 3.2.0-59 内核)在产生随机性方面变得如此出色。

也许区别只是 openssl 使用/dev/urandom和 gpg 使用/dev/random,如果真的可以解释时差,我的问题是我不知道我将如何发现这一点,以验证这一点。

更新2

为了测试我使用的 openssl 的随机源

strace -xe trace=file,read,write,close openssl genrsa -out testkey5.private 2048 2>&1 | grep 随机 -A1

这产生

open("/dev/urandom", O_RDONLY|O_NOCTTY|O_NONBLOCK) = 4
读(4,“\x21\xd8\xaa\xf1\x2b\x5f\x4a\x89\x5d\x6c\x58\x82\xc1\x88\x21\x04\xfa\x5b\x18\x98\x8a\x34\ x2b\xe3\xf3\xc0\xb1\xef\xfb\x44\x15\x09", 32) = 32

所以似乎来自/dev/urandom(不是“更好” /dev/random)的32 个字节对于 openssl 中的 2048 位 RSA 密钥对来说已经足够了。因此它是如此之快!

测量

2048bit RSA密钥对生成方式

  • 仅 32 字节/dev/urandom(使用 openssl)
  • 300 字节/dev/random(使用 openPGP GNU Privacy Guard)

这当然解释了时差!

Hau*_*ing 10

GnuPG/dev/random为它实际使用的每个随机字节消耗几个字节。您可以使用以下命令轻松检查:

start cmd:> strace -e trace=open,read gpg --armor --gen-random 2 16 2>&1 | tail
open("/etc/gcrypt/rngseed", O_RDONLY)   = -1 ENOENT (No such file or directory)
open("/dev/urandom", O_RDONLY)          = 3
read(3, "\\\224F\33p\314j\235\7\200F9\306V\3108", 16) = 16
open("/dev/random", O_RDONLY)           = 4
read(4, "/\311\342\377...265\213I"..., 300) = 128
read(4, "\325\3\2161+1...302@\202"..., 172) = 128
read(4, "\5[\372l\16?\...6iY\363z"..., 44) = 44
open("/home/hl/.gnupg/random_seed", O_WRONLY|O_CREAT, 0600) = 5
cCVg2XuvdjzYiV0RE1uzGQ==
+++ exited with 0 +++
Run Code Online (Sandbox Code Playgroud)

为了输出 16 字节的高质量熵,GnuPG 从/dev/random.

这在这里解释:随机数子系统架构

Linux 最多可存储 4096 字节(请参阅 参考资料cat /proc/sys/kernel/random/poolsize)的熵。如果进程需要的多于可用的资源(请参阅 参考资料cat /proc/sys/kernel/random/entropy_avail),那么 CPU 使用率或多或少变得无关紧要,因为内核熵池的馈送速度成为相关因素。

  • @HumanityANDpeace 随机性是一个无休止的讨论。不久前,该网站的“主用户”声称“/dev/urandom”足以用于加密目的。在 GnuPG 邮件列表上,他可能会因此而被嘲笑。AFAIK 不可能证明某些数据是纯粹随机的。你可以找到非随机性,但只能在你寻找确切的模式的地方。 (2认同)
  • @HaukeLaging 这个站点的“主用户”从 [security.se] 和 [crypto.se] 的“主用户”那里得到了这个建议,并给出了一个有意义的解释(不像 Linux 的熵池大小计算,它不)。[来自 /dev/urandom 的 rand 是否安全用于登录密钥?](http://security.stackexchange.com/questions/3936/is-a-rand-from-dev-urandom-secure-for-a-login -key/3939#3939) “简短的回答是肯定的。长答案也是肯定的。” (2认同)
  • 从种子良好的 CSPRNG 读取的 32 个字节提供了 256 位的安全性(这是[*一大堆*](http://crypto.stackexchange.com/questions/1145/how-much-would-it-cost-in- us-dollars-to-brute-force-a-256-bit-key-in-a-year/1160#1160))。RSA-2048 位密钥仅提供大约 112 位的安全性。`/dev/urandom` 唯一可疑的属性是(在 linux 上)它在启动后直接播种之前不会阻塞。一旦播种,它将永远保持安全。 (2认同)

Ant*_*hon 7

您认为这种差异是因为openssl使用 /dev/urandom 并gpg使用的建议/dev/random是正确的。

您可以在使用以下命令生成密钥时观察可用熵的下降gpg

watch -n 1 cat /proc/sys/kernel/random/entropy_avail
Run Code Online (Sandbox Code Playgroud)

我使用了一个程序来生成设置 OpenGPG 智能卡gpg的步骤描述,因此我不得不gpg多次运行,直到一切都按预期进行。在初始运行后,我注意到/dev/random没有足够的熵,gpg 会停止等待新的熵累积。

我写了一个小程序来提供额外的非随机数据,这样做时gpg不会“停止”而是几乎立即生成密钥:测试脚本是否正确运行很好,但当然不是在生成真实数据时应该做的事情键。

加速程序gpg不要在实际情况下使用):

# For testing purposes only 
# DO NOT USE THIS, tHIS DOES NOT PROVIDE ENTROPY TO /dev/random

import fcntl
import time
import struct

RNDADDENTROPY=0x40085203

while True:
    random = "3420348024823049823-984230942049832423l4j2l42j"
    t = struct.pack("ii32s", 8, 32, random)
    with open("/dev/random", mode='wb') as fp:
        # as fp has a method fileno(), you can pass it to ioctl
        res = fcntl.ioctl(fp, RNDADDENTROPY, t)
        time.sleep(0.001)
Run Code Online (Sandbox Code Playgroud)

当我在观看时运行它时,entropy_avail我可以看到可用的熵超过 3800。