元數據加密

Android 7.0 及更高版本支持基於文件的加密(FBE)。 FBE 允許使用可以獨立解鎖的不同密鑰對不同文件進行加密。這些密鑰用於加密文件內容和文件名。使用 FBE 時,其他信息(例如目錄佈局、文件大小、權限和創建/修改時間)不會加密。這些其他信息統稱為文件系統元數據。

Android 9 引入了對元數據加密的支持。使用元數據加密,啟動時存在的單個密鑰會加密 FBE 未加密的任何內容。此密鑰受 Keymaster 保護,而 Keymaster 又受驗證啟動保護。

每當啟用 FBE 時,始終在可採用的存儲上啟用元數據加密。元數據加密也可以在內部存儲上啟用。搭載 Android 11 或更高版本的設備必須啟用內部存儲元數據加密。

內部存儲的實現

您可以通過設置metadata文件系統、更改初始化序列以及在設備的 fstab 文件中啟用元數據加密,在新設備的內部存儲上設置元數據加密。

先決條件

元數據加密只能在數據分區第一次格式化時設置。因此,此功能僅適用於新設備;這不是OTA應該改變的。

元數據加密需要在內核中啟用dm-default-key模塊。在 Android 11 及更高版本中, dm-default-key受 Android 通用內核 4.14 及更高版本支持。此版本的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

設置元數據文件系統

因為在元數據加密密鑰存在之前,用戶數據分區中的任何內容都無法讀取,因此分區表必須留出一個稱為“元數據分區”的單獨分區,用於存儲保護此密鑰的 keymaster 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。這可以通過在fs_mgr_flags列中設置metadata_encryption選項來覆蓋:

  • 在缺乏 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 工具連接到vold over binder以設置元數據加密設備並掛載分區。在此調用期間, init被阻止,並且嘗試讀取或設置init屬性將被阻止,直到mount_all完成。如果在這個階段, vold工作的任何部分在讀取或設置屬性時被直接或間接阻塞,就會導致死鎖。重要的是要確保vold可以完成讀取密鑰、與 Keymaster 交互以及掛載數據目錄的工作,而無需與init進一步交互。

如果在mount_all運行時 Keymaster 沒有完全啟動,它不會響應vold直到它從init讀取某些屬性,從而導致完全描述的死鎖。將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卷元數據加密方法使用 AES-256-XTS 加密算法和 4096 字節加密扇區。可以通過設置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 密鑰至少與元數據加密密鑰一樣難以被破壞。供應商可以進行內核定制以避免雙重加密,特別是通過實現系統屬性ro.crypto.allow_encrypt_override設置為true時 Android 將傳遞給dm-cryptallow_encrypt_override選項。 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。