產生虛擬亂數 (pseudo-random number),不是真的亂數,也不是機密的,而是一系列看起來像亂數的數列,這些數字實際上是有固定順序的。
#include <stdlib.h> void srand(unsigned int seed); // 設定函式庫內部的 seed,一開始預設是 1。 int rand(void); // 依據 seed 運算產生範圍為 [0, RAND_MAX] 的虛擬亂數回傳,並儲存為新的 seed。 int rand_r(unsigned int *seedp); //
rand_r() 為 reentrant 版的 rand(),需要傳入儲存 seed 的記憶體指標,在 thread 程式得以不被其它 thread 干擾來產生同樣的數列。在 POSIX.1-2008 標注為廢棄。
POSIX.1-2001 rand() 和 srand() 的實作範例:
static unsigned long next = 1;
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned int seed) {
next = seed;
}
注意
- 虛擬亂數是有一定順序的,知道 seed 就知道下一個產生的值。假設初始 seed 設為目前的時間秒數,已知是今年的話,大約有 225 個可能的值,縮小範圍後依現今運算能力很容易試出來。
- 產生序列的最低 bit 固定 01010101..,其實不夠亂。
- 1995 發現 Netscape 瀏覽器產生的 SSL session keys 使用時間和 process ID 作為 seed,猜得到,所以 SSL sessions 可在幾分鐘內破壞。...
以上經驗告訴我們,作為 secure 的虛擬亂數產生器,有兩個基本原則:
- seed 必須是無法預測的 (實際上只能難以預測?)。要有足夠的可能性,例如 2128 就足夠 (隨著計算能力越來越強,暴力破解越容易,需要更多 bit),所有可能出現的機率相同,沒有東西讓攻擊者可以縮小範圍。
- 產生虛擬亂數的 algorithm 必須是 secure,pseudorandom bits 沒有可辨別的 patterns。即使攻擊者學到或猜到一些 pseudorandom bits,也無法預測其它 pseudorandom bits。
參考
- https://inst.eecs.berkeley.edu//~cs161/fa08/Notes/random.pdf
- drand48():較長的虛擬亂數產生器。
- 在 Linux C Library,rand() 使用和 random() 相同的亂數產生器。
- GNU C Pseudo-Random Numbers
- https://blog.gtwang.org/programming/c-cpp-rand-random-number-generation-tutorial-examples/
沒有留言:
張貼留言