本文件說明 Zircon 加密編譯安全虛擬隨機號碼產生器 (CPRNG) 的設計,包括其演算法、(重新)種植程序和熵來源。
說明
Zircon 內建的 CPRNG 會以非阻塞的方式提供經過加密的安全虛擬資料。使用者空間程式可透過 zx_cprng_draw()
系統呼叫來存取。
Zircon 的 CPRNG 只會信任可從核心內部直接存取的熵來源,因為核心以外的任何項目 (例如這些視為使用者空間程式的驅動程式) 不可信任。為了讓 CPRNG 正常運作,至少需要其中一個來源。不過,使用者空間程式可能會透過 zx_cprng_add_entropy()
系統呼叫,將額外的熵插入 CPRNG。
演算法
Zircon 的 CPRNG 是偽隨機號碼產生器。其實作位於 zircon/kernel/lib/crypto
。它支援兩項作業:Draw()
和 AddEntropy()
,對應上述兩種系統呼叫。內部狀態包含 256 位元 key
和 128 位元 nonce
。key
必須保存密鑰,因為 CPRNG 輸出內容的知識可以穩定地預測。一開始,key
會使用一些隨機位元組 (請參閱下一節) 進行初始化,nonce
則初始化為 0。
呼叫 Draw()
方法時:
nonce
已增加。使用 ChaCha20 演算法搭配
key
和nonce
加密輸出緩衝區。
此處的 nonce
會針對每個 Draw()
要求遞增,以確保不同的結果。呼叫端提供緩衝區,以便執行就地加密作業。系統會使用緩衝區中的所有現有資料,因為這些資料不會影響安全性屬性。
收到 AddEntropy()
要求時,系統會混合其他熵與舊金鑰,藉此更新 key
:
k<sub>new</sub> = H(e || k<sub>old</sub>)
其中 k<sub>old</sub>
和 k<sub>new</sub>
是新舊且新的 key
,e
是輸入位元組,H
是 SHA256 雜湊函式,||
則代表串連。舊鍵包含在雜湊中,以確保呼叫端 (例如呼叫 zx_cprng_add_entropy()
的使用者空間程式) 無法清除舊的 key
,並將其替換為這些程式控制項。
播種與復育
呼叫 AddEntropy()
方法會執行 Zircon CPRNG 的初始播種。虛擬記憶體 ASLR 需要初始播種,因此在使用者空間開始之前,對 AddEntropy()
方法發出的第一個呼叫會在使用者空間開始前提早進行。設定初始初始值,以便 CPRNG 運作,因為 Draw()
方法會封鎖,直到新增足夠的熵為止。
初始播種後,系統會建立執行緒,藉由呼叫 AddEntropy()
方法,每 30 秒重新填入 CPRNG。這可確保正向密碼 (確保 CPRNG 上次重新種後所執行的所有輸出內容皆安全無虞,即使內部狀態遭到入侵)。
熵來源
Zircon 的 CPRNG 有數種可用於播種和重種的熵來源:
核心 cmdline 選項
kernel.entropy-mixin
的熵,詳情請參閱 kernel_cmdline.md。硬體 RNG 的熵,例如 x86 裝置上的
RDSEED
指令和其他硬體專屬 RNG。
核心 cmdline 是啟動時在啟動時傳入的常數,因此僅可在初始種子使用。硬體和時基熵的熵可用於初始種子和重新種子。如要確保 CPRNG 充足 (重新) 從所選熵來源種子,可以使用核心 cmdline kernel.cprng-(re)seed-require.*
選項。詳情請參閱 kernel_cmdline.md。
可能還有其他可用的熵來源,例如可信平台模組 (TPM),但我們目前還沒有強大的架構,無法針對使用者空間程式安全地與核心中的 CPRNG 子系統進行通訊。