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

时间:2010-04-03 19:19:44

标签: c linux random

我想在C中使用/dev/random/dev/urandom。我该怎么办?我不知道如何在C中处理它们,如果有人知道请告诉我如何。谢谢。

5 个答案:

答案 0 :(得分:97)

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

在最近的Linux发行版中,getrandom系统调用可以用来获取加密安全随机数,如果 GRND_RANDOM 不<<>,它就不能失败 / em>指定为标志,读取量最多为256个字节。

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

char myRandomData[50];
arc4random_buf(myRandomData, sizeof myRandomData); // done!

否则,您可以将随机设备用作文件。你从他们读取,你得到随机数据。我在这里使用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
    }
}

在关闭文件描述符之前,您可能会读取更多随机字节。除非系统调用被信号中断,否则/ 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);
}

答案 1 :(得分:21)

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

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

答案 2 :(得分:16)

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

答案 3 :(得分:8)

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

以上的典型实现:

typedef struct prandom {
     struct prandom *prev;
     int64_t number;
     struct prandom *next;
} prandom_t;

这或多或少像刚刚前进的磁带,可以根据需要由另一个线程神奇地补充。有lot services refills via entropy提供大量文件转储,只有随机数生成的更强大的生成器,如:

  • 放射性衰变
  • 光学行为(光子撞击半透明镜子)
  • 大气噪音(不如上述强度)
  • 在键盘上打字并移动老鼠(开玩笑)的醉酒猴子的农场

不要使用“预先打包”的熵加密种子 ,以防不言而喻。这些集合适用于模拟,根本不适合生成密钥等。

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

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

答案 4 :(得分:4)

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

如果在第一次读取随机设备之前执行此操作,则可以确定您已获得随机设备。所以@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);

疯狂编码博客covered this, and other pitfalls不久以前;我强烈建议您阅读整篇文章。我必须赞扬他们解决这个问题的方法。

编辑添加(2014-07-25)...
顺便提一下,我昨晚读到,作为LibReSSL effort的一部分,Linux似乎正在获得GetRandom()系统调用。截至撰写本文时,还没有任何关于它何时可用于内核通用版本的消息。然而,这将是获得加密安全随机数据的首选接口,因为它消除了通过文件提供访问的所有陷阱。另请参阅LibReSSL possible implementation