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

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

一般来说,避免打开文件来获取随机数据是一个好主意,因为程序中有多少个失败点。

在最近的Linux发行版中, getrandom系统调用可以用来获得加密安全的随机数,并且如果 GRND_RANDOM 没有被指定为标志并且读取量最多为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); } 

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

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

只要打开文件进行阅读,然后读取数据。 在C ++ 11中,你可能希望使用std::random_device ,它提供了跨平台访问这些设备。

Zneak是100%正确的。 读取随机数字的缓冲区也比较常见,这些随机数字比启动时需要的稍大。 然后你可以在内存中填充一个数组,或者把它们写到你自己的文件中,以备以后使用。

以上的典型实现:

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

这变得或多或少像一个磁带,只要进展,就可以根据需要用另一个线程神奇补充。 有很多 服务可以提供大量的文件转储,只不过是用更强大的生成器生成的随机数字,例如:

  • 放射性衰变
  • 光学行为(光子撞击半透明镜子)
  • 大气噪声(不如上述那么强)
  • 陶醉于键盘和移动鼠标(开玩笑)的猴子农场

不要使用“预包装”的熵来加密种子 ,以防万一。 这些集合对于模拟来说是很好的,对于生成密钥等来说也不是很好

不关心质量,如果你需要大量的数字用于蒙特卡洛仿真,最好让它们以不会导致read()阻塞的方式提供。

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

zneak的答案只是简单的介绍一下,然而现实比这更复杂。 例如,你首先需要考虑/ dev / {u}是否真的是随机数设备。 如果您的计算机已被入侵,并将设备替换为/ 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); 

疯狂的编码博客覆盖了这一点,以及不久前的其他陷阱 ; 我强烈建议阅读整篇文章。 我必须把这个解决方案从哪里拿出来。

编辑添加(2014-07-25)…
同样地,我昨天晚上看到,作为LibReSSL工作的一部分,Linux似乎正在得到一个GetRandom()系统调用。 截至撰写本文时为止,在内核通用版本中将不会提供何时可用。 但是,这将是首选的接口来获得密码安全的随机数据,因为它消除了通过文件访问提供的所有缺陷。 另请参阅LibReSSL 可能的实现 。