【问题标题】:RAND_bytes doesn't give the same result from the same seed [duplicate]RAND_bytes 不会从同一个种子中给出相同的结果[重复]
【发布时间】:2017-05-08 03:21:35
【问题描述】:

我正在尝试使用 OpenSSL 编写自定义 RSA 密钥对生成算法。我已经使用PKCS5_PBKDF2_HMAC_SHA1 函数来生成 PRNG 种子,所以我使用这个种子作为 RAND_seed 输入。

不幸的是,每次我使用相同的种子调用RAND_bytes 时,我都会获得不同的随机数,但这不是预期的行为,因为正如How can one securely generate an asymmetric key pair from a short passphrase? 的答案所说,随机数生成器是确定性的(相同的种子相同的输出)。

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

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

哪里出错了?

【问题讨论】:

标签: c openssl pbkdf2


【解决方案1】:

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

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

来自RAND_seed 的手册页:

    #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);

RAND_add()buf 处的 num 字节混合到 PRNG 状态。因此,如果 buf 的数据对于对手来说是不可预测的,这增加了 状态的不确定性并使 PRNG 输出更少 可预测的。合适的输入来自用户交互(随机键 按下、鼠标移动)和某些硬件事件。 entropy 参数是(的下限)对随机性的估计 包含在 buf 中,以字节为单位。有关来源的详细信息 随机性以及如何估计它们的熵可以在 文学,例如RFC 1750。

RAND_add() 可能会使用敏感数据(例如用户输入)调用 密码。种子值无法从 PRNG 中恢复 输出。

OpenSSL 确保 PRNG 状态对于每个线程都是唯一的。 在提供“/dev/urandom”的系统上,随机设备是 用于透明地播种 PRNG。 但是,在所有其他系统上, 应用程序负责通过调用播种 PRNG RAND_add()RAND_egd(3)RAND_load_file(3)

RAND_seed() 等价于RAND_add() num == entropy

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

【讨论】:

  • 您好,感谢您的回复,主题为crypto.stackexchange.com/questions/1662/…,它说“PRNG 是确定性的(相同的种子意味着相同的输出序列)并产生随机位。”
  • @CrescenzoMugione PRNG 是确定性的。这里的不同之处在于,OpenSSL 使用来自/dev/urandom 的随机数据透明地为 PRNG 播种。可以多次调用RAND_seedRAND_add 来添加种子数据。因此,当您调用其中一个函数时,给定的种子缓冲区会添加到从/dev/random 提取的数据中。这有助于增加随机性并使任何生成的字节不可预测。
【解决方案2】:

Openssl 的int RAND_bytes(unsigned char *buf, int num); 试图让事情尽可能随机。这显然是您不想要的功能,而是在寻找可重复的伪随机序列

但是Openssl也有

int RAND_pseudo_bytes(unsigned char *buf, int num);

这可能是您正在寻找的,部分,为您提供可重复的序列。

https://linux.die.net/man/3/rand_pseudo_bytes

Force openssl's RNGs to return a repeatable byte sequence

顺便说一句,如果您正在使用 RSA,那么可重复的随机序列并不是那么好,因为您要寻找的是两个大素数。做一个大的 PRNG 数字,然后测试素数可能是一个坏主意。其中一半可以被 2 整除! :)

如果我没记错的话,您需要选择一个好的起始数字,通过与 1 进行 ORing 使其为奇数,然后测试素数,如果不是,则增加 4 并重试。

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

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

https://stackoverflow.com/a/5246045/6047952

【讨论】:

  • 您好,感谢您的回复,我尝试了 RAND_pseudo_bytes,但它总是给我相同种子的随机输出。我需要为相同的输入生成相同的输出,因为我的密钥对对于单个设备必须是唯一的,由一些参数标识。
  • RAND_pseudo_bytes 将 PID、时间等混合到其状态中。分叉也混入新的状态。检查md_rand.c and rand_bytes function的源文件。
  • @jww 我已经尝试了stackoverflow.com/a/7510354/6047952 的测试程序,我得到了一个可重复的序列。我的版本与您的源代码版本有何不同我不能说。但是可重复的伪随机序列对于诸如蒙特卡洛程序之类的东西很有用,所以如果这种能力已经丢失,我会很惊讶
  • @CrescenzoMugione。即使你得到了一个可重复的序列,你也得到了一个非常弱的系统。这类似于 Debian 曾经犯的错误,最终导致他们的 openssh 只生成 32K 唯一会话密钥,因为最终他们的种子仅基于 PID。 schneier.com/blog/archives/2008/05/random_number_b.html MAC 地址之类的东西甚至都不是好秘密,因为您子网上的每个人都可以得到它。请记住,约翰·冯·诺依曼曾经说过:“任何考虑用算术方法产生随机数字的人,当然都处于一种犯罪状态。”[
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 2018-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多