如同大多數的磁碟與檔案加密軟體,Android 的儲存空間加密機制一樣 通常依賴系統記憶體中的原始加密金鑰 才能加密即使是透過專用硬體而非軟體執行加密作業,軟體通常仍需要管理原始加密金鑰。
這在傳統上並未被視為問題,因為在離線攻擊期間,系統不會顯示金鑰,而這正是儲存空間加密功能旨在防範的主要攻擊類型。不過,仍希望 針對其他類型的攻擊 (例如冷啟動) 強化防護 ,以及攻擊者可能基於安全目的洩漏系統的線上攻擊 而不破壞裝置
為解決這個問題,Android 11 推出了硬體包裝金鑰支援功能,前提是硬體支援。硬體包裝的金鑰是原始形式的儲存金鑰 專用硬體;軟體只能在已包裝的金鑰中查看和處理這些金鑰 (加密) 表單。這項硬體必須能夠產生及匯入儲存空間金鑰、以暫時和長期形式包裝儲存空間金鑰、衍生子金鑰、直接將一個子金鑰程式設計至內嵌加密引擎,以及將個別子金鑰傳回至軟體。
注意:內嵌加密引擎或內嵌加密引擎 加密硬體) 是指將資料加密/解密 收發檔案。通常是 UFS 或 eMMC 主機 控制器,可實作由對應的 JEDEC 規格。
設計
本節介紹硬體包裝按鍵功能的設計,包括所需的硬體支援。本討論重點是檔案型加密 (FBE),但解決方案也適用於中繼資料加密。
如要避免需要使用系統記憶體中的原始加密金鑰, 這些金鑰只儲存在內嵌加密引擎的金鑰運算單元中。不過,這項做法會遇到一些問題:
- 加密金鑰的數量可能會超過金鑰專用的記憶體位址數量。
- 內嵌加密貨幣引擎只能用於加密/解密 磁碟資料不過,就 FBE 而言,軟體仍要能 執行其他加密編譯作業,例如檔案名稱加密和衍生金鑰 識別碼軟體仍須存取原始 FBE 金鑰,才能 執行其他工作
為避免這類問題,系統會將儲存空間金鑰改為 「硬體包裝的金鑰」,這類金鑰只能解開包裝, 專屬硬體這樣一來,系統就能支援無限數量的鍵。此外,金鑰階層會經過修改,並部分移至這項硬體,讓子金鑰可傳回至軟體,用於無法使用內嵌加密編譯引擎的作業。
金鑰階層
您可以使用 KDF (金鑰衍生函式) (例如 HKDF) 從其他金鑰衍生金鑰,進而產生金鑰階層。
下圖描述 FBE 在 「不會」使用硬體包裝的金鑰:
FBE 類別金鑰是 Android 傳遞至 Linux 核心的原始加密金鑰,用於解鎖特定的加密目錄組合,例如特定 Android 使用者的憑證加密儲存空間。(在核心中, 稱為 fscrypt 主金鑰)。核心會從這個鍵衍生出下列子鍵:
- 鍵 ID。這不是用於加密,而是用來識別用於保護特定檔案或目錄的金鑰。
- 檔案內容加密金鑰
- 檔案名稱加密金鑰
相反地,下圖描述 FBE 的 使用的是硬體包裝的金鑰:
與先前的案例相比,額外在索引鍵中新增了層級 階層,且檔案內容加密金鑰重新位置。根目錄 節點仍代表 Android 傳遞給 Linux 以解鎖一組 加密目錄不過,現在該金鑰處於臨時包裝的形式,因此必須傳送至專用硬體才能使用。這個硬體必須 實作兩個介面,以使用暫時包裝的金鑰:
- 一個介面,用於擷取
inline_encryption_key
,並直接將其編程至內嵌加密引擎的鍵槽。這樣一來,即使軟體無法存取原始金鑰,也能加密/解密檔案內容。在 Android 常用核心中,這個介面會對應至blk_crypto_ll_ops::keyslot_program
作業,必須是 由儲存驅動程式實作 - 一個介面,用於衍生並傳回
sw_secret
(「軟體密鑰」-- 在某些地方也稱為「原始密鑰」),這是 Linux 用來衍生檔案內容加密以外所有項目的子金鑰。在 Android 常用核心中,這個介面會對應至blk_crypto_ll_ops::derive_sw_secret
作業,必須是 由儲存驅動程式實作
導出 inline_encryption_key
和 sw_secret
原始儲存金鑰,硬體必須使用經過加密的高強度 KDF。這個 KDF
必須遵循密碼學最佳做法。其安全強度只有
等於 256 位元,已經足以容納後續使用的演算法。而且必須使用
不重複標籤、背景資訊和應用程式專屬資訊字串
衍生各類型的子鍵,藉此確保產生的子鍵
加密作業,也就是說,得知其中一份資料後不會發現
其他。不需要延展金鑰,因為原始儲存金鑰已經是
完全隨機的隨機金鑰
從技術層面來說,任何符合安全性規定的 KDF 都可以使用。不過,基於測試目的,務必在測試時重新導入相同的 KDF。
測試程式碼目前,我們已審查並實作一個 KDF,您可以在 vts_kernel_encryption_test
的原始碼中找到該 KDF。我們建議硬體使用這個 KDF,其使用 NIST SP 800-108 "KDF in Counter Mode" 搭配 AES-256-CMAC 做為 PRF。請注意,您必須能夠相容
演算法的部分必須相同,包括選擇的 KDF 結構定義
為每個子鍵建立和標籤
金鑰包裝
為達到硬體包裝金鑰的安全性目標,我們有兩種金鑰包裝 定義:
- 暫時包裝:硬體會使用金鑰加密原始金鑰 這組 ID 在每次啟動時隨機產生,不會直接公開 硬體元件
- 長期包裝:硬體會使用 專屬永久金鑰,並非直接內建於硬體中 暴露於硬體外
所有傳遞至 Linux 核心的金鑰,都是為了解鎖儲存空間而暫時包裝的。這可確保即使攻擊者從系統記憶體中擷取目前使用的金鑰,該金鑰仍無法在裝置關機後使用,也無法在裝置重新啟動後使用。
同時,Android 仍需能夠在磁碟上儲存金鑰的加密版本,以便在第一時間解鎖金鑰。原始 就是基於這個目的不過,我們建議您不要 金鑰存在於系統記憶體中 即使在啟動時擷取,也不成問題因此,我們定義了長期包裝的概念。
為了支援以這兩種不同方式包裝的金鑰,硬體必須實作下列介面:
- 產生及匯入儲存空間金鑰的介面,以長期包裝形式傳回。這些介面可經由
KeyMint,而且與
TAG_STORAGE_KEY
KeyMint 標記相對應。vold
會使用「產生」功能,為 Android 產生新的儲存空間金鑰,而vts_kernel_encryption_test
會使用「匯入」功能匯入測試金鑰。 - 這個介面可將長期包裝的儲存空間金鑰轉換為暫時包裝的儲存空間金鑰。這會對應至
convertStorageKeyToEphemeral
KeyMint 方法。vold
和vts_kernel_encryption_test
都會使用這個方法解鎖儲存空間。
金鑰包裝演算法是實作詳細資料,但應使用 高強度 AEAD,例如 AES-256-GCM 與隨機 IV。
必須變更軟體
AOSP 已提供基本架構,可支援硬體包裝金鑰。這個
包括支援使用者空間元件,例如 vold
做為 blk-crypto、fscrypt 的 Linux kernel 支援,以及
dm-default-key。
不過,您需要進行一些針對導入作業的調整。
KeyMint 異動
必須修改裝置的 KeyMint 實作,才能支援
TAG_STORAGE_KEY
,並導入
convertStorageKeyToEphemeral
方法。
在 Keymaster 中,使用 exportKey
而非 convertStorageKeyToEphemeral
。
Linux kernel 變更
必須修改裝置內嵌加密引擎的 Linux 核心驅動程式 可支援硬體包裝的金鑰
對於 android14
以上核心,
設定BLK_CRYPTO_KEY_TYPE_HW_WRAPPED
位於blk_crypto_profile::key_types_supported
,
CANNOT TRANSLATEblk_crypto_ll_ops::keyslot_program
和 blk_crypto_ll_ops::keyslot_evict
支援程式設計/撤銷硬體包裝金鑰;
並實作 blk_crypto_ll_ops::derive_sw_secret
。
針對 android12
和 android13
核心,請在 blk_keyslot_manager::features
中設定 BLK_CRYPTO_FEATURE_WRAPPED_KEYS
,讓 blk_ksm_ll_ops::keyslot_program
和 blk_ksm_ll_ops::keyslot_evict
支援程式設計/淘汰硬體包裝金鑰,並實作 blk_ksm_ll_ops::derive_raw_secret
。
針對 android11
核心,請在 keyslot_manager::features
中設定 BLK_CRYPTO_FEATURE_WRAPPED_KEYS
,讓 keyslot_mgmt_ll_ops::keyslot_program
和 keyslot_mgmt_ll_ops::keyslot_evict
支援程式設計/淘汰硬體包裝的鍵,並實作 keyslot_mgmt_ll_ops::derive_raw_secret
。
測試
雖然使用硬體包裝的金鑰加密會比加密更難測試
您可以匯入測試金鑰
重新實作硬體確實執行的關鍵衍生工具在這個
在 vts_kernel_encryption_test
中。如要執行這項測試
執行:
atest -v vts_kernel_encryption_test
請閱讀測試記錄,並確認硬體包裝金鑰測試案例 (例如 FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy
和 DmDefaultKeyTest.TestHwWrappedKey
) 並未因未偵測到硬體包裝金鑰的支援而略過,因為在這種情況下,測試結果仍會是「通過」。
啟用按鍵
一旦裝置的硬體包裝金鑰支援功能正常運作,您就可以
對裝置的 fstab
檔案進行下列變更
Android 用來加密 FBE 和中繼資料:
- FBE:將
wrappedkey_v0
標記新增至fileencryption
參數。例如使用fileencryption=::inlinecrypt_optimized+wrappedkey_v0
。詳情請參閱 FBE 說明文件。 - 中繼資料加密:將
wrappedkey_v0
標記新增至metadata_encryption
參數。舉例來說,請使用metadata_encryption=:wrappedkey_v0
。詳情請參閱結構描述資料加密說明文件。