硬件封裝的密鑰

與大多數磁碟和檔案加密軟體一樣,Android 的儲存加密傳統上依賴系統記憶體中存在的原始加密金鑰,以便可以執行加密。即使加密是由專用硬體而不是軟體執行時,軟體通常仍需要管理原始加密金鑰。

傳統上這並不被視為問題,因為在離線攻擊期間金鑰不會出現,而離線攻擊是儲存加密旨在防範的主要攻擊類型。然而,人們希望提供針對其他類型攻擊的增強保護,例如冷啟動攻擊和線上攻擊,其中攻擊者可能能夠在不完全損害設備的情況下洩漏系統記憶體。

為了解決這個問題,Android 11引入了對硬體封裝按鍵的支持,其中硬體支援是存在的。硬體封裝金鑰是僅以原始形式為專用硬體所知的儲存金鑰;軟體只能看到並使用這些封裝(加密)形式的金鑰。該硬體必須能夠產生和匯入儲存金鑰、以臨時和長期形式包裝儲存金鑰、衍生子金鑰、將一個子金鑰直接編程到內聯加密引擎以及將單獨的子金鑰傳回給軟體。

注意內嵌加密引擎(或稱內嵌加密硬體)是指在資料傳入/傳出儲存裝置時對資料進行加密/解密的硬體。通常這是一個 UFS 或 eMMC 主機控制器,用於實現相應 JEDEC 規範定義的加密擴展。

設計

本節介紹硬體封裝按鍵功能的設計,包括它需要哪些硬體支援。本討論重點討論基於檔案的加密(FBE),但此解決方案也適用於元資料加密

避免在系統記憶體中需要原始加密金鑰的一種方法是將它們僅保存在內聯加密引擎的金鑰槽中。然而,這種方法遇到了一些問題:

  • 加密密鑰的數量可能超過密鑰槽的數量。
  • 內聯加密引擎只能用於加密/解密磁碟上的完整資料區塊。然而,就 FBE 而言,軟體仍需要能夠執行其他加密工作,例如檔案名稱加密和衍生金鑰標識符。軟體仍需要存取原始 FBE 金鑰才能完成其他工作。

為了避免這些問題,儲存金鑰被製成硬體包裝金鑰,只能由專用硬體解包和使用。這允許支援無限數量的密鑰。此外,金鑰層次結構經過修改並部分移至該硬體,這允許將子金鑰傳回給軟體以執行無法使用內聯加密引擎的任務。

關鍵層次結構

可以使用KDF(金鑰衍生函數) (例如HKDF)從其他金鑰派生金鑰,從而形成金鑰層次結構

下圖描述了使用硬體封裝金鑰時 FBE 的典型金鑰層次結構:

FBE 密鑰層次結構(標準)
圖 1. FBE 密鑰層次結構(標準)

FBE 類別金鑰是 Android 傳遞給 Linux 核心以解鎖一組特定加密目錄的原始加密金鑰,例如特定 Android 使用者的憑證加密儲存。 (在核心中,該金鑰稱為fscrypt 主金鑰。)核心從該金鑰衍生出下列子金鑰:

  • 密鑰標識符。這不用於加密,而是用於標識保護特定檔案或目錄的金鑰的值。
  • 文件內容加密金鑰
  • 檔案名稱加密金鑰

相反,下圖描述了使用硬體包裝金鑰時 FBE 的金鑰層次結構:

FBE 金鑰層次結構(附硬體封裝金鑰)
圖 2. 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_keysw_secret ,硬體必須使用加密強度高的 KDF。該 KDF 必須遵循密碼學最佳實踐;它必須具有至少 256 位元的安全強度,即足以供以後使用的任何演算法使用。在派生每種類型的子金鑰時,它還必須使用不同的標籤、上下文和/或特定於應用程式的資訊字串,以確保產生的子金鑰是加密隔離的,即了解其中一個子密鑰不會洩漏任何其他子密鑰。不需要密鑰拉伸,因為原始儲存密鑰已經是統一隨機密鑰。

從技術上講,任何滿足安全要求的 KDF 都可以使用。然而,出於測試目的,有必要在測試程式碼中重新實作相同的 KDF。目前,已審查並實施了一項KDF;它可以在vts_kernel_encryption_test的原始碼中找到。建議硬體使用此 KDF,它使用NIST SP 800-108“計數器模式下的 KDF” ,並以AES-256-CMAC作為 PRF。請注意,為了相容,演算法的所有部分都必須相同,包括 KDF 上下文的選擇和每個子金鑰的標籤。

密鑰包裝

為了滿足硬體包裝金鑰的安全目標,定義了兩種類型的金鑰包裝:

  • 臨時包裝:硬體使用每次啟動時隨機產生的密鑰對原始密鑰進行加密,並且不會直接暴露在硬體之外。
  • 長期包裝:硬體使用硬體內建的唯一、持久性金鑰對原始金鑰進行加密,該金鑰不會直接暴露在硬體外部。

所有傳遞給 Linux 核心以解鎖儲存的密鑰都被暫時包裝。這確保瞭如果攻擊者能夠從系統記憶體中提取正在使用的金鑰,則該金鑰不僅在裝置外無法使用,而且在重新啟動後在裝置上也無法使用。

同時,Android 仍然需要能夠在磁碟上儲存密鑰的加密版本,以便能夠首先解鎖它們。原始密鑰可用於此目的。然而,我們希望原始密鑰根本不存在於系統記憶體中,這樣即使在啟動時提取它們,它們也永遠不會被提取出來在設備外使用。為此,定義了長期包裹的概念。

為了支援管理以這兩種不同方式包裝的金鑰,硬體必須實作以下介面:

  • 產生和匯入儲存金鑰的接口,以長期包裝形式傳回它們。這些介面透過KeyMint間接訪問,它們對應於KeyMint標籤TAG_STORAGE_KEYvold使用「產生」功能來產生供 Android 使用的新儲存金鑰,而vts_kernel_encryption_test使用「導入」功能來導入測試金鑰。
  • 將長期包裝儲存金鑰轉換為臨時包裝儲存金鑰的介面。這對應於convertStorageKeyToEphemeral KeyMint 方法。 voldvts_kernel_encryption_test都使用此方法來解鎖儲存。

金鑰包裝演算法是一個實作細節,但它應該使用強大的 AEAD,例如帶有隨機 IV 的 AES-256-GCM。

需要更改軟體

AOSP 已經有了支援硬體封裝金鑰的基本架構。這包括對vold等用戶空間組件的支持,以及blk-cryptofscryptdm-default-key中的 Linux 核心支援。

但是,需要進行一些特定於實現的更改。

KeyMint 的變化

必須修改設備的 KeyMint 實作以支援TAG_STORAGE_KEY並實作convertStorageKeyToEphemeral方法。

在Keymaster中,使用exportKey代替convertStorageKeyToEphemeral

Linux 核心變化

必須修改裝置內聯加密引擎的 Linux 核心驅動程式以支援硬體包裝金鑰。

對於android14及更高版本的內核,請在blk_crypto_profile::key_types_supported中設定BLK_CRYPTO_KEY_TYPE_HW_WRAPPED ,使blk_crypto_ll_ops::keyslot_programblk_crypto_ll_ops::keyslot_evict blk_crypto_ll_ops::derive_sw_secret ::

對於android12android13內核,在blk_keyslot_manager::features中設定BLK_CRYPTO_FEATURE_WRAPPED_KEYS ,使blk_ksm_ll_ops::keyslot_programblk_ksm_ll_ops::keyslot_evict和blk_ksm_ll_ops::keyslot_evict_ops blk_ksm_ll_ops::derive_raw_secret

對於android11內核,在keyslot_manager::features中設定BLK_CRYPTO_FEATURE_WRAPPED_KEYS ,使keyslot_mgmt_ll_ops::keyslot_programkeyslot_mgmt_ll_ops::keyslot_evict /cterive 包裝,並實現驅逐硬體包裝,並keyslot_mgmt_ll_ops::derive_raw_secret

測試

儘管使用硬體封裝金鑰的加密比使用標準金鑰的加密更難測試,但仍可以透過匯入測試金鑰並重新實現硬體所執行的金鑰派生來進行測試。這是在vts_kernel_encryption_test中實現的。若要執行此測試,請執行:

atest -v vts_kernel_encryption_test

讀取測試日誌並驗證硬體包裝的金鑰測試用例(例如FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicyDmDefaultKeyTest.TestHwWrappedKey )是否未因為未偵測到對硬體包裝的支援而被跳過,因為測試結果仍將在那種情況。

啟用

一旦裝置的硬體封裝金鑰支援正常運作,您可以對裝置的fstab檔案進行以下更改,以使 Android 將其用於 FBE 和元資料加密:

  • FBE:將wrappedkey_v0標誌加入fileencryption參數。例如,使用fileencryption=::inlinecrypt_optimized+wrappedkey_v0 。有關更多詳細信息,請參閱FBE 文件
  • 元資料加密:將wrappedkey_v0標誌加入metadata_encryption參數。例如,使用metadata_encryption=:wrappedkey_v0 。有關更多詳細信息,請參閱元資料加密文件