基于文件的加密

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

Android 7.0 及更高版本支持基于文件的加密 (FBE)。基于文件的加密允许使用可以独立解锁的不同密钥对不同文件进行加密。

本文介绍如何在新设备上启用基于文件的加密,以及系统应用程序如何使用 Direct Boot API 为用户提供最佳、最安全的体验。

直接启动

基于文件的加密启用了 Android 7.0 中引入的一项称为Direct Boot的新功能。直接启动允许加密设备直接启动到锁定屏幕。以前,在使用全盘加密 (FDE) 的加密设备上,用户需要提供凭据才能访问任何数据,从而阻止手机执行除最基本操作之外的所有操作。例如,警报无法运行,无障碍服务不可用,电话无法接听电话,但仅限于基本的紧急拨号操作。

通过引入基于文件的加密 (FBE) 和新的 API 以使应用程序了解加密,这些应用程序可以在有限的上下文中运行。这可能发生在用户提供其凭据同时仍保护私人用户信息之前。

在启用 FBE 的设备上,设备的每个用户都有两个可供应用程序使用的存储位置:

  • 凭据加密 (CE) 存储,这是默认存储位置,仅在用户解锁设备后可用。
  • 设备加密 (DE) 存储,这是在直接启动模式期间和用户解锁设备后都可用的存储位置。

这种分离使工作配置文件更加安全,因为它允许一次保护多个用户,因为加密不再仅基于启动时密码。

Direct Boot API 允许加密感知应用程序访问这些区域中的每一个。应用程序生命周期发生了变化,以适应在用户的 CE 存储被解锁以响应在锁定屏幕上首次输入凭据时通知应用程序的需要,或者在工作配置文件提供工作挑战的情况下。运行 Android 7.0 的设备必须支持这些新的 API 和生命周期,无论它们是否实现 FBE。虽然,没有 FBE,DE 和 CE 存储将始终处于解锁状态。

Android 开源项目 (AOSP) 中提供了在 Ext4 和 F2FS 文件系统上的基于文件的加密的完整实现,并且只需要在满足要求的设备上启用。选择使用 FBE 的制造商可能希望探索基于所使用的片上系统 (SoC) 优化功能的方法。

AOSP 中所有必要的软件包都已更新为支持直接启动。但是,如果设备制造商使用这些应用程序的定制版本,他们将希望至少确保有直接启动感知包提供以下服务:

  • 电话服务和拨号器
  • 锁屏密码输入法

示例和来源

Android 提供了基于文件的加密的参考实现,其中vold ( system/vold ) 提供了在Android 上管理存储设备和卷的功能。 FBE 的添加为vold 提供了几个新命令,以支持对多个用户的CE 和DE 密钥进行密钥管理。除了在内核中使用基于文件的加密功能的核心更改外,包括锁屏和 SystemUI 在内的许多系统包都已修改为支持 FBE 和直接启动功能。这些包括:

  • AOSP 拨号器(包/应用程序/拨号器)
  • 桌面时钟(包/应用程序/DeskClock)
  • LatinIME(包/输入方法/LatinIME)*
  • 设置应用程序(包/应用程序/设置)*
  • SystemUI(框架/基础/包/SystemUI)*

* 使用defaultToDeviceProtectedStorage清单属性的系统应用程序

通过在 AOSP 源代码树的 frameworks 或 packages 目录中运行命令mangrep directBootAware可以找到更多具有加密意识的应用程序和服务示例。

依赖项

为了安全地使用 FBE 的 AOSP 实现,设备需要满足以下依赖关系:

  • 内核支持Ext4 加密或 F2FS 加密。
  • HAL 版本 1.0 或 2.0 的Keymaster 支持。不支持 Keymaster 0.3,因为它不提供必要的功能或确保对加密密钥的充分保护。
  • Keymaster/ Keystore和 Gatekeeper必须在可信执行环境(TEE) 中实施,以便为 DE 密钥提供保护,以便未经授权的操作系统(闪存到设备上的自定义操作系统)不能简单地请求 DE 密钥。
  • 需要绑定到 keymaster 初始化的硬件信任根验证启动,以确保未经授权的操作系统无法访问设备加密凭据。

注意:存储策略适用于文件夹及其所有子文件夹。制造商应将未加密的内容限制在 OTA 文件夹和保存系统解密密钥的文件夹中。大多数内容应驻留在凭证加密存储中,而不是设备加密存储中。

执行

首先,根据Direct Boot开发者文档,闹钟、电话、辅助功能等应用程序应设为 android:directBootAware。

内核支持

对 Ext4 和 F2FS 加密的内核支持在 Android 通用内核 3.18 及更高版本中可用。要在 5.1 或更高版本的内核中启用它,请使用:

CONFIG_FS_ENCRYPTION=y

对于较旧的内核,如果设备的用户数据文件系统是 Ext4,则使用CONFIG_EXT4_ENCRYPTION=y ,如果设备的userdata数据文件系统是userdata ,则使用CONFIG_F2FS_FS_ENCRYPTION=y

如果您的设备将支持可采用的存储或将在内部存储上使用元数据加密,还请启用元数据加密所需的内核配置选项,如元数据加密文档中所述。

除了对 Ext4 或 F2FS 加密的功能支持外,设备制造商还应启用加密加速以加速基于文件的加密并改善用户体验。例如,在基于 ARM64 的设备上,可以通过设置以下内核配置选项来启用 ARMv8 CE(加密扩展)加速:

CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
CONFIG_CRYPTO_SHA2_ARM64_CE=y

为了进一步提高性能并降低功耗,设备制造商还可以考虑实施内联加密硬件,该硬件在数据进出存储设备的途中对数据进行加密/解密。 Android 通用内核(4.14 及更高版本)包含一个框架,当硬件和供应商驱动程序支持可用时,该框架允许使用内联加密。可以通过设置以下内核配置选项来启用内联加密框架:

CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_FS_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y

如果您的设备使用基于 UFS 的存储,请同时启用:

CONFIG_SCSI_UFS_CRYPTO=y

如果您的设备使用基于 eMMC 的存储,请同时启用:

CONFIG_MMC_CRYPTO=y

启用基于文件的加密

在设备上启用 FBE 需要在内部存储 ( userdata ) 上启用它。这也会在可采用的存储上自动启用 FBE;但是,如有必要,可采用存储上的加密格式可能会被覆盖。

内部存储器

通过将选项fileencryption=contents_encryption_mode[:filenames_encryption_mode[:flags]]添加到userdatafstab行的fs_mgr_flags列来启用 FBE。此选项定义内部存储的加密格式。它最多包含三个以冒号分隔的参数:

  • contents_encryption_mode参数定义了用于加密文件内容的加密算法。它可以是aes-256-xtsadiantum 。从 Android 11 开始,它也可以留空以指定默认算法,即aes-256-xts
  • filenames_encryption_mode参数定义用于加密文件名的加密算法。它可以是aes-256-ctsaes-256-hehadiantumaes-256-hctr2 。如果未指定,则默认为aes-256-cts如果contents_encryption_modeaes-256-xtsadiantum如果contents_encryption_modeadiantum
  • Android 11 中新增的flags参数是由+字符分隔的标志列表。支持以下标志:
    • v1标志选择版本 1 加密策略; v2标志选择版本 2 加密策略。第 2 版加密策略使用更安全、更灵活的密钥派生功能。如果设备在 Android 11 或更高版本上启动(由ro.product.first_api_level确定),则默认值为 v2,如果设备在 Android 10 或更低版本上启动,则默认值为 v1。
    • inlinecrypt_optimized标志选择一种加密格式,该格式针对不能有效处理大量密钥的内联加密硬件进行了优化。它通过每个 CE 或 DE 密钥仅派生一个文件内容加密密钥来实现这一点,而不是每个文件一个。 IVs(初始化向量)的生成会相应调整。
    • emmc_optimized标志类似于inlinecrypt_optimized ,但它还选择了一种将 IV 限制为 32 位的 IV 生成方法。此标志应仅用于符合 JEDEC eMMC v5.2 规范并因此仅支持 32 位 IV 的内联加密硬件。在其他内联加密硬件上,请改用inlinecrypt_optimized 。这个标志永远不应该用在基于 UFS 的存储上; UFS 规范允许使用 64 位 IV。
    • 在支持硬件封装密钥的设备上, wrappedkey_v0标志允许将硬件封装密钥用于 FBE。这只能与inlinecrypt挂载选项以及inlinecrypt_optimizedemmc_optimized标志结合使用。

如果您不使用内联加密硬件,大多数设备的推荐设置是fileencryption=aes-256-xts 。如果您使用内联加密硬件,大多数设备的推荐设置是fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized (或等效fileencryption=::inlinecrypt_optimized )。在没有任何形式的 AES 加速的设备上,可以通过设置fileencryption=adiantum来使用Adiantum代替 AES。

自 Android 14(AOSP 实验性)以来,AES-HCTR2 是具有加速加密指令的设备的首选文件名加密模式。但是,只有较新的 Android 内核支持 AES-HCTR2。在未来的 Android 版本中,它计划成为文件名加密的默认模式。如果您的内核支持 AES-HCTR2,则可以通过将filenames_encryption_mode设置为aes-256-hctr2来启用文件名加密。在最简单的情况下,这将通过fileencryption=aes-256-xts:aes-256-hctr2

在搭载 Android 10 或更低版本的设备上,也接受fileencryption=ice来指定使用FSCRYPT_MODE_PRIVATE文件内容加密模式。 Android 通用内核未实现此模式,但可以由供应商使用自定义内核补丁来实现。此模式生成的磁盘格式是特定于供应商的。在搭载 Android 11 或更高版本的设备上,不再允许使用此模式,必须改用标准加密格式。

默认情况下,文件内容加密是使用 Linux 内核的加密 API 完成的。如果您想改用内联加密硬件,还要添加inlinecrypt挂载选项。例如,完整的fstab行可能如下所示:

/dev/block/by-name/userdata /data f2fs nodev,noatime,nosuid,errors=panic,inlinecrypt wait,fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized

可采用的存储

从 Android 9 开始,FBE 和可采用的存储可以一起使用。

userdata指定fileencryption fstab 选项还会在可采用的存储上自动启用 FBE 和元数据加密。但是,您可以通过在PRODUCT_PROPERTY_OVERRIDES中设置属性来覆盖可采用存储上的 FBE 和/或元数据加密格式。

在搭载 Android 11 或更高版本的设备上,使用以下属性:

  • ro.crypto.volume.options (Android 11 中的新功能)在可采用的存储上选择 FBE 加密格式。它与fileencryption fstab 选项的参数具有相同的语法,并且使用相同的默认值。有关在此处使用的内容,请参阅上面的fileencryption建议。
  • ro.crypto.volume.metadata.encryption选择可采用存储上的元数据加密格式。请参阅元数据加密文档

在搭载 Android 10 或更低版本的设备上,使用以下属性:

  • ro.crypto.volume.contents_mode选择内容加密模式。这相当于ro.crypto.volume.options的第一个冒号分隔的字段。
  • ro.crypto.volume.filenames_mode选择文件名加密模式。这等效于ro.crypto.volume.options的第二个以冒号分隔的字段,但搭载 Android 10 或更低版本的设备上的默认值为aes-256-heh 。在大多数设备上,这需要显式覆盖为aes-256-cts
  • ro.crypto.fde_algorithmro.crypto.fde_sector_size选择可采用存储上的元数据加密格式。请参阅元数据加密文档

与 Keymaster 集成

密钥的生成和内核密钥环的管理由vold处理。 FBE 的 AOSP 实现要求设备支持 Keymaster HAL 1.0 或更高版本。不支持早期版本的 Keymaster HAL。

首次启动时,会在启动过程的早期生成并安装用户 0 的密钥。当initon-post-fs阶段完成时,Keymaster 必须准备好处理请求。在 Pixel 设备上,这是通过一个脚本块来处理的,确保 Keymaster 在挂载/data之前启动。

加密策略

基于文件的加密在目录级别应用加密策略。首次创建设备的用户数据分区时, userdata脚本init应用基本结构和策略。这些脚本将触发创建第一个用户(用户 0)的 CE 和 DE 密钥,并定义哪些目录将使用这些密钥进行加密。当创建其他用户和配置文件时,会生成必要的附加密钥并将其存储在密钥库中;他们的凭证和设备存储位置被创建,加密策略将这些密钥链接到这些目录。

在 Android 11 及更高版本中,加密策略不再硬编码到集中位置,而是由 init 脚本中mkdir命令的参数定义。使用系统 DE 密钥加密的目录使用encryption=Require ,而未加密的目录(或其子目录使用每个用户密钥加密的目录)使用encryption=None

在 Android 10 中,加密策略被硬编码到这个位置:

/system/extras/libfscrypt/fscrypt_init_extensions.cpp

在 Android 9 及更早版本中,该位置为:

/system/extras/ext4_utils/ext4_crypt_init_extensions.cpp

可以添加例外以防止某些目录被加密。如果进行了此类修改,则设备制造商应包含SELinux 策略,仅授予对需要使用未加密目录的应用程序的访问权限。这应该排除所有不受信任的应用程序。

唯一已知的可接受的用例是支持旧版 OTA 功能。

在系统应用程序中支持直接启动

使应用程序具有 Direct Boot 意识

为了方便系统应用程序的快速迁移,可以在应用程序级别设置两个新属性。 defaultToDeviceProtectedStorage属性仅适用于系统应用。 directBootAware属性可供所有人使用。

<application
    android:directBootAware="true"
    android:defaultToDeviceProtectedStorage="true">

应用程序级别的directBootAware属性是用于将应用程序中的所有组件标记为加密感知的简写。

defaultToDeviceProtectedStorage属性将默认应用存储位置重定向到指向 DE 存储,而不是指向 CE 存储。使用此标志的系统应用程序必须仔细审核存储在默认位置的所有数据,并更改敏感数据的路径以使用 CE 存储。使用此选项的设备制造商应仔细检查他们存储的数据,以确保其中不包含个人信息。

在此模式下运行时,以下系统 API 可用于在需要时显式管理由 CE 存储支持的上下文,这相当于其受设备保护的对应项。

  • Context.createCredentialProtectedStorageContext()
  • Context.isCredentialProtectedStorage()

支持多用户

多用户环境中的每个用户都会获得一个单独的加密密钥。每个用户都有两个密钥:一个 DE 和一个 CE 密钥。用户 0 必须先登录设备,因为它是一个特殊用户。这与设备管理使用有关。

加密感知应用程序以这种方式在用户之间进行交互: INTERACT_ACROSS_USERSINTERACT_ACROSS_USERS_FULL允许应用程序在设备上的所有用户之间进行操作。但是,这些应用程序将只能访问已解锁用户的 CE 加密目录。

一个应用程序可能能够跨 DE 区域自由交互,但一个用户解锁并不意味着设备上的所有用户都解锁。应用程序应在尝试访问这些区域之前检查此状态。

每个工作资料用户 ID 还获得两个密钥:DE 和 CE。当工作挑战得到满足时,配置文件用户被解锁并且 Keymaster(在 TEE 中)可以提供配置文件的 TEE 密钥。

处理更新

恢复分区无法访问用户数据分区上受 DE 保护的存储。强烈建议实现 FBE 的设备支持使用A/B 系统更新的OTA。由于可以在正常操作期间应用 OTA,因此无需恢复即可访问加密驱动器上的数据。

使用传统 OTA 解决方案时,需要恢复才能访问userdata分区上的 OTA 文件:

  1. userdata分区中创建一个顶级目录(例如misc_ne )。
  2. 将此顶级目录添加到加密策略例外(请参阅上面的加密策略)。
  3. 在顶级目录中创建一个目录来保存 OTA 包。
  4. 添加 SELinux 规则和文件上下文以控制对该文件夹及其内容的访问。只有接收 OTA 更新的进程或应用程序才能读取和写入此文件夹。其他应用程序或进程不应有权访问此文件夹。

验证

为确保实现的功能版本按预期工作,首先运行许多 CTS 加密测试,例如DirectBootHostTestEncryptionTest

如果设备运行的是 Android 11 或更高版本,还请运行vts_kernel_encryption_test

atest vts_kernel_encryption_test

或者:

vts-tradefed run vts -m vts_kernel_encryption_test

此外,设备制造商可能会执行以下手动测试。在启用 FBE 的设备上:

  • 检查ro.crypto.state存在
    • 确保ro.crypto.state已加密
  • 检查ro.crypto.type存在
    • 确保ro.crypto.type设置为file

此外,测试人员可以使用在主用户上设置的锁屏来启动userdebug实例。然后adb shell 进入设备并使用su成为 root。确保/data/data包含加密的文件名;如果没有,则有问题。

还鼓励设备制造商探索在其设备或内核上运行fscrypt 的上游 Linux 测试。这些测试是 xfstests 文件系统测试套件的一部分。但是,Android 不正式支持这些上游测试。

AOSP 实施细节

本节提供有关 AOSP 实施的详细信息,并描述基于文件的加密的工作原理。设备制造商无需在此处进行任何更改即可在其设备上使用 FBE 和直接启动。

fscrypt 加密

AOSP 实现在内核中使用“fscrypt”加密(由 ext4 和 f2fs 支持),通常配置为:

  • 在 XTS 模式下使用 AES-256 加密文件内容
  • 在 CBC-CTS 模式下使用 AES-256 加密文件名

还支持Adiantum 加密。启用 Adiantum 加密后,文件内容和文件名都使用 Adiantum 加密。

有关 fscrypt 的更多信息,请参阅上游内核文档

密钥派生

基于文件的加密密钥是 512 位密钥,由 TEE 中保存的另一个密钥(256 位 AES-GCM 密钥)加密存储。要使用此 TEE 密钥,必须满足三个要求:

  • 授权令牌
  • 延伸的凭证
  • “可丢弃的哈希”

身份验证令牌是用户成功登录时由Gatekeeper生成的加密身份验证令牌。除非提供正确的身份验证令牌,否则 TEE 将拒绝使用该密钥。如果用户没有凭证,则不需要使用授权令牌。

拉伸凭证是使用scrypt算法加盐拉伸后的用户凭证。在传递给vold以传递给scrypt之前,凭据实际上在锁定设置服务中被散列一次。这以加密方式绑定到 TEE 中的密钥,并具有适用于KM_TAG_APPLICATION_ID的所有保证。如果用户没有凭证,则不使用也不需要扩展凭证。

secdiscardable hash是随机 16 KB 文件的 512 位散列,与用于重建密钥的其他信息(例如种子)一起存储。该文件在删除密钥时被安全删除,或者以新的方式加密;这种额外的保护确保攻击者必须恢复这个安全删除的文件的每一位以恢复密钥。这以加密方式绑定到 TEE 中的密钥,并具有适用于KM_TAG_APPLICATION_ID的所有保证。

在大多数情况下,FBE 密钥还在内核中经过额外的密钥派生步骤,以生成实际用于进行加密的子密钥,例如每个文件或每个模式的密钥。对于版本 2 加密策略,使用 HKDF-SHA512。