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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2572366/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:54:55  来源:igfitidea点击:

How to use /dev/random or urandom in C?

clinuxrandom

提问by stojance

I want to use /dev/randomor /dev/urandomin C. How can I do it? I don't know how can I handle them in C, if someone knows please tell me how. Thank you.

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

采纳答案by zneak

In general, it's a better idea to avoid opening files to get random data, because of how many points of failure there are in the procedure.

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

On recent Linux distributions, the getrandomsystem call can be used to get crypto-secure random numbers, and it cannot fail ifGRND_RANDOMis notspecified as a flag and the read amount is at most 256 bytes.

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

As of October 2017, OpenBSD, Darwin and Linux (with -lbsd) now all have an implementation of arc4randomthat is crypto-secure and that cannot fail. That makes it a very attractive option:

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

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

Otherwise, you can use the random devices as if they were files. You read from them and you get random data. I'm using open/readhere, but fopen/freadwould work just as well.

否则,您可以像使用文件一样使用随机设备。您从它们中读取并获得随机数据。我在这里使用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
    }
}

You may read many more random bytes before closing the file descriptor. /dev/urandom never blocks and always fills in as many bytes as you've requested, unless the system call is interrupted by a signal. It is considered cryptographically secure and should be your go-to random device.

在关闭文件描述符之前,您可以读取更多的随机字节。/dev/urandom 永远不会阻塞,并且总是按照您的要求填充尽可能多的字节,除非系统调用被信号中断。它被认为是加密安全的,应该是您的首选随机设备。

/dev/random is more finicky. On most platforms, it can return fewer bytes than you've asked for and it can block if not enough bytes are available. This makes the error handling story more complex:

/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);
}

回答by Tronic

Just open the file for reading and then read data. In C++11 you may wish to use std::random_devicewhich provides cross-platform access to such devices.

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

回答by Tim Post

Zneakis 100% correct. Its also very common to read a buffer of random numbers that is slightly larger than what you'll need on startup. You can then populate an array in memory, or write them to your own file for later re-use.

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

A typical implementation of the above:

上述的典型实现:

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

This becomes more or less like a tape that just advances which can be magically replenished by another thread as needed. There are a lotof servicesthat provide large file dumps of nothing but random numbers that are generated with much stronger generators such as:

这或多或少就像一个磁带,它可以根据需要由另一个线程神奇地补充。这里有很多服务提供了与更强大的发电机,如产生什么,但随机数的大型文件的转储:

  • Radioactive decay
  • Optical behavior (photons hitting a semi transparent mirror)
  • Atmospheric noise (not as strong as the above)
  • Farms of intoxicated monkeys typing on keyboards and moving mice (kidding)
  • 放射性衰变
  • 光学行为(光子撞击半透明镜子)
  • 大气噪音(没有上面的那么强)
  • 陶醉的猴子在键盘上打字和移动老鼠的农场(开玩笑)

Don't use 'pre-packaged' entropy for cryptographic seeds, in case that doesn't go without saying. Those sets are fine for simulations, not fine at allfor generating keys and such.

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

Not being concerned with quality, if you need a lot of numbers for something like a monte carlo simulation, it's much better to have them available in a way that will not cause read() to block.

不关心质量,如果你需要很多数字来进行蒙特卡罗模拟,最好让它们以不会导致 read() 阻塞的方式可用。

However, remember, the randomness of a number is as deterministic as the complexity involved in generating it. /dev/randomand /dev/urandomare convenient, but not as strong as using a HRNG (or downloading a large dump from a HRNG). Also worth noting that /dev/randomrefills via entropy, so it can block for quite a while depending on circumstances.

但是,请记住,数字的随机性与生成它所涉及的复杂性一样具有确定性。/dev/random并且/dev/urandom很方便,但不如使用 HRNG(或从 HRNG 下载大型转储)强大。另外值得注意的是,/dev/random通过 entropy 重新填充,因此它可以根据情况阻塞很长一段时间。

回答by Dustin Kirkland

There are other accurate answers above. I needed to use a FILE*stream, though. Here's what I did...

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

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

回答by Chris J

zneak's answer covers it simply, however the reality is more complicated than that. For example, you need to consider whether /dev/{u}random really is the random number device in the first place. Such a scenario may occur if your machine has been compromised and the devices replaced with symlinks to /dev/zero or a sparse file. If this happens, the random stream is now completely predictable.

zneak 的回答只是简单地涵盖了它,但实际情况比这更复杂。例如,您首先需要考虑 /dev/{u}random 是否真的是随机数设备。如果您的机器受到威胁并且设备被替换为 /dev/zero 的符号链接或稀疏文件,则可能会发生这种情况。如果发生这种情况,随机流现在是完全可预测的。

The simplest way (at least on Linux and FreeBSD) is to perform an ioctl call on the device that will only succeed if the device is a random generator:

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

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

If this is performed before the first read of the random device, then there's a fair bet that you've got the random device. So @zneak's answer can better be extended to be:

如果这是在第一次读取随机设备之前执行的,那么可以肯定您已经获得了随机设备。所以@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);

The Insane Coding blog covered this, and other pitfallsnot so long ago; I strongly recommend reading the entire article. I have to give credit to their where this solution was pulled from.

Insane Coding 博客就不久前介绍了这一点以及其他陷阱;我强烈建议阅读整篇文章。我必须感谢他们从何处提取此解决方案。

Edited to add (2014-07-25)...
Co-incidentally, I read last night that as part of the LibReSSL effort, Linux appears to be getting a GetRandom()syscall. As at time of writing, there's no word of when it will be available in a kernel general release. However this would be the preferred interface to get cryptographically secure random data as it removes all pitfalls that access via files provides. See also the LibReSSL possible implementation.

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