如何在C中使用/ dev/random或urandom?

sto*_*nce 72 c linux random

我想使用/dev/random/dev/urandom在C.我怎么能这样做?我不知道如何在C中处理它们,如果有人知道请告诉我如何.谢谢.

zne*_*eak 98

一般来说,最好避免打开文件来获取随机数据,因为程序中存在多少个故障点.

在最近的Linux发行版,该getrandom系统调用可用来获取加密安全随机数,它不能失败,如果 GRND_RANDOM没有指定为标志和阅读量最多为256个字节.

截至2017年10月,OpenBSD,Darwin和Linux(with -lbsd)现在都有一个arc4random加密安全的实现,并且不会失败.这使它成为非常有吸引力的选择:

char myRandomData[50];
arc4random_buf(myRandomData, sizeof myRandomData); // done!
Run Code Online (Sandbox Code Playgroud)

否则,您可以将随机设备用作文件.你从他们读取,你得到随机数据.我在open/ read这里使用,但fopen/ fread也可以.

int randomData = open("/dev/urandom", O_RDONLY);
if (randomData < 0)
{
    // something went wrong
}
else
{
    char myRandomData[50];
    ssize_t result = read(randomData, myRandomData, sizeof myRandomData);
    if (result < 0)
    {
        // something went wrong
    }
}
Run Code Online (Sandbox Code Playgroud)

在关闭文件描述符之前,您可能会读取更多随机字节.除非系统调用被信号中断,否则/ dev/urandom永远不会阻塞并始终填写您请求的字节数.它被认为是加密安全的,应该是你的随机设备.

/ dev/random更挑剔.在大多数平台上,它可以返回比您要求的更少的字节,如果没有足够的字节可用,它可以阻止.这使错误处理故事更加复杂:

int randomData = open("/dev/random", O_RDONLY);
if (randomData < 0)
{
    // something went wrong
}
else
{
    char myRandomData[50];
    size_t randomDataLen = 0;
    while (randomDataLen < sizeof myRandomData)
    {
        ssize_t result = read(randomData, myRandomData + randomDataLen, (sizeof myRandomData) - randomDataLen);
        if (result < 0)
        {
            // something went wrong
        }
        randomDataLen += result;
    }
    close(randomData);
}
Run Code Online (Sandbox Code Playgroud)

  • @karim:请永远不要读取/ dev/random中的所有字节.只是不要.您的程序可能不是系统中需要随机字节的唯一*用户. (11认同)
  • 或者只是阅读更多内容以填充整数数组. (3认同)
  • @morrog Overeager评论员拒绝了它,所以我手动完成了更改.对不起,你没有得到它的记入. (2认同)
  • @zneak强调*长寿*因为对于那些不会因为额外的偏执而受到伤害的人.对于正常的加密使用`/ dev/urandom`很好. (2认同)

Dus*_*and 21

上面还有其他准确的答案.不过,我需要使用一个FILE*流.这就是我做的......

int byte_count = 64;
char data[64];
FILE *fp;
fp = fopen("/dev/urandom", "r");
fread(&data, 1, byte_count, fp);
fclose(fp);
Run Code Online (Sandbox Code Playgroud)

  • 在两种情况下都不应该在C代码中使用强制转换,fread()需要一个void*,所以只需要fread(&myInt,...); (4认同)

Tro*_*nic 16

只需打开文件进行读取,然后读取数据即可.在C++ 11中,您可能希望使用std::random_device它提供对此类设备的跨平台访问.

  • 看起来像[`std :: random_device`](http://en.cppreference.com/w/cpp/numeric/random/random_device)_did_最后进入C++ 11. (2认同)

Tim*_*ost 8

Zneak是100%正确的.读取一个稍微大于启动时所需的随机数缓冲区也很常见.然后,您可以在内存中填充数组,或将它们写入您自己的文件以供以后重复使用.

以上的典型实现:

typedef struct prandom {
     struct prandom *prev;
     int64_t number;
     struct prandom *next;
} prandom_t;
Run Code Online (Sandbox Code Playgroud)

这或多或少像一个刚刚前进的磁带,可以根据需要由另一个线程神奇地补充.这里有很多服务提供的只是那些有更强的发电机,如产生的随机数大文件的转储:

  • 放射性衰变
  • 光学行为(光子撞击半透明镜子)
  • 大气噪音(不如上面那么强)
  • 在键盘和移动鼠标上打字的醉酒猴子(开玩笑)

如果不言而喻,请不要使用"预打包"熵来加密种子.这些集合适用于模拟,而不是生成密钥等.

不关心质量,如果你需要大量数字来进行蒙特卡罗模拟,那么以不会导致read()阻塞的方式提供它们会好得多.

但是,请记住,数字的随机性与生成它的复杂性一样具有确定性./dev/random并且/dev/urandom方便,但不如使用HRNG(或从HRNG下载大型转储)那么强大.另外值得注意的是,/dev/random 通过熵补充,因此它可以根据情况阻止相当长的一段时间.

  • 下载"除了随机数之外的大型文件转储"对于加密目的来说是一个糟糕的建议.它要求其他人为您的功能提供种子,这些服务似乎通过互联网传输未加密的数据.请不要这样做. (2认同)

Chr*_*s J 5

zneak的答案很简单,但是实际情况要复杂得多。例如,您首先需要考虑/ dev / {u} random是否真的是随机数设备。如果您的计算机受到感染,并且设备被替换为/ dev / zero或稀疏文件的符号链接,则可能会发生这种情况。如果发生这种情况,则随机流现在是完全可预测的。

最简单的方法(至少在Linux和FreeBSD上)是在设备上执行ioctl调用,仅当设备是随机生成器时才会成功:

int data;
int result = ioctl(fd, RNDGETENTCNT, &data); 
// Upon success data now contains amount of entropy available in bits
Run Code Online (Sandbox Code Playgroud)

如果这是在第一次读取随机设备之前执行的,那么可以肯定地说您已经拥有了随机设备。因此,@ zneak的答案最好扩展为:

int randomData = open("/dev/random", O_RDONLY);
int entropy;
int result = ioctl(randomData, RNDGETENTCNT, &entropy);

if (!result) {
   // Error - /dev/random isn't actually a random device
   return;
}

if (entropy < sizeof(int) * 8) {
    // Error - there's not enough bits of entropy in the random device to fill the buffer
    return;
}

int myRandomInteger;
size_t randomDataLen = 0;
while (randomDataLen < sizeof myRandomInteger)
{
    ssize_t result = read(randomData, ((char*)&myRandomInteger) + randomDataLen, (sizeof myRandomInteger) - randomDataLen);
    if (result < 0)
    {
        // error, unable to read /dev/random 
    }
    randomDataLen += result;
}
close(randomData);
Run Code Online (Sandbox Code Playgroud)

Insane Coding博客介绍了此问题以及不久前的其他陷阱;我强烈建议您阅读整篇文章。我必须归功于他们从中寻求解决方案的地方。

编辑添加(2014-07-25)... 巧合的
是,我昨晚读到,作为LibReSSL工作的一部分,Linux似乎正在获取GetRandom()系统调用。截至撰写本文时,尚无何时在内核通用发行版中提供它。但是,这将是获取加密安全随机数据的首选接口,因为它消除了通过文件访问提供的所有陷阱。另请参见LibReSSL 可能的实现

  • 具有足够能力将/ dev / random或/ dev / urandom替换为其他东西的攻击者通常也具有足够的能力来加载内核模块,从而破坏您确定是否为随机设备的所有尝试。 (2认同)