【问题标题】:/dev/random returning always the same sequence/dev/random 总是返回相同的序列
【发布时间】:2013-10-09 08:38:10
【问题描述】:

我打算使用 /dev/random 输出作为 openssl 密钥生成的种子,然后我编写了这个小程序来检查我要做什么:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#define LEN 128

void uc2hex(char* hex, unsigned char* uc, unsigned short uc_len)
{
    FILE* bp=fmemopen(hex,2*uc_len+1,"w");
    unsigned short i;
    for(i=0;i<uc_len;i++)
    {
        fprintf(bp,"%02x",uc[i]);
        //printf("%02x\n",uc[i]);
        //fprintf(bp,"%d-",i);
    }
    fprintf(bp,"%c",'\0');
    fclose(bp);
}

int main()
{
    unsigned char buf[LEN];
    char str[2*LEN+1];
    int fd=open("/dev/random",O_RDONLY);
    read(fd,buf,LEN);
    uc2hex(str,buf,LEN);
    printf("%s\n",str);
    close(fd);
    return 0;
}

我运行程序一到两次,一切似乎都运行良好,但随后我又在短时间内再次运行了四次,这是输出:

[walter@eM350 ~]$ ./random 
0ee08c942ddf901af1278ba8f335b5df8db7cf18e5de2a67ac200f320a7a20e84866f533667a7e66a4572b3bf83d458e6f71f325783f2e3f921868328051f8f296800352cabeaf00000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000
[walter@eM350 ~]$ ./random 
1f69a0b931c16f796bbb1345b3f58f17f74e3df600000000bb03400000000000ffffffff00000000880e648aff7f0000a88103b4d67f000000305cb4d67f000030415fb4d67f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000
[walter@eM350 ~]$ ./random 
4e8a1715238644a840eb66d9ff7f00002e4e3df600000000bb03400000000000ffffffff00000000a8ec66d9ff7f0000a871a37ad97f00000020fc7ad97f00003031ff7ad97f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000
[walter@eM350 ~]$ ./random 
598c57563e8951e6f0173f0cff7f00002e4e3df600000000bb03400000000000ffffffff0000000058193f0cff7f0000a8e1cbda257f0000009024db257f000030a127db257f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000

在我看来,除了 128 字节的随机字符串之外,这些都是一样的,因为它们几乎是相同的。然后,排除 NSA 篡改 linux 内核随机数生成器的可能性,我只能猜测这与我机器中的可用熵有关,当我按顺序询问太多字节时,它会耗尽。我的问题是: 1)这个猜测正确吗? 2)假设1)是正确的,我怎么知道是否有足够的熵来生成真正的随机字节序列?

【问题讨论】:

  • 使用/dev/urandom。真正的随机性是稀缺的,不应该那样浪费。
  • @KerrekSB 定义“浪费”。如果我从/dev/urandom 阅读,熵数也会减少。不同之处在于,如果计数达到 0,urandom 不会停止。
  • @glglgl:不同之处在于urandom 使用真正的随机性来播种伪随机性。确实,如果有更多可用随机性,您会获得更好的随机性,但伪随机性至少与给定可用随机性一样好。
  • @KerrekSB 我知道这一点,但我的印象是使用urandom 也会消耗熵(从而干扰random)。但似乎他们使用了两个完全不同的熵池。

标签: c linux random


【解决方案1】:

从手册页阅读:

Upon successful completion, read(), readv(), and pread() return the number of bytes actually read and placed in the buffer. The system guarantees to read the number of bytes requested if the descriptor references a normal file that has that many bytes left before the end-of-file, but in no other case.

底线:检查来自 read 的返回值并查看您实际读取了多少字节 - 可能没有足够的熵来生成您请求的字节数。

int len = read(fd, buf, LEN);
printf("read() returned %d bytes: ", len);
if (len > 0)
{
    uc2hex(str, buf, len);
    printf("%s\n", str);
}

测试:

$ ./a.out 
read() returned 16 bytes: c3d5f6a8ee11ddc16f00a0dea4ef237a
$ ./a.out
read() returned 8 bytes: 24e23c57852a36bb
$ ./a.out 
read() returned 16 bytes: 4ead04d1eedb54ee99ab1b25a41e735b
$

【讨论】:

  • 当然...我被 OP 没有直接阻塞 看到通话这一事实吓坏了。我猜在通话之间发生了少量的自然随机性。好电话,绝对是 +1。
【解决方案2】:

正如其他人所建议的,您需要检查读取的字节数的返回值。

如果 /dev/random 没有足够的可用字节,它将返回更少。

但是,您仍然在以下调用中使用 预期 长度:

uc2hex(str,buf,LEN);
printf("%s\n",str);

所以,您正在转换和打印未初始化的内存。我对后续调用显示相同的值并不感到惊讶 - 因为如果在调用之间没有写入该内存,则该值不会改变。

编辑:最好是:

int nBytes=read(fd,buf,LEN);
uc2hex(str,buf,nBytes);
printf("%s\n",str);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    • 1970-01-01
    • 2016-06-07
    • 1970-01-01
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多