中繼資料加密

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

設定中繼資料檔案系統

由於在出現中繼資料加密金鑰之前,無法讀取使用者資料分區中的任何內容,因此分區表必須設定名為「中繼資料分區」的獨立分區,用於儲存用來保護此金鑰的 Keymaster Blob。中繼資料分區應為 16 MB。

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

在初始化嘗試掛載 /data 之前,Keymaster 必須處於執行中且就緒狀態。

init.hardware.rc 應已包含 mount_all 指令,可在 on late-fs 段落中掛載 /data。在該行前方加入指令,執行 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 是預設演算法),將中繼資料加密金鑰包裝在硬體中。

由於 Android 11 中 dm-default-key 的核心介面已變更,您也需要確保已在 device.mk 中為 PRODUCT_SHIPPING_API_LEVEL 設定正確的值。舉例來說,如果裝置搭載 Android 11 (API 級別 30),device.mk 應包含以下項目:

PRODUCT_SHIPPING_API_LEVEL := 30

您也可以設定下列系統屬性,無論運送 API 級別為何,一律強制使用新版 dm-default-key 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 互動。

如果 Keymaster 在 mount_all 執行時未完全啟動,就不會回應 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

您也可以設定下列系統屬性,無論發布 API 級別為何,都能強制使用新的音量中繼資料加密方法 (以及新的預設 FBE 政策版本):

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 金鑰的安全性至少與中繼資料加密金鑰一樣高。供應商可以進行核心自訂設定,避免雙重加密,特別是實作 allow_encrypt_override 選項,當系統屬性 ro.crypto.allow_encrypt_override 設為 true 時,Android 會將此選項傳遞至 dm-crypt。Android 通用核心不支援這些自訂項目。

根據預設,dm-crypt 磁碟區中繼資料加密方法會使用 AES-128-CBC 加密演算法,搭配 ESSIV 和 512 位元組加密區塊。您可以設定下列系統屬性 (也用於 FDE) 來覆寫此值:

  • ro.crypto.fde_algorithm 會選取中繼資料加密演算法。可用的選項為 aes-128-cbcadiantum。只有在裝置缺乏 AES 加速功能時,才能使用 Adiantum
  • ro.crypto.fde_sector_size 會選取加密編譯區塊大小。可用的值包括 512、1024、2048 和 4096。針對 Adiantum 加密,請使用 4096。