C RAND_字节不';同一粒种子不能产生同样的结果

C RAND_字节不';同一粒种子不能产生同样的结果,c,openssl,pbkdf2,C,Openssl,Pbkdf2,我正在尝试使用OpenSSL编程自定义RSA密钥对生成算法。我使用了PKCS5_PBKDF2_HMAC_SHA1函数来生成PRNG种子,因此,我将此种子用作RAND_种子输入 不幸的是,每次我调用RAND_bytes,使用相同的种子,我都会得到不同的随机数,但这不是预期的行为,因为正如所说,随机数生成器的答案是确定性的(相同的种子,相同的输出) 下面是测试用例。我也声明了常量种子,但生成永远不是确定性的 unsigned int seed = 0x00beef00; unsigned int r

我正在尝试使用OpenSSL编程自定义RSA密钥对生成算法。我使用了
PKCS5_PBKDF2_HMAC_SHA1
函数来生成PRNG种子,因此,我将此种子用作RAND_种子输入

不幸的是,每次我调用
RAND_bytes
,使用相同的种子,我都会得到不同的随机数,但这不是预期的行为,因为正如所说,随机数生成器的答案是确定性的(相同的种子,相同的输出)

下面是测试用例。我也声明了常量种子,但生成永远不是确定性的

unsigned int seed = 0x00beef00;
unsigned int rnum[5];
RAND_seed(&seed, sizeof(seed));
RAND_bytes((unsigned char *)&rnum[0], sizeof(rnum));

错误在哪里?

这不是错误。OpenSSL随机数生成器使用良好的随机性源自行进行一些种子设定

因此,在
RAND_seed
中使用相同的种子值不能保证相同的随机数序列。这是一件好事,因为它使它们更不可预测,因此更安全

RAND_seed
的手册页:

#包括
void RAND_seed(const void*buf,int num);
void RAND_add(const void*buf,int num,双熵);
国际随机状态(无效);
int RAND_事件(UINT iMsg、WPARAM WPARAM、LPARAM LPARAM);
无效随机屏幕(无效);
RAND_add()。因此,如果
buf
的数据对于对手来说是不可预测的,这会增加 状态的不确定性使得PRNG输出更少 可预测的适当的输入来自用户交互(随机键 按键、鼠标移动)和某些硬件事件。
参数是对随机性的估计(下限) 包含在buf中,以字节为单位。资料来源详情 随机性和如何估计它们的熵可以在 文献,如RFC 1750

RAND\u add()
密码。无法从PRNG恢复种子值
输出

OpenSSL确保每个线程的PRNG状态是唯一的。 在提供“/dev/uradom”的系统上,随机性设备是 用于透明地为PRNG播种。但是,在所有其他系统上, 应用程序负责通过调用
RAND\u add()
RAND\u egd(3)
RAND\u load\u文件(3)

RAND\u seed()
等同于
RAND\u add()
num==entropy


因此,如果您的系统具有
/dev/uradom
,它将用作PRNG的初始种子。

Openssl的
int RAND_字节(无符号字符*buf,int num)尝试使事情尽可能随机。这显然是一个你不想要的特性,而是寻找一个可重复的伪随机序列

但是Openssl也有很多优点

int RAND\u伪字节(无符号字符*buf,int num)

这可能就是你想要的,伪序列,给你一个可重复的序列

另一方面,如果你在做RSA,一个可重复的随机序列并不是那么好,因为你要找的是两个大素数。做一个大的PRNG数,然后测试素数可能是个坏主意。其中一半可以被2整除:)

如果我没记错的话,你需要选择一个好的起始数字,用1进行ORing,使之成为奇数,然后测试素数,如果不是,则增加4,然后再试一次

一旦找到它们,您可能就不想再使用可重复的PRNG字节开始搜索了

虽然我很确定这是一个学习项目,但如果你想要的只是openssl中的RSA密钥对,请检查一下


您好,谢谢您的回复,我尝试了RAND_伪字节,但它总是为同一种子提供随机输出。我需要为相同的输入生成相同的输出,因为我的密钥对对于单个设备必须是唯一的,由一些参数标识。
RAND\u pseudo\u bytes
将PID、时间等混合到其状态中。分叉也混合在新的状态。检查源文件中是否有。@jww我从中尝试了测试程序,得到了一个可重复的序列。我的版本与您的源代码版本有什么不同,我不能说。但是一个可重复的伪随机序列对于Monte Carlo程序之类的东西是有用的,所以我很惊讶这种能力是否已经被证明了lost@CrescenzoMugione. 即使你得到了一个可重复的序列,你也得到了一个非常弱的系统。这类似于Debian曾经犯过的错误,他们的openssh只生成32K唯一的会话密钥,因为最终他们的种子仅仅基于PID。像MAC地址这样的东西甚至不是好的秘密,因为你子网上的每个人都可以得到它。请记住,约翰·冯·诺伊曼曾经说过:“任何考虑产生随机数字的算术方法的人,当然都处于罪恶状态。”[嗨,感谢你的回答,从主题中可以看出,“PRNG是确定性的(相同的种子意味着相同的输出序列)并产生随机位。”@PRNG是确定性的。这里的区别是OpenSSL透明地使用来自
/dev/uradom
随机种子
随机种子添加
的随机数据为PRNG种子。可以多次调用以添加种子数据。因此,当您调用其中一个函数时,给定的种子缓冲区将添加到数据中来自
/dev/random
。这有助于增加随机性,并使任何生成的字节不可预测。假设您使用默认的
RAND
引擎,请检查源代码。另请参阅关于堆栈溢出。简短的是,您必须创建一个OpenSSL
引擎
。要创建自定义引擎,请参阅和onOpenSSL博客。
    #include <openssl/rand.h>

    void RAND_seed(const void *buf, int num);

    void RAND_add(const void *buf, int num, double entropy);

    int  RAND_status(void);

    int  RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam);
    void RAND_screen(void);