元數據加密

Android 7.0 及更高版本支援基於檔案的加密(FBE)。 FBE允許使用不同的金鑰對不同的檔案進行加密,並且可以獨立解鎖。這些密鑰用於加密檔案內容和檔案名稱。使用 FBE 時,其他資訊(例如目錄佈局、檔案大小、權限和建立/修改時間)不會加密。總的來說,這些其他資訊稱為檔案系統元資料。

Android 9 引入了對元資料加密的支援。透過元資料加密,啟動時出現的單一金鑰可以加密 FBE 未加密的任何內容。此金鑰受 Keymaster 保護,而 Keymaster 又受驗證啟動保護。

只要啟用 FBE,元資料加密就始終在可採用的儲存空間上啟用。也可以在內部儲存上啟用元資料加密。使用 Android 11 或更高版本啟動的裝置必須啟用內部儲存元資料加密。

內部儲存的實現

您可以透過設定metadata檔案系統、變更初始化序列以及在裝置的 fstab 檔案中啟用元資料加密,在新裝置的內部儲存體上設定元資料加密。

先決條件

元資料加密只能在資料分割區首次格式化時設定。因此,該功能僅適用於新設備;這不是 OTA 應該改變的事情。

元資料加密要求在內核中啟用dm-default-key模組。在 Android 11 及更高版本中,Android 通用核心版本 4.14 及更高版本支援dm-default-key 。此版本的dm-default-key使用與硬體和供應商無關的加密框架,稱為blk-crypto

若要啟用dm-default-key ,請使用:

CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_DM_DEFAULT_KEY=y

dm-default-key在可用時使用內聯加密硬體(在資料傳入/傳出儲存裝置時對資料進行加密/解密的硬體)。如果您使用內聯加密硬件,則還需要啟用內核加密 API 的回退:

CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y

當不使用內聯加密硬體時,您還應該按照FBE 文件中的建議啟用任何可用的基於 CPU 的加速。

在 Android 10 及更低版本中,Android 通用核心不支援dm-default-key 。因此,由供應商來實施dm-default-key

設定元資料檔案系統

由於在存在元資料加密金鑰之前無法讀取使用者資料分割區中的任何內容,因此分割區表必須留出一個稱為「元資料分割區」的單獨分割區,用於儲存保護該金鑰的金鑰主blob 。元資料分區應為 16MB。

fstab.hardware必須包含元資料檔案系統的條目,該元資料檔案系統位於安裝在/metadata的分割區上,包括formattable標誌以確保它在啟動時格式化。 f2fs 檔案系統不適用於較小的分割區;我們建議使用 ext4。例如:

/dev/block/bootdevice/by-name/metadata              /metadata          ext4        noatime,nosuid,nodev,discard                          wait,check,formattable

要確保/metadata掛載點存在,請將以下行加入BoardConfig-common.mk

BOARD_USES_METADATA_PARTITION := true

初始化順序的更改

當使用元資料加密時, vold必須在掛載/data之前運行。為了確保它足夠早啟動,請將以下節添加到init.hardware.rc

# We need vold early for metadata encryption
on early-fs
    start vold

在 init 嘗試掛載/data之前,Keymaster 必須正在運行並準備就緒。

init.hardware.rc應該已經包含一個mount_all指令,該指令將/data本身安裝在on late-fs節中。在此行之前,新增指令以執行wait_for_keymaster服務:

on late-fs
   … 
    # Wait for keymaster
    exec_start wait_for_keymaster

    # Mount RW partitions which need run fsck
    mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late

開啟元資料加密

最後將keydirectory=/metadata/vold/metadata_encryption加入到userdatafstab條目的fs_mgr_flags欄位。例如,完整的 fstab 行可能如下所示:

/dev/block/bootdevice/by-name/userdata              /data              f2fs        noatime,nosuid,nodev,discard,inlinecrypt latemount,wait,check,fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized,keydirectory=/metadata/vold/metadata_encryption,quota,formattable

預設情況下,內部儲存的元資料加密演算法為 AES-256-XTS。這可以透過設定metadata_encryption選項來覆蓋,也在fs_mgr_flags欄位中:

  • 在缺乏 AES 加速的裝置上,可以透過設定metadata_encryption=adiantum來啟用Adiantum 加密
  • 在支援硬體包裝金鑰的裝置上,可以透過設定metadata_encryption=aes-256-xts:wrappedkey_v0 (或等效的metadata_encryption=:wrappedkey_v0 ,因為aes-256-xts是預設演算法)來對元資料加密金鑰進行硬體包裝。

由於dm-default-key的核心介面在 Android 11 中發生了更改,因此您還需要確保在device.mk中為PRODUCT_SHIPPING_API_LEVEL設定了正確的值。例如,如果您的裝置啟動時搭載 Android 11(API 等級 30),則device.mk應包含:

PRODUCT_SHIPPING_API_LEVEL := 30

您也可以設定以下系統屬性來強制使用新的dm-default-key API,無論發布的 API 等級:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.crypto.dm_default_key.options_format.version=2

驗證

若要驗證元資料加密是否已啟用且正常運作,請執行下面所述的測試。另請注意下面描述的常見問題

測試

首先執行以下命令來驗證內部儲存上是否啟用了元資料加密:

adb root
adb shell dmctl table userdata

輸出應類似:

Targets in the device-mapper table for userdata:
0-4194304: default-key, aes-xts-plain64 - 0 252:2 0 3 allow_discards sector_size:4096 iv_large_sectors

如果您透過在裝置的fstab中設定metadata_encryption選項來覆蓋預設加密設置,則輸出將與上面略有不同。例如,如果您啟用了Adiantum 加密,則第三個欄位將為xchacha12,aes-adiantum-plain64而不是aes-xts-plain64

接下來,執行vts_kernel_encryption_test來驗證元資料加密和FBE的正確性:

atest vts_kernel_encryption_test

或者:

vts-tradefed run vts -m vts_kernel_encryption_test

常見問題

在呼叫mount_all期間(掛載元資料加密的/data分割區), init會執行 vdc 工具。 vdc 工具透過binder連接到vold以設定元資料加密裝置並掛載分割區。在此呼叫期間, init被阻止,讀取或設定init屬性的嘗試將被阻止,直到mount_all完成。如果在此階段, vold工作的任何部分在讀取或設定屬性時直接或間接被阻止,則會導致死鎖。重要的是要確保vold可以完成讀取金鑰、與 Keymaster 互動以及掛載資料目錄的工作,而無需進一步與init互動。

如果在mount_all運行時 Keymaster 未完全啟動,則在從init讀取某些屬性之前,它不會回應vold ,從而導致所描述的死鎖。依照規定將exec_start wait_for_keymaster放置在相關的mount_all呼叫之上可確保 Keymaster 提前完全運行,從而避免這種死鎖。

可採用儲存上的配置

自 Android 9 起,每當啟用 FBE 時,即使未在內部儲存上啟用元資料加密,也會在可採用儲存體上啟用某種形式的元資料加密。

在 AOSP 中,可採用儲存上有兩種元資料加密實作:一種基於dm-crypt已棄用的實現,以及一種基於dm-default-key較新的實作。為了確保為您的裝置選擇正確的實現,請確保您已在device.mk中為PRODUCT_SHIPPING_API_LEVEL設定正確的值。例如,如果您的裝置啟動時搭載 Android 11(API 等級 30),則device.mk應包含:

PRODUCT_SHIPPING_API_LEVEL := 30

您還可以設定以下系統屬性來強制使用新的捲元資料加密方法(以及新的預設 FBE 策略版本),無論發布的 API 等級為何:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.crypto.volume.metadata.method=dm-default-key \
    ro.crypto.dm_default_key.options_format.version=2 \
    ro.crypto.volume.options=::v2

目前的方法

在搭載 Android 11 或更高版本的裝置上,可採用儲存上的元資料加密使用dm-default-key核心模組,就像內部儲存一樣。請參閱上面的先決條件以了解要啟用的核心配置選項。請注意,在裝置內部儲存上工作的內聯加密硬體可能在可採用儲存體上不可用,因此可能需要CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y

預設情況下, dm-default-key磁碟區元資料加密方法使用具有 4096 位元組加密磁區的 AES-256-XTS 加密演算法。可以透過設定ro.crypto.volume.metadata.encryption系統屬性來覆寫該演算法。此屬性的值與上述的metadata_encryption fstab 選項具有相同的語法。例如,在缺乏 AES 加速的裝置上,可以透過設定ro.crypto.volume.metadata.encryption=adiantum來啟用Adiantum 加密

舊方法

在搭載 Android 10 或更低版本的裝置上,可採用儲存上的元資料加密使用dm-crypt核心模組而非dm-default-key

CONFIG_DM_CRYPT=y

dm-default-key方法不同, dm-crypt方法會導致檔案內容加密兩次:一次使用 FBE 金鑰,一次使用元資料加密金鑰。這種雙重加密會降低效能,並且不需要實現元資料加密的安全目標,因為 Android 確保 FBE 金鑰至少與元資料加密金鑰一樣難以洩露。供應商可以進行核心自訂以避免雙重加密,特別是透過實作allow_encrypt_override選項,當系統屬性ro.crypto.allow_encrypt_override設定為true時,Android 將傳遞給dm-crypt 。 Android 通用核心不支援這些自訂。

預設情況下, dm-crypt磁碟區元資料加密方法使用具有 ESSIV 和 512 位元組加密磁區的 AES-128-CBC 加密演算法。這可以透過設定以下系統屬性(也用於 FDE)來覆蓋:

  • ro.crypto.fde_algorithm選擇元資料加密演算法。選擇是aes-128-cbcadiantum 。只有在設備缺乏 AES 加速時才可使用Adiantum
  • ro.crypto.fde_sector_size選擇加密磁區大小。選項包括 512、1024、2048 和 4096。對於 Adiantum 加密,請使用 4096。