我试图让 openssl 生成确定性的私有和公共 RSA 密钥对。这个想法是我用一些设备相关数据的哈希填充我的种子缓冲区,并将其用作种子。但是播种 RAND 似乎不起作用,密钥仍然是随机的。
由于种种原因,我不想只生成一次密钥,然后存储它,我只希望私钥存在于内存中。
RAND_seed(seedbuf, sizeof(seedbuf));
bne = BN_new();
if (1 != BN_set_word(bne,e)) {
goto free_stuff;
}
keypair = RSA_new();
if(1 != RSA_generate_key_ex(keypair, KEY_LENGTH, bne, NULL)) {
goto free_stuff;
}
Run Code Online (Sandbox Code Playgroud)
所以基本上我希望“RSA_generate_key_ex”函数返回相同的密钥对,每次用相同的输入播种。
使 openssl 生成确定性密钥...
我不相信你可以开箱即用。默认情况下,OpenSSL 使用md_rand, 并且自动种子本身。调用rand_seed内部调用rand_add,这增加了的状态(而不是丢弃/更换状态)。您可以找到md_randin的来源crypto/rand/md_rand.c。
如果您在构建时FIPS启用,则有来自 NIST 的 SP 800-90 的确定性随机位生成器。但是,我似乎记得它们的操作方式与md_rand. 也就是说,您可以添加到内部状态,但您无法真正控制它。您可以在crypto/rand/rand_lib.c.
我想你只有一种选择。您可以创建自己的my_rand. 它基于块密码或哈希。在启动时,用设备相关数据为其播种,然后返回确定性字节。
现在,要获得RSA_generate_key_ex使用 PRNG 之类的功能,您必须将其打包在 OpenSSL 中ENGINE。OpenSSL 的 Richard Levitte 在引擎构建第 1 课:最小无用引擎和引擎构建第 2 课: OpenSSL 博客上的示例 MD5 引擎中有一个很好的两系列博客。
一旦你把它和引擎打包在一起,你就可以像这样使用它。使用 设置随机方法后ENGINE_METHOD_RAND,您将使用您的算法。
ENGINE* eng = ENGINE_by_id("my_rand");
unsigned long err = ERR_get_error();
if(NULL == eng) {
fprintf(stderr, "ENGINE_by_id failed, err = 0x%lx\n", err);
abort(); /* failed */
}
int rc = ENGINE_init(eng);
err = ERR_get_error();
if(0 == rc) {
fprintf(stderr, "ENGINE_init failed, err = 0x%lx\n", err);
abort(); /* failed */
}
rc = ENGINE_set_default(eng, ENGINE_METHOD_RAND);
err = ERR_get_error();
if(0 == rc) {
fprintf(stderr, "ENGINE_set_default failed, err = 0x%lx\n", err);
abort(); /* failed */
}
Run Code Online (Sandbox Code Playgroud)
如果你想看看一个ENGINE实现,看看该rdrand发动机crypto/engine/eng_rdrand.c。引擎没有太多内容,复制/粘贴很容易。请务必将新引擎添加到Makefilein 中crypto/engine/Makefile。
如果您正在寻找一种不一定使用 OpenSSL 生成确定性密钥的方法,GnuTLS可能可以提供帮助:
certtool --generate-privkey --outfile privkey.pem --key-type=rsa --sec-param=high --seed=0000000000000000000000000000000000000000000000000000000000000000
Run Code Online (Sandbox Code Playgroud)
--seed至少在当前版本中使用意味着使用--provable算法生成 (FIPS PUB186-4)。
生成的privkey.pem将为 RSA-PSS 格式,您可以使用以下命令将其转换为原始 RSA 格式:
certtool --to-rsa --load-privkey privkey.pem --outfile privkey.key
Run Code Online (Sandbox Code Playgroud)
然后,如果需要,您可以从任一格式的密钥生成自签名证书:
certtool --generate-self-signed --load-privkey privkey.key --outfile signed.crt --template cert.cfg
Run Code Online (Sandbox Code Playgroud)
如果您也希望使此步骤具有确定性或避免每次运行命令时回答问题,请将--template cert.cfg参数添加到最后一个命令。cert.cfg使生成具有确定性的最小文件内容为:
serial = 1
activation_date = "2019-01-01 00:00:00 UTC"
expiration_date = "2029-01-01 00:00:00 UTC"
Run Code Online (Sandbox Code Playgroud)