1冈涧、概念
有兩個最主要的方法來生成隨機數(shù):
a) 通過測量某些隨機的物理現(xiàn)象茂附,然后補償測量過程中可能出現(xiàn)的偏差。比如大氣噪聲督弓、熱噪聲和其他外部電磁以及量子現(xiàn)象逻锐。從自然資源中獲取熵的速度取決于被測量的潛在物理現(xiàn)象伸辟,因此它們的速率是有限的哟楷,往往比較慢爱沟。
b) 使用計算算法,可以產(chǎn)生明顯隨機結果的長序列奸攻,實際上由較短的初始值(稱為種子)確定蒜危。結果是,如果種子的值是已知的睹耐,整個看似隨機的序列可以被重復產(chǎn)生辐赞。這類隨機數(shù)生成器被稱為偽隨機數(shù)生成器。這類生成器類型是非阻塞的硝训,可以大量產(chǎn)生數(shù)據(jù)响委。
2新思、不同的隨機數(shù)生成方法
-
類Linux系統(tǒng)下的 /dev/random
/dev/random 可以用作隨機數(shù)生成器或者偽隨機數(shù)生成器,取決于不同的實現(xiàn)赘风。
在linux下夹囚,隨機數(shù)生成器有一個容納噪聲數(shù)據(jù)的熵池,在讀取時邀窃,/dev/random設備會返回小于熵池噪聲總數(shù)的隨機字節(jié)荸哟。/dev/random可生成高隨機性的公鑰或一次性密碼本。若熵池空了瞬捕,對/dev/random的讀操作將會被阻塞鞍历,直到收集到了足夠的環(huán)境噪聲為止。這樣的設計使得/dev/random是真正的隨機數(shù)發(fā)生器肪虎,提供了最大可能的隨機數(shù)據(jù)熵劣砍,建議在需要生成高強度的密鑰時使用。
/dev/urandom(“unblocked”扇救,非阻塞的隨機數(shù)發(fā)生器)刑枝,它會重復使用熵池中的數(shù)據(jù)以產(chǎn)生偽隨機數(shù)據(jù)。這表示對/dev/urandom的讀取操作不會產(chǎn)生阻塞爵政,但其輸出的熵可能小于/dev/random的。它可以作為生成較低強度密碼的偽隨機數(shù)生成器陶缺,不建議用于生成高強度長期密碼钾挟。
FreeBSD操作系統(tǒng)實現(xiàn)了256位的Yarrow算法變體,以提供偽隨機數(shù)流饱岸。與Linux的/dev/random不同掺出,F(xiàn)reeBSD的/dev/random不會產(chǎn)生阻塞,與Linux的/dev/urandom相似苫费,提供了密碼學安全的偽隨機數(shù)發(fā)生器汤锨,而不是基于熵池。而FreeBSD的/dev/urandom則只是簡單的鏈接到了/dev/random百框。
void GetDevURandom(unsigned char *ent32)
{
int f = open("/dev/urandom", O_RDONLY);
if (f == -1) {
RandFailure();
}
int have = 0;
do {
ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
close(f);
RandFailure();
}
have += n;
} while (have < NUM_OS_RANDOM_BYTES);
close(f);
}
-
類Linux系統(tǒng)其他獲取隨機數(shù)方法
Linux下的SYS_getrandom
int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0);
- OpenBSD下的getentropy
getentropy(ent32, NUM_OS_RANDOM_BYTES)
- FreeBSD下的sysctl
static const int name[2] = {CTL_KERN, KERN_ARND};
int have = 0;
do {
size_t len = NUM_OS_RANDOM_BYTES - have;
if (sysctl(name, ARRAYLEN(name), ent32 + have, &len, nullptr, 0) != 0) {
RandFailure();
}
have += len;
} while (have < NUM_OS_RANDOM_BYTES);
-
OpenSSL的隨機數(shù)生成
OpenSSL的提供了RAND_bytes方法生成隨機數(shù)闲礼。在使用之前需要使用RAND_add向PRNG中添加種子及熵值。種子可以通過TSC生成铐维。
void RandAddSeed()
{
// Seed with CPU performance counter
int64_t nCounter = GetPerformanceCounter();
RAND_add(&nCounter, sizeof(nCounter), 1.5);
memory_cleanse((void*)&nCounter, sizeof(nCounter));
}
void GetRandBytes(unsigned char* buf, int num)
{
if (RAND_bytes(buf, num) != 1) {
RandFailure();
}
}
-
Windows平臺
CryptoAPI提供了CryptGenRandom方法產(chǎn)生隨機數(shù)柬泽。CryptGenRandom已經(jīng)被廢棄,應該使用新版CNG API:BCryptGenRandom
HCRYPTPROV hProvider;
int ret = CryptAcquireContextW(&hProvider, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
if (!ret) {
RandFailure();
}
ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32);
if (!ret) {
RandFailure();
}
CryptReleaseContext(hProvider, 0);
-
硬件方法:
CPU指令rdrand從芯片的硬件隨機數(shù)生成器中獲取隨機數(shù)
uint32_t eax, ebx, ecx, edx;
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) {
}
32位:
uint32_t r1, r2;
__asm__ volatile (".byte 0x0f, 0xc7, 0xf0;" // rdrand %eax
".byte 0x0f, 0xc7, 0xf2;" // rdrand %edx
"setc %2" :
"=a"(r1), "=d"(r2), "=q"(ok) :: "cc");
if (!ok) return false;
WriteLE32(ent32 + 8 * iter, r1);
WriteLE32(ent32 + 8 * iter + 4, r2);
}
64位:
uint64_t r1, r2, r3, r4;
__asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0, " // rdrand %rax
"0x48, 0x0f, 0xc7, 0xf3, " // rdrand %rbx
"0x48, 0x0f, 0xc7, 0xf1, " // rdrand %rcx
"0x48, 0x0f, 0xc7, 0xf2; " // rdrand %rdx
"setc %4" :
"=a"(r1), "=b"(r2), "=c"(r3), "=d"(r4), "=q"(ok) :: "cc");
if (!ok) return false;
WriteLE64(ent32, r1);
WriteLE64(ent32 + 8, r2);
WriteLE64(ent32 + 16, r3);
WriteLE64(ent32 + 24, r4);
3嫁蛇、BTC生成隨機數(shù)的方法
BTC采用了多種方式混合的形式锨并,將OpenSSL隨機數(shù)生成、OS隨機數(shù)生成睬棚、硬件隨機數(shù)生成再混淆隨機數(shù)發(fā)生器的狀態(tài)來生成強隨機數(shù)第煮。
void GetStrongRandBytes(unsigned char* out, int num)
{
assert(num <= 32);
CSHA512 hasher;
unsigned char buf[64];
// First source: OpenSSL's RNG
RandAddSeedPerfmon();
GetRandBytes(buf, 32);
hasher.Write(buf, 32);
// Second source: OS RNG
GetOSRand(buf);
hasher.Write(buf, 32);
// Third source: HW RNG, if available.
if (GetHWRand(buf)) {
hasher.Write(buf, 32);
}
// Combine with and update state
{
std::unique_lock<std::mutex> lock(cs_rng_state);
hasher.Write(rng_state, sizeof(rng_state));
hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter));
++rng_counter;
hasher.Finalize(buf);
memcpy(rng_state, buf + 32, 32);
}
// Produce output
memcpy(out, buf, num);
memory_cleanse(buf, 64);
}
參考文檔:
https://en.wikipedia.org/wiki/Random_number_generation#%22True%22_vs._pseudo-random_numbers
https://zh.wikipedia.org/wiki//dev/random
https://www.openssl.org/docs/man1.0.2/crypto/RAND_seed.html
https://zh.wikipedia.org/zh-hans/RdRand
版權歸本人所有,如需轉載,請注明出處