许多用户空间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("%llun", *(uint64_t *)data);
}
我从dtruss
中得到以下内容(去掉了不相关的内容):
open("/dev/random ", 0x0, 0x7FFF900D76F5) = 3 0
read(0x3, "b2029a6 20+254356256 173171222376T300212 17213 02 34w3608203-214373244177K177Y371 33243Y 20 30*M3264265 27216r220 02361 06262326234336357F 35 36o306216227 ", 0x40) = 64 0
read(0x3, "223??32633243604314:+362c311274326a_Ga331261 22 23265Cna211]356) ", 0x20) = 32 0
实现实际上是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
include for CCRandomCopyBytes中的注释表示它是fork()安全的:
调用系统随机数生成器很不方便直接地在调用/dev/random的简单情况下,调用者除了管理设备外,还必须打开和关闭设备当它打开的时候。这个模块的直接存在理由做这件事带来的不便。它管理一个文件描述符/dev随机,包括发生的异常处理在fork()和exec()中。调用CCRandomCopyBytes()和所有精细的部分是为你管理的。不管你做什么他们真的很努力。[…]
在我自己的快速测试中,当调用SecRandomCopyBytes()时,孩子会被杀死