7

许多用户空间 CSPRNG 有一个问题,在 之后fork(2),两个不同的进程可能返回相同的随机字节流。

从 看dtruss,很明显,SecRandomCopyBytes至少是从 播种/dev/random,但这样做的方式是否可以安全使用fork()

使用以下源代码:

#include <Security/Security.h>


int main() {
    uint8_t data[8];
    SecRandomCopyBytes(kSecRandomDefault, 8, data);
    SecRandomCopyBytes(kSecRandomDefault, 8, data);
    printf("%llu\n", *(uint64_t *)data);
}

我从中得到以下信息dtruss(删除了不相关的东西):

open("/dev/random\0", 0x0, 0x7FFF900D76F5)       = 3 0
read(0x3, "\b\2029a6\020+\254\356\256\017\3171\222\376T\300\212\017\213\002\034w\3608\203-\214\373\244\177K\177Y\371\033\243Y\020\030*M\3264\265\027\216r\220\002\361\006\262\326\234\336\357F\035\036o\306\216\227\0", 0x40)        = 64 0
read(0x3, "\223??3\263\324\3604\314:+\362c\311\274\326\a_Ga\331\261\022\023\265C\na\211]\356)\0", 0x20)      = 32 0
4

1 回答 1

8

实现实际上是 CCRandomCopyBytes():

http://www.opensource.apple.com/source/Security/Security-55471/libsecurity_keychain/lib/SecRandom.c

int SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes) {
    if (rnd != kSecRandomDefault)
        return errSecParam;
    return CCRandomCopyBytes(kCCRandomDefault, bytes, count);
}

所以实际的代码在这里:

http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-60049/lib/CommonRandom.c

CCRandomCopyBytes 的 include 中的注释声明它是 fork() 安全的:

直接调用系统随机数生成器很不方便。在调用 /dev/random 的简单情况下,调用者除了在设备打开时对其进行管理外,还必须打开并关闭它。这个模块的直接存在理由是这样做的不便。它管理 /dev/random 的文件描述符,包括在 fork() 和 exec() 中发生的异常处理。调用 CCRandomCopyBytes() 并为您管理所有繁琐的位。继续做你真正想做的事情。[...]

在我自己的快速测试中,孩子在调用 SecRandomCopyBytes() 时被杀死

于 2014-02-12T18:47:55.323 回答