用户数据加密是移动设备的一个重要特性,是使用对称加密算法对Android设备上的所有用户数据进行编码的过程,以防止用户数据被未经授权的用户或应用程序访问。
1.1.描述
AndroidAOSPhttps://cs.android.com/android/platform/superproject
Linux AOSP https://elixir.bootlin.com/linux/v5.15.111/source
谷歌值得信赖
https://github.com/haitao52198/TrustyOS/tree/master/AndroidTrustyOS
1.3.缩写
2、用户隐私数据保护计划
2.1.全盘加密FDE
Full-Disk Encryption,全盘加密,Android 5.0到Android 9.0支持,是使用密钥对Android设备上的所有用户数据进行编码的过程(密钥本身也会被加密)。当设备加密时,所有用户创建的数据在保存到磁盘之前都会自动加密,所有读取操作在将数据返回给调用者之前都会自动解密。
从Google对FDE的描述我们可以知道,在系统启动过程中,会随机生成用户数据分区加密密钥DEK(Disk Encryption Key),用户还需要输入Credentials来加密和保护DEK。使用时,首先要求用户输入Credentials并解密DEK,然后操作系统就可以使用DEK来解密userdata分区上的数据。所谓用户凭证,是指在开机过程中,在锁屏界面之前,操作系统会提供一个单独的UI供用户输入密码。
从Google关于创建DEK的描述可以看出,系统启动时会生成一个16字节的随机数作为DEK,并根据HBK和用户密钥创建一个KEK(Key Encryption Key)。使用KEK作为输入密钥,并使用AES_CBC算法对DEK进行加密。
虽然全盘加密FDE可以保护整个userdata分区,但在启动时,用户必须提供Credentials才能访问userdata分区。这意味着在用户提供Credentials之前系统无法访问用户数据,导致闹钟、无障碍服务等无法使用,即使运行,手机也无法接听电话,因此全盘加密FDE逐渐被替换为文件加密FBE。
2.2.文件加密FBE
基于文件的加密基于文件加密。由于Android将userdata分区格式化为F2FS类型的文件系统,因此也可以理解为基于F2FS类型系统的加密。
Android 7.0 及更高版本支持FBE。文件级加密允许使用不同的密钥对不同的文件进行加密,同时允许对加密的文件进行单独解密。支持文件级加密的设备支持直接启动。启用该功能后,加密设备启动后可直接进入锁屏,方便用户快速使用Android系统的闹钟和无障碍服务。这些系统服务主要包括:
总而言之,系统服务可以在用户解锁之前使用,同时用户的隐私数据也可以得到保护。
2.3.元数据加密ME
Android 9 在存在硬件支持的情况下引入了对元数据加密的支持。通过元数据加密,启动时出现的单个密钥可以加密FBE 未加密的任何内容,包括目录布局、文件大小、权限和创建/修改时间。此密钥受Keymaster 保护,而Keymaster 受启动时验证功能保护。
3.FBE关键框架
3.1. FBE TOP 硬件架构
Android FBE 功能依赖于UFS 和TEE。如果芯片支持高安全子系统,也取决于高安全子系统。
TEE或高安全子系统基于硬件环境提供KMS(密钥管理服务)。该服务提供密钥操作,如密钥生成(Key Generation)、密钥派生(Key Derivation)、密钥编程(KeyProgramming)等。
UFS包括UFS Core和UFS Device。 UFS 控制器工作在UFS Core 内部,用于接收来自AP 的数据和命令。
3.2. FBE TOP 软件架构
在不考虑平台高安全子系统的情况下,整体FBE框架可以从用户空间-内核空间、REE-TEE等多个维度进行划分。
3.3. FBE设计思路
FBE 将userdata 分区分为四个区域:Uncrypted Storage、System DE Storage、User DE Storage 和User CE Storage :
不同的存储使用不同的密钥。其中,System DE Storage对应SYSTEM_DE_KEY,User DE Storage对应USER_DE_KEY,User CE Storage对应USER_CE_KEY。
3.4.挂载文件fstab
下图是Android AOSP的挂载文件device/linaro/dragonboard/fstab.common:
文件加密
格式“fileencryption=contents_encryption_mode[:filenames_encryption_mode[:flags]]”包含最多3 个参数,以英文冒号分隔。
内容_加密_模式
用于加密文件内容的算法。可选值为“aes-256-xts”和“adiantum”。从Android 11 开始,默认加密算法允许留空,即“aes-256-xts”。
文件名_加密_模式
加密文件名算法,可选值为'aes-256-cts'、'aes-256-heh'和'adiantum'。如果未指定,当“contents_encryption_mode”为“aes-256-xts”时,该参数默认为“aes-256-cts”。如果“contents_encryption_mode”为“adiantum”,则此参数默认为“adiantum”。
v1 v2 标志
v2是第二版本的加密策略,第二版本的加密策略采用了更加安全、灵活的密钥导出函数。如果设备运行的是Android 11 或更高版本,则默认选择版本2;如果设备运行的是Android 10 或更低版本,则默认选择版本1。
内联加密优化
一种针对无法有效处理大量密钥的内联加密硬件进行优化的加密格式。对于每个CE 或DE 密钥,仅导出一个文件内容加密密钥,而不是为每个文件导出一个文件内容加密密钥,并且初始向量IV 生成会相应调整。
emmc_优化
与inlinecrypt_optimized 类似,初始化向量IV 限制为32 位。该标签仅用于符合JEDEC eMMC v5.2 规范的内联加密硬件,因此仅支持32 位IV。在其他内联加密硬件上,使用inlinecrypt_optimized。该标志不得在基于UFS 的存储设备上使用(UFS 规范允许使用64 位IV)。
wrappedkey_v0
在支持嵌入式加密硬件的设备上,允许使用硬件封装密钥进行FBE。该标志只能与inlinecrypt 挂载选项和标志inlinecrypt_optimized 或标志emmc_optimized 结合使用。
4. VOLD对密钥的处理
VOLD子系统对密钥的处理可以分为四个步骤,即“挂载用户数据分区”、“检索或生成密钥”、“将密钥安装到Linux内核密钥环”和“加密策略”。
4.1.挂载用户数据分区
Init进程是Android系统启动的第一个进程。它调用mount_all 命令来挂载userdata 分区。该命令在system/core/init/builtins.cpp中实现,对应函数do_mount_all。该命令读取并解析fstab挂载文件,并在挂载userdata分区后发送事件。
4.2.检索或生成密钥
Init进程是Android系统启动的第一个进程。与mount的过程类似,调用installkey命令来创建或提取FBE Class Key。该命令实现在system/core/init/builtins.cpp中,对应函数do_installkey:
该函数首先判断是否是文件加密方式。如果是,则执行vdc命令,正式进入加密流程。
/system/bin/vdc进程将cryptfs等参数发送给VOLD,最后调用fscrypt_initialize_systemwide_keys函数,该函数是VOLD子系统处理密钥的入口函数。
首先,调用get_data_file_encryption_options读取并解析挂载的文件fstab,获取加密模式、加密算法、加密标志等。其次,函数retrieveOrGenerateKey的处理可以分为两种场景:系统首次启动和非首次启动启动。系统第一次启动时,FBE Class Key(encrypted_key)和Keymaster_key(KEK)以KeyBlob的形式放置在userdata分区中。系统非首次启动时,从userdata分区中提取FBE Class Key和Keymaster_key对应的KeyBlob到TEEOS的Keymaster TA中进行解密。
4.2.1.解析挂载的文件fstab
函数ParseOptionsForApiLevel读取并解析挂载的文件fstab,并填充EncryptionOptions结构体:
4.2.2、检索或生成密钥
系统第一次启动时,FBE Class Key(encrypted_key)和Keymaster_key(KEK)以KeyBlob的形式放置在userdata分区中。系统非首次启动时,从userdata分区中提取FBE Class Key和Keymaster_key对应的KeyBlob到TEEOS的Keymaster TA进行解密。
4.3.将密钥安装到Linux 内核密钥环中
将FBE Class Key安装到Linux Kernel Keyring的入口函数是install_storage_key:
VOLD 子系统向Linux 内核密钥环发出IOCTL 命令FS_IOC_ADD_ENCRYPTION_KEY,并返回长度为128 位的FBE 类密钥标识符:
函数fscrypt_ioctl_add_key首先从User Space的VOLD子系统接收参数。其次,可以分为系统首次启动和非首次启动两种场景。当系统第一次启动时,加密的FBE 类密钥保存在Linux 内核密钥环中。当系统不是第一次启动时,从Linux Kernel Keyring中提取加密的FBE Class Key,并将FBE Class Key Identifier最终返回给VOLD子系统。这里,使用fscrypt_key_specifier结构描述返回的Key Identifier :
4.4.加密策略
4.4.1、加密策略概述
Android FBE加密策略与mkdir命令参数'加密'的配置有关:
'加密=需要'
强制设置并验证目录加密策略,必须严格匹配。
“加密=无”
未设置或验证目录加密策略,即目录不需要加密。
“加密=尝试”
尝试设置/验证目录加密策略。即使设置/验证失败,也不会进行任何处理。
'加密=DeleteNecessary'
尝试设置/验证目录加密策略。如果设置/验证失败,请清除目录并重新强制设置和验证。
4.4.2.设置加密策略
Init进程是Android系统启动的第一个进程。它调用mkdir 命令创建目录并设置加密策略。该命令在system/core/init/builtins.cpp中实现,对应函数do_mkdir。
最后调用函数EnsurePolicy设置目录:的加密策略
从挂载的文件fstab可以看出,Android FBE选择的是V2加密策略。接下来,初始化文件内容加密模式、文件名加密模式、加密标志和密钥标识符(Key Identifier)。
VOLD子系统使用结构体fscrypt_policy_v2来描述加密策略:
5.Linux内核对密钥的处理
5.1. FBE Class Key 的内核处理框架
fscrypt 是一个Linux 文件系统加密管理工具,用于管理元数据、密钥生成、密钥打包和PAM 集成,并为创建和修改加密目录提供统一的接口。 fscrypt 内核部分集成到ext4 等文件系统中。
blk-mq是Linux块设备层多队列机制。它将Linux Kernel存储堆栈中请求层的单个队列更改为多个队列,以提高性能。如果blk-mq 支持内联加密,它可以将加密上下文传递到存储堆栈。 Linux 内核源代码: 的提交对此进行了解释
这段话的含义是,必须有某种方式让存储设备驱动程序知道应该用于加密/解密请求的加密上下文,并且上层(例如Filesystem 或Fscrypt)知道情况并管理加密语境。当上层向块层提交BIO,并且BIO最终到达支持内联加密的设备驱动程序时,设备驱动程序已经指示了BIO加密上下文。具体改回代码就是在struct bio中添加结构体struct bio_crypt_ctx来表示加密上下文,并引入各种函数来操作bio_crypt_ctx并使bio/request合并逻辑感知到bio_crypt_ctx。
Fscrypt 从内核密钥环中提取FBE 类密钥。
F2FS 将Wrapped key 和Encryption Policy 保存在加密上下文中。
KSM 负责管理ICE Keyslot 并维护Keyslot 状态机。
TEEOS Keymaster TA 负责在ICE Keyslot 上执行Program 和Evict 操作。
5.2、Fscrypt
下面一段是Linux Kernel对fscrypt :的描述
Fscrypt 是一个允许文件系统支持文件和目录透明加密的库。 fscrypt 在文件系统级别而不是块级别运行,这允许它使用不同的密钥加密不同的文件,并在同一文件系统上拥有未加密的文件。需要注意的是,fscrypt 不会加密除Filename 之外的文件系统元数据。
这个函数的处理逻辑并不复杂。首先,它从VOLD子系统获取加密策略,并将加密策略保存到目录/文件的inode中。保存之前会先比较是否已设置加密策略。如果是,则判断两个设置是否一致。如果不一致就会报错。
5.3. F2FS 文件系统
F2FS,FlashFriendly File System,是专为NAND存储设备设计的新型开源闪存文件系统。它专门设计用于对NAND 闪存存储介质友好。
F2FS将整个卷划分为大量的Segment,每个Segment的大小固定为2MB。几个连续的Segment形成一个Section,多个连续的Section形成一个Zone。 F2FS文件系统将整个卷分为6个区域。除Superblock(SB)外,每个区域都包含多个Segment。其结构如下图:
5.3.1.段
连续的块被收集成段。一个段的大小是512 个块(2MB)。每个Segment都有一个Segment Summary Block元数据结构,它描述了Segment中每个Block的所有者(该块所属的文件以及文件内的块偏移量)。 Segment Summary主要用于标识在执行Cleaning操作时需要将Block中的哪些数据转移到新的位置,以及转移后如何更新Block的索引信息。一个Block可以完整存储512个Block的摘要信息,每个Block还有额外的1位空间用于其他用途。
5.3.2、超级块
F2FS的f2fs_super_block存储在设备的第二个块中,仅包含只读数据,称为超级块。文件系统一旦创建,SB信息就不会改变。 SB描述了文件系统有多大,Segment有多大,Section有多大,Zone有多大,分配给每个部分的“元数据”区域有多少空间,以及其他小量。的详细信息。 SB位于文件系统分区的开头,有两个备份,以避免文件系统崩溃时无法恢复。它包含基本分区信息和默认的F2FS 参数。
5.3.3、主要区域
主区域充满了4KB 块。这些块可以分配给文件的数据或文件的节点。是F2FS文件系统的主要数据存储区域。
5.4、KSM
KeySlot Manager,键槽管理器,以下是KSM :的Linux Kernel说明
可以看出,KSM是Linux内核用来维护ICE(Inline Crypto Engine)内部keyslot硬件密钥槽的状态机,由结构体blk_keyslot_manager :描述
这个结构体的重点是成员struct blk_ksm_ll_ops ksm_ll_ops,它定义了ICE Keyslot的操作函数集。成员函数keyslot_program用于对Keyslot进行Program操作,成员函数keyslot_evict用于对Keyslot进行Evict操作。
5.4.1、keyslot_program
以keyslot_program回调函数cqhci_crypto_keyslot_program@drivers/mmc/host/cqhci-crypto.c为例说明如何对ICE Keyslot进行Program操作,芯片平台厂商可以自定义。
该函数在空闲状态下将参数key指向的加密上下文编程到keyslot中,并将编程成功的keyslot索引保存到参数槽中。这样就实现了“密钥可用但不可见”,即密钥存储在ICE硬件Keyslot中,软件只能获取保存密钥的keyslot索引。
5.4.2、keyslot_evict
以keyslot_evict回调函数cqhci_crypto_keyslot_program@drivers/mmc/host/cqhci-crypto.c为例说明如何对ICE Keyslot进行evict操作,芯片平台厂商可以自定义。
根据参数key指向的加密上下文,获取ICE硬件中的keyslot索引,并请求TEEOS Keymaster TA根据keyslot索引对ICE硬件内部keyslot进行逐出操作。这样就实现了“密钥可用但不可见”,即密钥存储在ICE硬件Keyslot中,软件只能根据密钥keyslot索引进行evict操作。
6. TEEOS 密钥处理
注:使用Google Trusty分析TEEOS对AES对称密钥的处理流程。
6.1.值得信赖的TEE 架构
Google Trusty 是一个安全操作系统,为Android 提供可信执行环境(TEE)。 Trusty OS 和Android OS 运行在同一处理器上,通过硬件和软件与系统其他部分隔离,Trusty 和Android 并行运行。 Trusty 可以访问设备主处理器和内存的全部功能,但完全隔离。隔离可保护Trusty 免受用户安装的恶意应用程序以及Android 中可能发现的潜在漏洞的影响。
在运行时,Trusty 应用程序作为Trusty 内核下的隔离进程以非特权模式运行。每个进程都利用TEE 处理器的内存管理单元功能在自己的虚拟内存沙箱中运行。
6.2.值得信赖的Keymaster 架构
Android Keystore API 和Keymaster HAL 提供了一组加密原语,允许使用访问控制、硬件支持的密钥来实现协议。 Keymaster HAL 是OEM 提供的动态可加载库,由Keystore 服务用来提供硬件支持的加密服务。为了确保安全,HAL实现不会在用户空间甚至内核空间执行任何敏感操作。敏感操作被委托给通过某些内核接口到达的TEEOS。整体框架如下图:
在Android设备中,Keymaster HAL的客户端包括App、框架和KeyStore守护进程。其目的不是实现安全敏感算法,而是编排和安排发送到TEEOS 的请求。真正实现安全敏感计算的是位于TEEOS的Keymaster。 TA。下图是Google对Keymaster架构:的描述
6.3.钥匙大师功能
以下是Google对Keymaster功能:的定义
可见Keymaster的强大。回到FBE密钥框架领域,FBE密钥派生依赖于Keymaster TA的密钥生成功能,该功能与密钥特征、目的、客户端绑定、信任根绑定和版本绑定等多个因素有关。
6.3.1、主要特性
无论是FBE Class密钥还是加密FBE Class密钥的KEK,都使用AES对称算法。以下是Keymaster :支持的AES对称算法类型的说明
因此,在请求Keymaster派生密钥时,需要提供密钥特征:
6.3.2、主要目的
系统第一次启动时,需要创建FBE Class key和KEK,并以Keyblob的形式存储在userdata分区中。在这种场景下,需要使用Keymaster加密功能。系统非首次启动时,从userdata分区中提取Keyblob,获取FBE Class key和KEK。这种场景下,就需要使用Keymaster解密功能。因此,向Keymaster发送请求时,需要指定密钥目的:
6.3.3、客户端绑定
Keymaster生成的密钥需要绑定对应的应用程序。绑定参数为APP_ID 或ADD_DATA:
6.3.4、信任根绑定
下图是Google对信任根:的描述
6.3.5、版本绑定
下图是Google对版本绑定:的描述
6.4. FBE 密钥层次结构
下图是Android FBE密钥系统:
在密钥导出系统中,主要包含‘FileCo
ntens Encryption Key"、"FileName Encryption Key"和"Key Identifier"。 Linux Kernel KSM模块提供回调函数可以使用blk_crypto_ll_ops::keyslot_program将FileContents Encryption Key编程到ICE硬件Keyslot内,使用blk_crypto_ll_ops::derive_sw_secret进行密钥派生。 6.5、Keymaster派生FBE Class key 该函数处理逻辑并不复杂,最终FBE Class key以Keyblob形式落盘到userdata partition。 七、Inline Crypto Engine 基于软件的加密解决方案使用CPU来执行加密和解密任务,虽然这种方法提供了相当多的性能,但由于需要不断提高存储速度,因此存在不足。为了客服性能下降,JEDEC等标准机构向主机控制器内添加基于硬件的内联加密功能。内联意味着硬件加密引擎位于主机控制器内部,并动态加密和解密数据。使用内联硬件加密引擎处理大量安全数据。 就Android设备而言,内联加密引擎ICE位于UFS内部。当AP从DDR写数据到UFS Device时,需要对数据流进行加密。当AP从UFS Device读数据到DDR时,需要对数据流进行解密。下图是包含AES加解密引擎的UFS Controller内部逻辑框图: 八、总结 希望读者可以通过这篇文档对Android文件加密FBE有整体认识,受限于篇幅,更受限于芯片厂商专利等诸多因素,很多技术细节和方案无法更详细展开,希望在后续文章中能够结合开源方案和代码可以更深入剖析FBE技术细节,如Linux Kernel Keyring、Fscrypt、文件IO等。 参考资料 Full Disk Encryption https://source.android.com/docs/security/features/encryption/full-disk File-Based Encryption https://source.android.com/docs/security/features/encryption/file-based Metadata Encryption https://source.android.com/docs/security/features/encryption/metadata Hardware-Wrapped Keys https://source.android.com/docs/security/features/encryption/hw-wrapped-keys Android AOSP https://cs.android.com/android/platform/superproject Linux AOSP https://elixir.bootlin.com/linux/v5.15.111/source Google Trusty https://source.android.com/docs/security/features/trusty Google Keystore https://source.android.com/docs/security/features/keystore Google Trusty Code https://github.com/haitao52198/TrustyOS/tree/master/AndroidTrustyOS
用户评论
终于找到关于FBE密钥框架详细讲解的文章了!我一直想知道android手机如何保护数据加密的关键,看了这篇文章简直豁然开朗,原来是这么复杂的操作背后才能保证我们的隐私安全!
有5位网友表示赞同!
讲得太专业了,作为一个安卓新手,完全看不懂…不过文章写的很清晰,可以感受到作者对FBE技术非常透彻的理解。
有8位网友表示赞同!
这段时间的新闻经常看到关于手机安全问题,这篇文章正好解答了我很多疑问。原来还有这种强大的加密技术在保护着我们的数据!
有16位网友表示赞同!
学习了学习了!虽然FBE密钥框架和技术很复杂,但是作者介绍的很深入,读完以后对Android系统的安全机制有了更深的认识。希望以后能有更多类似的文章分享!
有13位网友表示赞同!
手机里的数据越来越重要了,但我也一直担心隐私泄露的问题。感谢作者这篇文章的讲解,让我了解到Android系统是如何保护数据的!
有10位网友表示赞同!
文章写的太好了!我之前一直在琢磨着安卓系统的安全机制是什么样的,终于找到了答案! FBE密钥框架的确很强大,能够有效地保护用户数据免遭恶意攻击。
有8位网友表示赞同!
说实话,这种技术细节我有点看不懂... 我更关心的是如何在日常生活中更好地保护手机安全。 文章可以再详细一些用户的实用指南吗?例如如何设置强大的密码、注意哪些常用的安全问题等等...
有13位网友表示赞同!
对Android系统安全很感兴趣一直想了解FBE密钥框架,这篇文章讲解得很详细,技术层面的分析也很到位,受益匪浅!
有6位网友表示赞同!
看了这个介绍才知道,原来手机安全不仅仅是单单的指纹或者密码就能保证的哦!FBE密钥框架的功能真的很厉害啊。以后要更加注意数据安全问题了。
有5位网友表示赞同!
我一直觉得安卓系统的安全性在过去几年里有了很大的提升,这篇文章让我更加清楚地认识到,FBE密钥框架就是其中重要的技术保障!
有9位网友表示赞同!
作为一名程序员,对Android系统安全技术一直非常关注。 这篇分析FBE密钥框架的文章很实用,能够帮助我更好地理解安卓系统的安全机制。
有14位网友表示赞同!
文章内容过于理论性强,缺乏一些实际案例的佐证和讲解,对于普通用户来说还是不太容易理解。
有14位网友表示赞同!
希望作者以后可以加入一些其他Android系统的安全技术介绍,比如基于容器的安全机制等。这样多角度的分析才能更加全面地了解安卓系统安全现状。
有16位网友表示赞同!
FBE密钥框架虽然很先进,但是它也存在一些局限性。例如:攻击者可以通过其他手段绕过FBE保护,所以不能完全依赖于它来保证数据安全。
有9位网友表示赞同!
Android系统不断发展,未来FBE的应用范围肯定会更广,技术的细节也会更加复杂。期待作者后续文章能带来更多深度解读!
有11位网友表示赞同!
说实话,对安卓系统的安全性一直不太放心。看了这篇文章感觉还是很有保障的,特别是FBE密钥框架这个功能,让我对手机数据安全有了更多的信心!
有13位网友表示赞同!
技术细节讲解很棒,可惜图文并茂一点能更有效地传达技术要点,这样更容易让人理解。
有6位网友表示赞同!