Linux核心隨機數產生器的設計與實現
EDN部落格精華文章 作者:bluehacker
這幾天抽了點時間看了看linux 2.6.10的程式碼,對裡面的那個核心隨機數產生器發生興趣,花了點工夫分析了下,貼在這裡灌水.
--------------------------------------------------------------------------------------------
隨機數在許多領域都有重要應用,如Monte Carlo模擬、密碼學和網路安全。隨機數的質量直接關係到網路安全系統的可靠性和安全性,關係到 Monte Carlo模擬結果的可信度。自從計算機誕生起,尋求用計算機產生高質量的隨機數序列的研究就一直是個長期受到關注的課題。Linux核心從 1.3.30版本開始實現了一個高強度的隨機數發生器,本文根據Linux 2.6.10核心的原始碼,詳細分析該隨機數產生器的設計與實現。
1. 基本原理
Linux核心採用熵來描述資料的隨機性。熵(entropy)是描述系統混亂無序程度的物理量,一個系統的熵越大則說明該系統的有序性越差,即不確定性越大。在資訊學中,熵被用來表徵一個符號或系統的不確定性,熵越大,表明系統所含有用資訊量越少,不確定度越大。
計算機本身是可預測的系統,因此,用計算機演算法不可能產生真正的隨機數。但是機器的環境中充滿了各種各樣的噪聲,如硬體裝置發生中斷的時間,使用者點選滑鼠的時間間隔等是完全隨機的,事先無法預測。Linux核心實現的隨機數產生器正是利用系統中的這些隨機噪聲來產生高質量隨機數序列。
核心維護了一個熵池用來收集來自裝置驅動程式和其它來源的環境噪音。理論上,熵池中的資料是完全隨機的,可以實現產生真隨機數序列。為跟蹤熵池中資料的隨機性,核心在將資料加入池的時候將估算資料的隨機性,這個過程稱作熵估算。熵估算值描述池中包含的隨機數位數,其值越大表示池中資料的隨機性越好。
2. 設計與實現
Linux 核心隨機數產生器在/drivers/char/random.c中作為字元裝置實現。在模組初始化函式rand_initialize()中呼叫 create_entropy_store()分別建立名為random_state的預設熵池,一個名為sec_random_state和一個名為 urandom_state的熵池。熵池用struct entropy_store來表示。
核心實現了一系列介面函式用於獲取系統環境的噪聲資料,並加入熵池,分別是:
void add_interrupt_randomness(int irq);
void add_keyboard_randomness(unsigned char scancode);
void add_mouse_randomness(__u32 mouse_data);
void add_disk_randomness(struct gendisk *disk);
其中add_interrupt_randomness()函式利用裝置兩次中斷的間隔時間作為噪聲源將隨機資料加入熵池。要使裝置的中斷作為系統噪聲,必須用SA_SAMPLE_RANDOM標誌註冊其中斷服務程式。這樣,每當裝置發生中斷時,中斷系統會自動呼叫 add_interrupt_randomness()將熵加入熵池。
Add_keyboard_randomness()將按鍵的掃描碼和兩次按鍵之間的時間間隔作為噪聲源;而add_mouse_randomness()則利用滑鼠位置和連續兩次滑鼠中斷時間間隔填充熵池;最後 add_disk_randomness()函式則以連續兩次磁碟操作之間的間隔產生隨機數。
上面的函式最終都是通過呼叫 add_timer_randomness()函式將熵加入熵池的。Add_timer_randomness()首先估算所加資料的熵,再呼叫 batch_entropy_store()函式將資料加入熵池。為了避免中斷的延遲過長影響系統性能,batch_entropy_store()並不直接將熵加入熵池,而是將其加入佇列中。當佇列長度達到一定長度後,由keventd核心執行緒通過呼叫batch_entropy_process()函式將佇列中的熵加入池中。
Batch_entropy_process()函式列舉佇列中的每個熵,對每個熵呼叫 add_entropy_words()函式將其加入熵池,但它並不更新熵池的熵估算值。為此,batch_entropy_process()對每個熵呼叫完add_entropy_words()後,立刻呼叫credit_entropy_store()函式更新熵估算值。