硬件封裝的密鑰

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

這在傳統上不被視為問題,因為在離線攻擊期間密鑰不會出現,這是存儲加密旨在防禦的主要攻擊類型。然而,有提供對其他類型的攻擊,比如增加保護的願望冷啟動攻擊,和在線攻擊其中的攻擊者可以完全不影響設備洩漏系統內存。

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

內嵌加密引擎(或內聯加密硬件)是指硬件加密/解密數據,而它是在它的途中從存儲設備/。通常這是一個 UFS 或 eMMC 主機控制器,它實現了相應 JEDEC 規範定義的加密擴展。

設計

本節介紹硬件封裝密鑰功能的設計,包括它需要哪些硬件支持。這個討論集中於基於文件的加密(FBE),但解決方案適用於元數據加密過。

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

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

為了避免這些問題,所述存儲密鑰被代替做成硬件包裹鍵,其只能被解開,並通過專用的硬件使用。這允許支持無限數量的密鑰。此外,密鑰層次結構被修改並部分移至該硬件,這允許將子密鑰返回給軟件,以執行無法使用內聯加密引擎的任務。

密鑰層次結構

密鑰可以從使用其他鍵導出KDF(密鑰導出函數)諸如香港民主促進會,產生密鑰層級

下圖描繪了當使用硬件包裹密鑰FBE典型密鑰層級:

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

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

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

相比之下,下圖描述了使用硬件封裝密鑰時 FBE 的密鑰層次結構:

FBE 密鑰層次結構(帶有硬件封裝的密鑰)
圖2. FBE密鑰層次結構(與硬件的包裝的密鑰)

與之前的情況相比,密鑰層次結構中增加了一個附加級別,並且文件內容加密密鑰已重新定位。根節點仍然代表 Android 傳遞給 Linux 以解鎖一組加密目錄的密鑰。但是,現在該密鑰處於臨時包裝的形式,為了使用它,必須將其傳遞給專用硬件。該硬件必須實現兩個採用臨時包裝密鑰的接口:

  • 一個接口來推導inline_encryption_key並將其直接編入內嵌加密引擎的keyslot。這允許在沒有軟件訪問原始密鑰的情況下加密/解密文件內容。在Android共同內核,該接口對應於blk_ksm_ll_ops::keyslot_program操作,這必須由存儲驅動器來實現。
  • 一個接口派生並返回sw_secret (“軟件的秘密” -也被稱為“原始的秘密”在一些地方),這是Linux用來導出子項不是文件內容加密的其他一切的關鍵。在Android共同內核,該接口對應於blk_ksm_ll_ops::derive_raw_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間接訪問,並且它們對應於TAG_STORAGE_KEY KeyMint標籤。 “生成”功能適用vold來產生由Android使用新的存儲密鑰,而“導入”功能適用vts_kernel_encryption_test導入測試鍵。
  • 將長期包裝的存儲密鑰轉換為臨時包裝的存儲密鑰的接口。這對應於convertStorageKeyToEphemeral KeyMint方法。該方法用於通過兩者voldvts_kernel_encryption_test以便解鎖的存儲。

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

需要更改軟件

AOSP 已經有一個支持硬件封裝密鑰的基本框架。這包括在用戶空間的組件,如支持vold ,以及在BLK-加密,fscryptDM-默認鍵的Linux內核支持。

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

KeyMint 的變化

該器件的KeyMint實施必須進行修改,以支持TAG_STORAGE_KEY和實施convertStorageKeyToEphemeral方法。

在鑰匙大師, exportKey來代替convertStorageKeyToEphemeral

Linux內核更改

Linux內核驅動程序對設備的內嵌加密引擎必須進行修改,以一套BLK_CRYPTO_FEATURE_WRAPPED_KEYS ,使keyslot_program()keyslot_evict()操作支持編程/逐出硬件包裹的按鍵,並實現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 。有關詳細信息,請參閱元數據加密文檔