Jitterentropy:調整設定

jitterentropy 程式庫是由 Stephan Mueller 所編寫,可從 https://github.com/smuellerDD/jitterentropy-library 取得,您可以在 http://www.chronox.de/jent.html 找到。在 Zircon 中,這個 API 可做為簡單的熵來源,用於種子系統 CPRNG。

有關時基誤差的基本設定選項隨附文件說明瞭兩個選項,這些選項基本上會影響時基線的執行方式。本文件描述的是控制時基誤差速度和收集熵程度的數值參數,但又不會改變其作業原則。也會說明如何測試各種參數,以及在輸出內容中查看的內容 (例如為新裝置新增支援,或執行更完整的參數最佳化參數工作)。

時基誤差參數的彙整報導

下列可微調的參數控制了基特熵的執行速度,以及收集熵的速度:

kernel.jitterentropy.ll

ll」代表「LFSR 迴圈」。Jitterentropy 使用 LFSR (故意沒有效率的 a) LFSR 實作 CPU 進行雜訊產生作業。內部迴圈將 LFSR 移動 64 次;外部迴圈會重複 kernel.jitterentropy.ll 次。

在我的經驗中,LFSR 程式碼大幅降低了時基誤差,但並未產生非常大的熵,我用 RPi3 和 qemu-arm64 進行測試,結果與品質類似的結果類似,但我們尚未在 x86 上進行測試。調整時,請考慮使用較少的 LFSR 迴圈,通常有助於提高整體效能。

請注意,設定 kernel.jitterentropy.ll=0 會使抖動現象以「隨機」方式選擇 LFSR 循環的數量。如基本設定文件所述,我不建議使用 kernel.jitterentropy.ll=0

kernel.jitterentropy.ml

ml」代表「記憶體存取迴圈」。抖動線會逐步經過中等大的 RAM 區塊,並讀取及寫入每個位元組。區塊和存取模式的大小由下列兩個參數控制。記憶體存取迴圈會重複 kernel.jitterentropy.ml 次。

根據我的經驗,記憶體存取迴圈是原始熵的絕佳來源。我又一次只用 RPi3 和 qemu-arm64 進行測試

kernel.jitterentropy.ll 類似,如果您設定 kernel.jitterentropy.ml=0,則時基線段就會選擇記憶體存取迴圈計數的「隨機」值。我也不建議這樣做。

kernel.jitterentropy.bs

bs」代表「區塊大小」。抖動熵將 RAM 區塊分割成這個大小的區塊。記憶體存取迴圈的開頭為區塊 0 的位元組 0,接著是區塊 1 的「位元組 -1」(實際上是區塊 0 的最後一個位元組)、區塊 2 的「位元組 -2」 (即區塊 1 的第二個位元組),以此類推。這個模式可確保每個位元組都會命中,而大多數存取作業都會進入不同的區塊。

我通常根據快取行的大小,使用 kernel.jitterentropy.bs=64 測試了時基誤差。我還沒進行測試,看看部分/所有平台是否有更好的選擇。

kernel.jitterentropy.bc

bc」代表「封鎖次數」。Jitterentropy 會在記憶體存取迴圈中使用許多 RAM 區塊,每個大小為 kernel.jitterentropy.bs

由於我選擇了 kernel.jitterentropy.bs=64,因此我通常會選擇 kernel.jitterentropy.bc=1024。 這表示使用 64 KB 的 RAM,足以溢位 L1 快取。

jent_memaccess 之前的註解中的時基誤差原始碼會建議選擇區塊大小和計數,讓使用的 RAM 大於 L1。錯亂地,上游時基誤差 (區塊大小 = 32,區塊數量 = 64) 的預設值不夠大,無法溢位 L1。

調整程序

基本概念很簡單,針對特定目標裝置嘗試不同的參數值。為每個參數組合收集大量資料 (最好約 1 MB),然後執行 NIST 測試套件來分析資料。判斷每個單位時間可得到最佳熵量的參數。測試下的系統會記錄繪製熵樣本所需的時間。

其中一個小工具是時基誤差內建的啟動測試。基本上,這在執行一些基本分析後,就可以繪製和捨棄 400 樣本 (主要確保時鐘是單調性,同時具備夠高的解析度和可變動性)。如要取得更準確的測試,系統會針對每一組參數重新啟動兩次:一次需要約 1 MB 的資料進行分析,第二次要以「右側」的熵量來啟動,第二次的啟動時間則根據第一階段的熵估計值計算,並使用適當的安全邊界等。請參閱「確定以下統計資料」:entropy_per_1000_bytes。第二階段的測試模擬實際啟動,包括啟動測試。完成第二階段後,選擇開機最快的參數集。當然,每個測試階段都應重複多次,以減少隨機變化。

判定 entropy_per_1000_bytes 統計資料

kernel/lib/crypto/include/lib/crypto/entropy/collector.hcrypto::entropy::Collector 介面需要從例項化時提供 entropy_per_1000_bytes 參數。與時基誤差相關的值目前是以硬式編碼的方式寫入 kernel/lib/crypto/entropy/jitterentropy_collector.cpp。這個值的用意是測量由時基線產生的資料中,每個位元組包含的最小熵 (因為位元組不獨立且均勻分佈),因此小於 8 位元。「每 1000 個位元組」部分單純只是可讓您指定「0.123 位元 / 位元組」等部分熵,不需要使用小數計算 (因為核心程式碼不允許 float,且定點算術可能會造成混淆)。

請使用 NIST 測試套件分析隨機資料樣本來判斷這個值,如熵品質測試文件所述。測試套件可預估最小熵 (以我的經驗來看),重複測試的相同 RNG 有幾十位元 (當熵值約每位元組約 0.5 位元) 時,這項測試非常重要!測試套件取得良好且一致的結果後,請套用安全因數 (即將熵估計值除以 2),然後更新 entropy_per_1000_bytes 的值 (別忘了乘以 1000)。

請注意,entropy_per_1000_bytes 最終應會在某處設定,而非在 jitterentropy_collector.cpp 中以硬式編碼方式寫入。核心 cmdline 甚至是前置處理器符號都可以使用。

測試指令碼相關附註

scripts/entropy-test/jitterentropy/test-tunable 指令碼會自動透過大型測試矩陣執行迴圈。缺點是在單一機器上依序執行測試,因此 (1) 錯誤會使測試管道停滯,因此需要監督;(2) 機器會不斷重新啟動,而非冷啟動 (再加上一個網路啟動重新開機),因此可能會產生測試。但還是有一千次按下關機/關機了!

以下提供一些快樂注意事項:

  1. 透過網路啟動時,指令碼會保持開機伺服器,等待 netcp 成功匯出資料檔案。如果系統停止運作,您可以關機再重新開啟,而現有的啟動伺服器程序會重新啟動失敗的測試。

  2. 假設要對 16 個參數組合執行 10 次測試,看起來會像這樣:

    測試 # 0: ml = 1 ll = 1 bc = 1 bs = 1 測試 # 1: ml = 1 ll = 1 bc = 64 測試 # 2:ml = 1 ll = 1 bc = 1 bc = ml 1 bc = 1 bs = 1

    (輸出檔案從 0 開始編號,所以我先從上述的 0 開始編號)。

    因此,如果測試 #17 失敗,您可以刪除測試 #16 和 #17,然後在每個測試中重新執行 9 個疊代。您至少可以保留第一次疊代的完整結果。理論上,測試可以更聰明,也能保留測試 #16 的現有結果,但目前的殼層指令碼並不複雜。

指令碼不會像我在上方「微調程序」一節中建議的兩階段程序執行。當然可以,但現有指令碼並不是十分複雜。

開放式問題

我們對低熵的依賴程度為何?

先前的做法是選擇小型參數值,盡可能提高每個單位時間的熵。最極端的是 ll=1, ml=1, bs=1, bc=1,但就好像 ll=1, ml=1, bs=64, bc=32 這樣的東西。需要注意的是,測試套件中的變異性不盡相同:假設測試在假設測試中,每個位元組的熵在 0.2 位元範圍內準確,而如要回報每個位元組的熵長度為 0.15 位元,我們要怎麼做?希望連續執行相同的測試幾百次就能找到明確的強制回應值,但仍不太願意依賴低預估值才能準確判斷。

NIST 發布狀態 (第 1302 行,第 35 頁、第二個草稿) 指出,在每樣本的 entropy-per-Sample 大於 0.1 時,估算器「一切正常」。這極低,因此希望它不會實際發生。不過,由於極限性越低,我們應該在它周圍留下一個相當保守的信封。

最佳參數選項是如何根據裝置而定?

在不同架構或硬體上,實際「每位元組位元數」指標的用量明顯有顯著差異。大多數系統是否可能以類似的參數值為最佳狀態 (這樣我們只需要以硬式編碼的方式,將這些值寫入 kernel/lib/crypto/entropy/jitterentropy_collector.cpp)?或者,我們需要將參數放入 MDI 或預先處理工具巨集中,才能針對每個平台 (或合適的精細程度) 使用不同的預設值。

我們甚至能以足夠精細程度記錄最佳參數嗎?

如上所述,但我們其中一個目標是「x86」,也就是在任何 x86 電腦上運作。x86 電腦通常不太習慣。即使我們選擇在版本中加入 JITTERENTROPY_LL_VALUE 等預先處理工具符號 (如在 kernel/project/target/pc-x86.mk 中自訂),是否能為所有電腦選擇理想的值?

如果不是,有哪些選項?

  1. 我們可以根據執行階段中可存取的值 (例如確切 CPU 型號、核心記憶體大小、快取行大小等) 儲存對照表。這看起來好像猶豫不決,或許如果我們能找到一到兩個簡單的屬性,例如「CPU 核心頻率」和「L1 快取大小」,就可能導致這個做法相對不可靠。

  2. 我們可以嘗試自動調整的方法:監控熵串流的品質,並根據即時調整參數。假如我們想要信任這個平台,可能要進行大量測試和正當理由。

  3. 我們可以針對大多數裝置上的設定「良好」參數,並可選擇透過核心 cmdline 或類似機制進行調整。這似乎是我最有可能的結果。我希望「優質」參數很容易找到,且幹擾程度不足以合理解釋極端解決方案。