
/dev/random 和 /dev/urandom 是 Linux 上的字元裝置檔案,它們是随機數生成器,為系統提供随機數
<h1 class="pgc-h-arrow-right" data-track="2">随機數的重要性</h1>
随機數在計算中很重要。 TCP/IP 序列号、密碼鹽和 DNS 源端口号都依賴于随機數。
在密碼學中,随機性無處不在,從密鑰的生成到加密系統,甚至密碼系統受到攻擊的方式。沒有随機性,所有加密操作都是可預測的,是以不安全。
<h1 class="pgc-h-arrow-right" data-track="5">随機數産生的原理</h1>
為了盡可能的做到随機,随機數生成器會收集系統環境中各種資料,比如:滑鼠的移動,鍵盤的輸入, 終端的連接配接以及斷開,音視訊的播放,系統中斷,記憶體 CPU 的使用等等
生成器把收集到的各種環境資料放入一個池子 ( 熵池 ) 中,然後将這些資料進行去偏、漂白,主要目的也是使得資料更加無序,更加難以猜測或者預料得到
有了大量的環境資料之後,每次擷取随機數時,從池子中讀取指定的位元組序列,這些位元組序列就是生成器生成的随機數
<h1 class="pgc-h-arrow-right" data-track="9">随機數生成器的結構</h1>
下圖是随機數生成器的結構
整個生成器的結構分成 收集器、主熵池、次熵池、urandom熵池、計數器 幾部分
收集器
收集器收集系統中的環境噪音,比如:滑鼠、鍵盤、中斷事件、記憶體、CPU等,收集之後進行批量去偏、漂白之後進入主熵池中
主熵池
主熵池接收收集器傳遞過來的環境資料,大小為 512位元組( 4098二進制位) , 它為 次熵池 和 urandom 熵池提供随機數
在 Linux上,可以通過下面的指令檢視目前系統主熵池大小, 機關是 二進制位的數量
次熵池
/dev/random 裝置關連的,大小為128位元組,它是阻塞的
urandom 熵池
和 /dev/urandom 裝置關連的,大小為128位元組,它是非阻塞的
計數器
主熵池 、次熵池 以及 urandom熵池各自都有一個計數器,用一個整數值來記錄,表示目前熵池中可用随機數的數量,這是一個預估的值,它是生成器根據熵池中的環境資料估算出來的
當熵池中有新的随機數加入時,對應熵池的計數器計數會增加,當熵池中随機數被取出時,熵池計數器計數減少
<h1 class="pgc-h-arrow-right" data-track="25">輸出接口</h1>
生成器主要有 /dev/random、/dev/urandom、get_random_bytes() 這三個接口
/dev/random、/dev/urandom
可以從使用者空間去通路這兩裝置檔案,即使是普通使用者也有通路權限,它們傳回指定請求數量的随機數
get_random_bytes()
隻供核心使用的接口, 傳回指定請求數量的随機數,暫時不讨論這個接口
<h1 class="pgc-h-arrow-right" data-track="31">請求随機數流程</h1>
現假如應用層分别調用 /dev/random、/dev/urandom 請求 N 個随機二進制位,它們的處理流程如下:
/dev/urandom
urandom 熵池計數器計數會減去 N ,如果結果大于等于0 ,直接從urandom熵池中取出 N 個随機二進制位并傳回,如果結果小于0,請求不會阻塞,隻不過傳回的是 N 個僞随機二進制位,這裡的僞随機二進制位是通過算法計算出來的,它的品質沒有 urandom 熵池中提取出的随機二進制位高
/dev/random
次熵池計數器減去 N, 如果結果大于等于0,直接從 次熵池中取出 N 個随機二進制位并傳回
如果結果小于 0, 先從主熵池提取剩餘所需的随機二進制位,主熵池計數器減去相應的值,同時傳回 N 個随機二進制位
如果這時主熵池和次熵池兩者計數器之和都不夠 N 的話, 則讀取随機二進制位的動作會被阻塞,直到次熵池中有足夠的随機二進制位
<h1 class="pgc-h-arrow-right" data-track="39">/dev/random、/dev/urandom 的差別</h1>
/dev/urandom 它傳回指定請求數量的随機數,如果請求的數量非常龐大的話,傳回的随機數可能是僞随機數,随機數品質稍差些,即使如此,它們對大多數應用來說已經足夠了
/dev/random 也是傳回指定請求數量的随機數,但是它産生的随機數品質很高, 是屬于真随機數, 主要用于需要高品質的随機數的地方,比如:生成加密密鑰等。
為了保證随機數的品質,/dev/random 隻能傳回熵池目前最大可用的随機二進制位,當請求超過這個值,就會阻塞,直到熵池中有足夠的随機二進制位
<h1 class="pgc-h-arrow-right" data-track="43">僞随機 和 真随機</h1>
上面提到了 僞随機 和 真随機,這裡的 "真" 和 "僞" 是相對的
僞随機數 是通過算法計算出來,它隻具有計算随機性
真随機數來自于系統中各種環境噪音資料,再利用算法混淆,可以認為是完全随機的了,具有真實的随機性和計算随機性
但是,對于一些微型的Linux系統,它的環境噪音很少,而且噪音種類也比較固定,能被猜測到的機率會大大增加,那麼它真實的随機性就大打折扣了,這時它産生的随機數的随機性 和 僞随機數已經差不多了
<h1 class="pgc-h-arrow-right" data-track="48">使用哪個随機數生成器</h1>
/dev/random 和 /dev/urandom 都是 Linux 上兩個随機數生成器,那我們應用中使用哪一個呢,按照怎樣的原則去選呢 ?
首先要明确一點,/dev/random 和 /dev/urandom 産生的随機數都是從同一個熵池 ( 主熵池 ) 中提取的,隻有當各自的熵池耗盡了,它們的行為才有所不同: /dev/random 阻塞,而 /dev/urandom 沒有,但是此時它傳回的是用算法計算出來的僞随機數
一般有個規則,/dev/random 産生的随機數品質高,主要用于一些安全方面,而且,它是阻塞的,對于大部分應用來說,這是不能接受的
對于 /dev/urandom ,當熵池計數器足夠的時候,産生真随機數,計數不夠的時候,産生僞随機數,最重要的是 它不會阻塞,而且,對于絕大多數的應用來說,僞随機數也能很好的滿足需求了
<h1 class="pgc-h-arrow-right" data-track="53">小結</h1>
本文主要介紹了 Linux 下 /dev/random 和 /dev/urandom 兩種随機數生成器的原理以及差別,關于它們更細節的知識請自行查閱 man 文檔 或 參考下面的連結
https://eprint.iacr.org/2006/086.pdf
https://hal.inria.fr/hal-00738638/document