時基線:基本設定

抖動式圖書館是由 Stephan Mueller 所編寫,可從以下位置取得: https://github.com/smuellerDD/jitterentropy-library,請參考以下連結: http://www.chronox.de/jent.html.在 Zircon 中,編碼器可當成簡單的熵 植入系統 CPRNG

本文件描述並分析 時基誤差:

  1. 是否使用變數,雜訊中的偽隨機數疊代 產生函式的方式
  2. 是否對使用抖動器內部人員的原始雜訊樣本進行後置處理 來處理處理常式

我考慮這些基本設定選項 這套程序我會將其與可微調的參數對比 (比如如果不選擇循環播放,就會計為一次循環播放次數) 虛擬記憶體空間,或是用戶端 O2 內部使用的暫存記憶體大小 時基誤差),因為可調整的參數並不會大幅影響 會收集熵收集到的數量與時間 這就需要耗費大量資源與成本

我得到的結論是在本文件的結尾處,但簡單來說,我覺得 因此應該避免選擇偽隨機疊代次數 抖動後處理的資料。

簡要說明抖動作用

如需作者的說明文件,請下載 HTML 表單,網址為: http://www.chronox.de/jent/doc/CPU-Jitter-NPTRNG.html 或 PDF 格式,網址為 http://www.chronox.de/jent/doc/CPU-Jitter-NPTRNG.pdf.簡單來說 會從 CPU 指示時間的變化中隨機收集位元。

Jitterentropy 會維護隨機狀態,格式為 64 位元數字 會受許多 jitterentropy 函數所影響。 輸出隨機性參數

雜訊來源有兩個,分別是執行速度相對緩慢的區塊 測量精確執行階段的程式碼 (使用系統時鐘,需要大約 奈秒解析度)。完成這些程式碼區塊的確切時間 不一定。我們測試這些時間,確保變數難以預測。「我們不能」 確保測試結果 (包括測試結果) ) 是鼓勵的。不過請注意,本文件的目的並非 正因如此 ,討論上述兩種設定選項。

第一個用做雜訊來源的程式碼區塊是耗用大量 CPU 的 LFSR 迴圈 jent_lfsr_time 函式。 LFSR 邏輯重複的次數是由 kernel.jitterentropy.ll cmdline (「ll」代表「LFSR 迴圈」)。如果是 ll = 0, 使用虛擬隨機計數,否則會使用 ll 的值。 查看原始碼時,外部迴圈會根據 ll 重複執行 參數。內部迴圈每 64 步就將 LFSR 推進了 64 步,每次以 XOR 插入時 最新時間樣本中的一個位元。透過 LFSR 則會做為處理步驟,通常會對 隨機時間步。如同 熵品質測試文件 在測試 CPU 作業時間的主體內容時,請略過這個處理程序 變化版本。而啟用處理方法也會導致 有時則有可疑的金額估計值 (請參閱 「處理原始樣本的影響」一節)。

第二個雜訊來源是記憶體存取迴圈 jent_memaccess 函式。 系統會根據 kernel.jitterentropy.ml 重複記憶體存取迴圈 cmdline (「ml」代表「記憶體迴圈」,值為 0 時則會啟用 偽隨機迴圈計數,任何非零值都會覆寫偽隨機值 數量。每次實際記憶體存取迴圈疊代時,都會讀取和寫入 記憶體區塊相當大,分為 kernel.jitterentropy.bc 個多組 每個大小為 kernel.jitterentropy.bs 個位元組的區塊。 已撰寫目前的文件為 bc = 1024bs = 64。最新的預設值 應記錄在 cmdline 文件。為了進行比較, 時基誤差原始碼為 bc = 64bs = 32 請參閱這裡的定義。 根據 jent_memaccess 函式上方的註解,記憶體總大小 應大於目標機器的 L1 快取大小。令人困惑 bc = 64bs = 32 會產生 2, 048 位元組的記憶體, 小於甚至大部分的 L1 快取 (我找不到任何大於 0 位元組的 CPU 但小於 4 KB 的 L1)。使用 bs = 64bc = 1024 會產生 64 KB 這通常足以溢位 L1 資料快取

選項 1:Pseudorandom 迴圈計數

抖動法最初的設計是為了讓兩個雜訊產生函式 執行偽隨機次數具體而言 jent_loop_shuffle 函式 結合 (1) 從高解析度時鐘讀取時間以及 (2) 用於決定執行次數 雜訊來源

我們新增了覆寫這些偽隨機迴圈計數的功能 無論是否使用覆寫值,都會提升抖動性的效能。結果如下 「偽隨機循環機制的影響」專區, 總而言之:統計測試結果建議偽隨機循環 數量增加了遠超過預期。這讓我不信任 都會計入更高的熵數,因此建議使用較低的預估值 且偏好具有確定性迴圈計數,而非偽隨機。

Jitterentropy 的隨機資料處理

如上所述,抖動器可以處理其隨機資料 看起來會「隨機排序」的資料具體而言,處理程序會減少 (且 理想情況下移除) 隨機資料的偏差; 並減少 (最好,移除) 隨機位元組之間的任何關聯性。

產生處理樣本的主要功能是 jent_gen_entropy、 系統就會在迴圈中呼叫 jent_read_entropy 產生任意數量的隨機位元組 基本上,jent_gen_entropy 會呼叫迴圈中的雜訊函式 64 次。 每次叫用 jent_lfsr_time 的 64 次時,都會同時混入雜訊時間測量結果 放入抖動式隨機狀態

經過 64 次疊代後,隨機狀態會選擇性顯示「stirred」英吋 jent_stir_pool敬上 由 XOR-ing 搭配「mixer」值,本身取決於抖動式隨機 時間。如原始碼中所述,此作業不能增加或減少 泳池裡的熵 (因為 XOR 具有生物識別性) 但有可能可以 隨機狀態的統計外觀

原則上,叫用雜訊來源函式 64 次後,應會產生 64 次 乘以熵,上限為隨機狀態可容納的 64 位元上限。 這會假設 jent_lfsr_time 中的混合作業已經過加密 。我不是加密分析專家,但 LFSR 本身並不是 透過 64 個連續位元揭露完整狀態,因此加密保護 RNG 64 位元 LFSR,之後所有過去和未來的值都能輕易整合 。我不太確定時抖動機制,使用 XOR 的時刻就好 將所有結果整合到「底部」會隨著 LFSR 變更而轉移 安全。在沒有嚴謹的加密檢查的情況下 ( 我知道可能存在,但眼中並沒有提到 會盡量使用未處理的樣本,並混合使用 更新為系統熵集區 (如目前採用的 SHA-2)。

也就是說,我確實針對已處理的資料樣本執行 NIST 測試套件。我的 有 個結果位於 「處理原始樣本的影響」專區)) 。

測試程序

如要瞭解執行熵來源品質測試的程序,請參閱 熵品質測試文件

這些初步結果是在 Raspberry Pi 上的 Zircon 偵錯版本收集而來 3,從修訂版 18358de5e90a012cb1e042efae83f5ea264d1502 建立於現已過時的專案:https://fuchsia.googlesource.com/zircon/+/a1a80a6a7d 「[virtio][entropy] 基本 virtio-rng 驅動程式庫」。下列標記已在 我的 local.mk 檔案 (建構時):

ENABLE_ENTROPY_COLLECTOR_TEST=1
ENTROPY_COLLECTOR_TEST_MAXLEN=1048576

我使用 下列核心 cmdline,改變 $ML$LL$RAW 的值:

kernel.entropy-test.src=jitterentropy
kernel.jitterentropy.bs=64
kernel.jitterentropy.bc=1024
kernel.jitterentropy.ml=$ML
kernel.jitterentropy.ll=$LL
kernel.jitterentropy.raw=$RAW

測試結果和分析

偽隨機迴圈的影響

原始資料

依循抖動原始碼中的邏輯 (搜尋 MAX_FOLD_LOOP_BIT敬上 和 MAX_ACC_LOOP_BIT) 虛擬迴圈計數在以下範圍內各有不同:

ml: 1 .. 128 (inclusive)
ll: 1 .. 16 (inclusive)

在此附上 NIST 套件的整體最低熵預估值 和兩個產生預估值:壓縮預估值和 馬可夫估價。NIST 最小值為 10 個不同的 包括這兩個項目壓縮估算值通常是 會以決定性迴圈計數的抖動回饋原始樣本的最小量表示,而 馬可夫估計值通常最小為,與其他動物的抖動傳染性 儲存空間設定

ml ll 最小熵 (位元 / 位元組) 壓縮估算值 馬可夫估價
隨機 (1 .. 128) 隨機 (1 .. 16) 5.77 6.84 5.77
128 16 1.62 1.62 3.60
1 1 0.20 0.20 0.84

換句話說,改變迴圈計數時,會無意識地提高最低熵 原始樣本的 4.15 位元 (即 250%) 的預估結果,與確定性 一律使用偽隨機範圍中的最大值的版本。

分析

偽隨機循環計數值是由多一個額外時間決定 每個雜訊函式的範例首先,這些時間樣本與 雜訊函式時間測量,因為循環計數與間隔時間之間的落差 這些樣本與雜訊函式時間測量結果相對可預測。身為 所以很難以判斷 輸出資料的最小熵。其次,如果能想到 循環次數樣本與雜訊函式相同,約有 250% 時間測量,因為這兩者都仰賴相同的雜訊來源,但 第一個迴圈計數的時間樣本,可能會從 系統啟動系統所需的執行時間。

因此,我懷疑這起因是偽隨機迴圈計數 足以成為「笨蛋」也就是特定的統計測試套件 以預測器為基礎的 NIST 套件,但以 有關如何衍生出抖動偽迴圈計數的特定知識 甚至可以更準確地預測輸出內容我認為 偽隨機迴圈計數測試中的最小熵,對對 特別針對程式碼,在 測試,即每位元組約 0.20 到 1.62 位元。

憑藉偽隨機數的手法迫使我們做出其他決定: 保守地估計實際的熵內容,單位為每位元組 0.20 位元 偽隨機計數函式一律選擇 ml = 1ll = 1)?或是 挑選一般熵內容 (可能擁有較聰明的) 比計算 (1.62 + 0.20) / 2 = 0.91 位元 / 位元組 為本討論目的提供) 使用,並可能導致虛擬迴圈計數不足 偶爾會讓我們忽略平均熵內容如果是 過於保守,我們會花更多時間收集熵;如果 但太樂觀來看,可能出現了安全漏洞最後,這個 強制在安全性之間做出取捨 (偏好保守的熵) 估算) 和效率 (偏好以樂觀的熵估算)。

處理原始樣本的影響

原始資料

我重複了上述的三項測試,但測試者在內部使用抖動器的內部 套用設定 (使用 kernel.jitterentropy.raw = false,而不是 預設值為 true)。為了方便起見,下表包含 原始 最後的三列範例結果 (從上方複製),然後處理 結果 (新增) 會顯示在底部的三列。

ml ll 原始 最小熵 (位元 / 位元組) 壓縮估算值 馬可夫估價
隨機 (1 .. 128) 隨機 (1 .. 16) true 5.77 6.84 5.77
128 16 true 1.62 1.62 3.60
1 1 true 0.20 0.20 0.84
ml ll 原始 最小熵 (位元 / 位元組) 壓縮估算值 馬可夫估價
隨機 (1 .. 128) 隨機 (1 .. 16) false 5.79 美元 6.59 5.79 美元
128 16 false 5.78 6.97 美元 5.78
1 1 false 5.77 6.71 5.77

分析

後續處理的最低熵估計值幾乎等於 稍有變化,容易因隨機性而解釋 針對含虛擬迴圈計數的原始樣本進行最低熵估算。

回想一下,抖動器處理的熵由 64 個獨立隨機產生 資料樣本,混合在 64 位元內部狀態緩衝區中。每個原始 樣本與 raw = true 資料表中的一個範例相對應。尤其是 也就是說,結合 64 樣本與 ml = 1ll = 1 之後, 處理時會產生 (5.77 * 8) = 每 8 個位元組的 46.2 位元熵 處理的輸出內容,意即 (46.2 / 64) = 每秒 0.72 位元的熵 而不是測量到 0.20 位元的樣本值。

此引數適用於 ml = 1ll = 1raw = false 測量、 但「不適用於」ml = 128ll = 16raw = false我們要用 結合 64 個原始樣本與 ml = 128ll = 16 的原則 collection (1.64 * 64 / 8) = 13.1 位元的熵,每個處理的位元組除外 當然,每位元組 8 位元有硬性限制

有趣的是,最小的熵估算器會從壓縮資料中切換 馬可夫估算器的值理論上,額外「混淆」是 後續處理就足以達到「fool」壓縮率百分比如果有 抖動處理程式中的加密編譯漏洞 然後編寫類似的 估算器,以大幅縮小 極低熵。如果我們使用一般用途測試來決定原始樣本數量 收集到 256 次最低熵,但對手使用目標性 然後 (相對於此目標性攻擊),我們的系統擁有較少的熵 擁有超乎預期的熵池這是安全漏洞。

若是基特熵處理流程中有非常糟糕的弱點, 事實上,降低「真實性」都會有「抖動現象」內部集區。 ml = 1ll = 1 的算數引數顯示我們無法信任 以準確地測量 因此處理過程中 但我們的工具也無法偵測到損失。這會使得 安全漏洞。

結論

抖動實驗室的偽隨機循環計數是最大的好處 或是迫使我們犧牲安全/效益,除非我們能 顯示有說服力的證據指出偽隨機時間確實發生劇烈 提高熵預估值,而不僅是擊敗 NIST 測試套件, 採用確定性迴圈,最理想的方式是調整 或每個目標採購的費用。

據我所知,Jtterentropy 處理相關處理程序同樣問題 沒有經過足夠的加密編譯分析和測試 。此外,我們無法直接測量 透過 NIST 測試套件處理後的資料, 我們難以輕易偵測到的安全漏洞我認為我們應該改為 Zircon CPRNG 中的熵混合程式碼 (以 SHA-2 為基礎),然後退出 抖動器的處理功能已停用。

TODOs

  1. 針對不同的 Zircon 版本重複上述回報的測試。 確保熵估計值保持一致。
  2. 在不同平台和指定目標上重複測試 (注意:x86 目標不含 目前可以在早期啟動階段使用系統時鐘,所以在早期啟動階段 熵測試和早期啟動 CPRNG 種子目前不支援時抖動 x86)。
  3. 自動執行測試程序,並產生此頁面中的報表 文件。具體而言,這些測試應比較下列項目:

    • 偽隨機迴圈計數與各種確定性迴圈計數值
    • 原始樣本與已處理的資料