L016使用/dev/random生成隨機數(shù)

很多庫例程產(chǎn)生的“隨機”數(shù)是準備用于仿真鳖轰、游戲等等庄拇;它們在被用于密鑰生成一類的安全函數(shù)時是不夠隨機的敲长。其問題在于這些庫例程使用的算法的未來值可以被攻擊者輕易地推導(dǎo)出來(雖然看起來它們可能是隨機的)技俐。對于安全函數(shù)鸣驱,需要的隨機值應(yīng)該是基于量子效應(yīng)之類的確實無法預(yù)測的值昼牛。Linux內(nèi)核(1.3.30以上)包括了一個隨機數(shù)發(fā)生器/dev/random术瓮,對于很多安全目的是足夠的。

/dev/random 是如何創(chuàng)建隨機數(shù)的呢贰健?

Linux 操作系統(tǒng)提供本質(zhì)上隨機(或者至少具有強烈隨機性的部件)的庫數(shù)據(jù)胞四。這些數(shù)據(jù)通常來自于設(shè)備驅(qū)動程序。例如伶椿,鍵盤驅(qū)動程序收集兩個按鍵之間時間的信息辜伟,然后將這個環(huán)境噪聲填入隨機數(shù)發(fā)生器庫。

隨機數(shù)據(jù)存儲在 熵池中悬垃,它在每次有新數(shù)據(jù)進入時進行“攪拌”游昼。這種攪拌實際上是一種數(shù)學轉(zhuǎn)換,幫助提高隨機性尝蠕。當數(shù)據(jù)添加到熵池中后烘豌,系統(tǒng)估計獲得了多少真正隨機位。

測定隨機性的總量是很重要的看彼。問題是某些量往往比起先考慮時看上去的隨機性小廊佩。例如囚聚,添加表示自從上次按鍵盤以來秒數(shù)的 32 位數(shù)實際上并沒有提供新的 32 位隨機信息,因為大多數(shù)按鍵都是很接近的标锄。

從 /dev/random 中讀取字節(jié)后顽铸,熵池就使用 MD5 算法進行密碼散列,該散列中的各個字節(jié)被轉(zhuǎn)換成數(shù)字料皇,然后返回谓松。

如果在熵池中沒有可用的隨機性位, /dev/random 在池中有足夠的隨機性之前等待践剂,不返回結(jié)果鬼譬。這意味著如果使用 /dev/random 來產(chǎn)生許多隨機數(shù),就會發(fā)現(xiàn)它太慢了逊脯,不夠?qū)嵱糜胖省N覀兘?jīng)常看到 /dev/random 生成幾十字節(jié)的數(shù)據(jù)军洼,然后在許多秒內(nèi)都不產(chǎn)生結(jié)果巩螃。

幸運的是有熵池的另一個接口可以繞過這個限制:/dev/urandom。即使熵池中沒有隨機性可用匕争,這個替代設(shè)備也總是返回隨機數(shù)避乏。如果您取出許多數(shù)而不給熵池足夠的時間重新充滿,就再也不能獲得各種來源的合用熵的好處了汗捡;但您仍可以從熵池的 MD5 散列中獲得非常好的隨機數(shù)淑际!這種方式的問題是,如果有任何人破解了 MD5 算法扇住,并通過查看輸出了解到有關(guān)散列輸入的信息,那么您的數(shù)就會立刻變得完全可預(yù)料盗胀。大多數(shù)專家都認為這種分析從計算角度來講是不可行的艘蹋。然而,仍然認為 /dev/urandom 比 /dev/random 要“不安全一些”(并通常值得懷疑)票灰。

應(yīng)用中出現(xiàn)的問題:

在我們的服務(wù)器程序中女阀,用戶登陸的時候會讀取/dev/random產(chǎn)生隨機數(shù),問題來了屑迂,當用戶登陸比較密集浸策,這時候read就會返回特別慢,并且返回的字節(jié)數(shù)也比要求的少惹盼,甚至不返回――阻塞庸汗。我們把用戶登陸處理函數(shù)放在了線程池里,導(dǎo)致的問題就是線程池里所有線程都可能會阻塞手报,這就造成了拒絕服務(wù)攻擊蚯舱。導(dǎo)致其他用戶登陸失敗改化。

CODE:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <sys/file.h>
 6 #include <sys/time.h>
 7 #include <errno.h>
 8 #include <unistd.h>
 9 #include <stdlib.h>
 10

 11 static int get_random_fd (void)
 12 {
 13     static int fd = -2;
 14
 15     if (fd == -2)
 16     {
 17         fd = open ("/dev/random", O_RDONLY | O_NONBLOCK);
 18         if (fd == -1)
 19         fd = open ("/dev/urandom", O_RDONLY | O_NONBLOCK);
 20     }
 21
 22     return fd;
 23 }
 24
 25 /*
 26 * Generate a series of random bytes. Use /dev/random if possible,
 27 * and if not, use /dev/urandom.
 28 */
 29 void get_random_bytes(void* buf, int nbytes)
 30 {
 31 int i, fd = get_random_fd();
 32 int lose_counter = 0;
 33 char cp = (char)buf;
 34 struct timeval tv;
 35 static unsigned seed = 0;
 36
 37 if (fd >= 0)
 38 {
 39 while (nbytes > 0)
 40 {
 41 i = read (fd, cp, nbytes);
 42 if ((i < 0) &&
 43 ((errno == EINTR) || (errno == EAGAIN)))
 44 continue;
 45
 46 if (i <= 0)
 47 {
 48 if (lose_counter++ == 8)
 49 break;
 50
 51 continue;
 52 }
 53 nbytes -= i;
 54 cp += i;
 55 lose_counter = 0;
 56 }
 57 }
 58
 59 for (i = 0; i < nbytes; i++)
 60 {
 61 if (seed == 0)
 62 {
 63 gettimeofday(&tv, 0);
 64 seed = (getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec;
 65 }
 66 *cp++ = rand_r(&seed) & 0xFF;
 67 }
 68
 69 return;
 70 }

解決方案:

1--3行:  定義fd為靜態(tài)變量,這樣只打開一次設(shè)備枉昏。
  17 – 19行: 無阻塞模式打開/dev/random設(shè)備陈肛。如果該設(shè)備打開失敗嘗試打開/dev/urandom。
 ⌒至选29行:  void get_random_bytes(void* buf, int nbytes)函數(shù)是提供給用戶的接口句旱,用戶調(diào)用這個函數(shù)就可以得到隨機數(shù)。
 ∥薄37-57行: read有可能返回的字節(jié)數(shù)小于請求的字節(jié)數(shù)谈撒。這時候就循環(huán)讀直到讀夠了所請求的大小。這樣最多重復(fù)8次畅涂。然后返回港华。
  59-67行: 如果上面重復(fù)8次都沒有讀夠所請求的字節(jié)數(shù)午衰,則我們自己生成隨機數(shù)來填充立宜。
  注意:打開的fd我們并沒有關(guān)閉,請您根據(jù)自己需求在合適的地方關(guān)閉臊岸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末橙数,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子帅戒,更是在濱河造成了極大的恐慌灯帮,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逻住,死亡現(xiàn)場離奇詭異钟哥,居然都是意外死亡,警方通過查閱死者的電腦和手機瞎访,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門腻贰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扒秸,你說我怎么就攤上這事播演。” “怎么了伴奥?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵写烤,是天一觀的道長。 經(jīng)常有香客問我拾徙,道長洲炊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮选浑,結(jié)果婚禮上蓝厌,老公的妹妹穿的比我還像新娘。我一直安慰自己古徒,他們只是感情好拓提,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著隧膘,像睡著了一般代态。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疹吃,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天蹦疑,我揣著相機與錄音,去河邊找鬼萨驶。 笑死歉摧,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的腔呜。 我是一名探鬼主播叁温,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼核畴!你這毒婦竟也來了膝但?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谤草,失蹤者是張志新(化名)和其女友劉穎跟束,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丑孩,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡冀宴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了温学。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片花鹅。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖枫浙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情古拴,我是刑警寧澤箩帚,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站黄痪,受9級特大地震影響紧帕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一是嗜、第九天 我趴在偏房一處隱蔽的房頂上張望愈案。 院中可真熱鬧,春花似錦鹅搪、人聲如沸站绪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恢准。三九已至,卻和暖如春甫题,著一層夾襖步出監(jiān)牢的瞬間馁筐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工坠非, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留敏沉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓炎码,卻偏偏與公主長得像盟迟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子辅肾,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容