硬件封裝的密鑰

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

與大多數磁盤和文件加密軟件一樣,Android 的存儲加密傳統上依賴於系統內存中存在的原始加密密鑰,以便可以執行加密。即使加密是由專用硬件而不是軟件執行的,軟件通常仍需要管理原始加密密鑰。

這在傳統上不被視為問題,因為在離線攻擊期間密鑰不會出現,這是存儲加密旨在防止的主要攻擊類型。然而,人們希望提供增強的保護以防止其他類型的攻擊,例如冷啟動攻擊和在線攻擊,在這些攻擊中,攻擊者可能會在不完全破壞設備的情況下泄漏系統內存。

為了解決這個問題,Android 11 引入了對硬件包裝密鑰的支持,其中存在硬件支持。硬件包裝密鑰是存儲密鑰,只有專用硬件才能知道原始形式;軟件只能以包裝(加密)形式查看和使用這些密鑰。該硬件必須能夠生成和導入存儲密鑰,以臨時和長期形式包裝存儲密鑰,派生子密鑰,將一個子密鑰直接編程到內聯加密引擎中,並將單獨的子密鑰返回給軟件。

注意內聯加密引擎(或內聯加密硬件)是指在數據進出存儲設備的過程中對數據進行加密/解密的硬件。通常這是一個 UFS 或 eMMC 主機控制器,它實現了由相應的 JEDEC 規範定義的加密擴展。

設計

本節介紹硬件包裝密鑰功能的設計,包括它需要哪些硬件支持。本次討論的重點是基於文件的加密(FBE),但該解決方案也適用於元數據加密

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

  • 加密密鑰的數量可能會超過密鑰槽的數量。
  • 內聯加密引擎只能用於加密/解密磁盤上的完整數據塊。然而,在 FBE 的情況下,軟件仍然需要能夠進行其他加密工作,例如文件名加密和派生密鑰標識符。軟件仍然需要訪問原始 FBE 密鑰才能完成其他工作。

為了避免這些問題,將存儲密鑰改為硬件包裝密鑰,只能由專用硬件解包和使用。這允許支持無限數量的鍵。此外,密鑰層次結構已修改並部分移至此硬件,這允許將子密鑰返回給軟件以用於無法使用內聯加密引擎的任務。

密鑰層次結構

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

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

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

FBE 類密鑰是原始加密密鑰,Android 將其傳遞給 Linux 內核以解鎖一組特定的加密目錄,例如特定 Android 用戶的憑據加密存儲。 (在內核中,這個密鑰被稱為fscrypt master key 。)從這個密鑰,內核派生出以下子密鑰:

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

相比之下,下圖描述了使用硬件封裝密鑰時 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 in Counter Mode”AES-256-CMAC作為 PRF。請注意,為了兼容,算法的所有部分都必須相同,包括為每個子密鑰選擇 KDF 上下文和標籤。

密鑰包裝

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

  • 臨時包裝:硬件使用每次啟動時隨機生成的密鑰對原始密鑰進行加密,並且不會直接暴露在硬件外部。
  • 長期包裝:硬件使用內置於硬件中的唯一持久密鑰對原始密鑰進行加密,該密鑰不會直接暴露在硬件外部。

傳遞給 Linux 內核以解鎖存儲的所有密鑰都是臨時包裝的。這確保瞭如果攻擊者能夠從系統內存中提取正在使用的密鑰,那麼該密鑰將不僅在設備外無法使用,而且在重啟後在設備上也將無法使用。

同時,Android 仍然需要能夠在磁盤上存儲密鑰的加密版本,以便能夠在第一時間將其解鎖。原始密鑰可用於此目的。然而,最好永遠不要讓原始密鑰出現在系統內存中,這樣它們就永遠不會被提取出來在設備外使用,即使是在啟動時提取的。為此,定義了長期包裝的概念。

為了支持管理以這兩種不同方式包裝的密鑰,硬件必須實現以下接口:

  • 生成和導入存儲密鑰的接口,以長期包裝的形式返回它們。這些接口是通過 KeyMint 間接訪問的,它們對應於TAG_STORAGE_KEY KeyMint 標籤。 vold使用“生成”功能來生成供 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::derive_raw_secret

對於android11內核,在keyslot_manager::features中設置BLK_CRYPTO_FEATURE_WRAPPED_KEYS ,使keyslot_mgmt_ll_ops::keyslot_programkeyslot_mgmt_ll_ops::keyslot_evict支持編程/驅逐硬件包裝密鑰,並實現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 。有關詳細信息,請參閱元數據加密文檔