android全磁盘加密
什么是全磁盘加密?
全磁盘加密是使用一个密钥来为android设备上所有的用户数据加密的过程。一旦设备被加密,所有的用户创建的数据都将会在提交的磁盘之前自动加密,在读取之前都会自动解密。
Android 5.0中添加了啥创建了快速加密,该加密方式仅仅加密在数据分区中使用块设备的数据来避免第一次启动耗费较长时间。仅仅ext4和f2fs文件系统支持快速加密。
在首次启动的时候添加forceencrypt标志来加密增加了对模式的支持和没有密码的加密增加使用可信执行环境的密钥的硬件支持存储。
注意:升级到Android5.0并且被加密的设备可能会数据恢复出厂后返回一个未加密状态。在首次启动时加密的新的Android 5.0设备不能返回到未加密状态。
Android全磁盘加密是如何工作的
Android全磁盘加密基于dm-crypy,他是一个内核特征,工作在块设备层。出于这个原因,加密是和嵌入式多媒体卡和作为块设备的闪存设备一起工作的。在YAFFS文件系统中,加密是不可能工作的,他是直接和NAND闪存芯片工作的。
加密算法是带有CBC和 ESSIV:SHA256的128高级加密标准。主键是通过128位AES通过OpenSSL库被加密的。你必须要使用128位或更大位数的键值。
注意:OEMs能够使用128位或更高位数来加密主键。
在Android5.0的发行版中,有四种加密状态:
默认PIN密码模式在第一次启动的时候,设备创建一个随机生成的128位主键,然后使用默认密码和存储的salt进行哈希运算。默认密码是”default_password”。然而,结果散列也需要通过TEE进行签名,他使用一个签名的散列来加密主键。
你可以在Android源码文件cryptfs.c中找到默认密码。
当用户在设备中设置了PIN或者是密码,仅仅128位的键被重新加密和存储。(用户PIN/密码/模式的改变不会造成用户数据重新加密)。注意管理的设备可能会受到PIN,模式或密码的限制。
加密是由init和vold管理的。init调用vold,vold设置位于init中的属性来触发事件。系统的其他部分也会根据这些属性来进行工作,例如报告状态,查询密码,或者是发生致命错误的时候及时工厂重置。为了在vold中激活加密特征,系统使用命令行工具vdc’s cryptfs运行命令: checkpw, restart, enablecrypto, changepw, cryptocomplete, verifypw,setfield, getfield, mountdefaultencrypted, getpwtype, getpw, 和clearpw.
为了进行加密,解密或清除/data,/data必须要被挂载。然而,为了能够显示用户接口,框架一定要运行并且框架需要/data来运行。为了解决这个难题,在/data中会挂载一个临时的文件系统。这使得安卓能够提示密码,显示进展,或在需要的时候进行数据擦除。在从临时文件系统到真实的/data文件系统的转换的时候强加了一些限制,系统必须要停止打开临时文件系统中文件的每一个进程,然后在真实的/data文件系统中重启这些进程。为了这样做,所有的服务都必须在这三个组中的一个中:core,main和late_start。
core:在启动后永远不关闭main:在磁盘密码输入后关机在重启late_restart:在/data被解密并且挂载之前不要开始为了激发这些行为,vold.decrypt属性被设置为各种字符串。为了杀死并且重启服务,init命令为:
class_reset:停止服务,并且允许使用class_start进行重启。class_start:重启服务class_stop:停止一个服务,并且添加一个SVC_DISABLED标志。停止的服务不向class_start做出回应。流对于一个加密的设备来说有四个流。一个设备仅仅加密一次,然后遵循一个正常的启动流。
加密一个原先未加密的设备:使用forceencrypt加密一个新的设备:在首次启动的时候强制性加密(在Android L开始)加密一个存在的设备:用户初始化加密(Android K并且更早)启动一个加密设备:启动一个不带密码的加密设备:启动一个没有设置密码的加密设备(相关的设备运Android 5.0或更新)开始一个带有密码的加密设备:启动一个设置密码的加密设备。除了这些流,设备加密/data就会失败。每一个流在下面都会详细解释。
加密一个带有/forceencrypt新设备这是一个Android 5.0设备正常的首次启动。
检测到带有/forceencrypt标志的未加密文件系统
/data没有被加密,但是必须要进行加密。因为 /forceencrypt委托他这样做。卸载/data
开始加密/data
vold.decrypt = "trigger_encryption" triggers init.rc, which will cause vold to encrypt /data with no password. (None is set because this should be a new device.)
挂载tmpfsvold挂载一个临时文件系统 /data(从ro.crypto.tmpfs_options中使用tmpfs选项),并且设置属性vold.encrypt_progress 为0.vold为启动一个加密的系统准备tmpfs /data,并且设置属性vold.decrypt为trigger_restart_min_framework
提出框架,显示进度因为该设备几乎没有数据去加密了,进度条也不会显示了,因为加密过程会很快。
当/data被加密之后,卸下框架vold设置vold.decrypt为 开始defaultcrypto 服务的trigger_default_encryption。(这个会开始下面的流用于挂载一个默认的加密用户数据)。trigger_default_encryption检查加密类型来查看/data是否是带有密码被加密的。因为Android5.0设备在首次启动的时候被加密,应该没有密码设置;因此我们解密并且挂载/data。
挂载/datainit然后使用从ro.crypto.tmpfs_options中选出的参数在tmpfs的RAMDisk 中挂载/data,ro.crypto.tmpfs_options是在init.rc中被设置的。
启动框架设置vold为trigger_restart_framework,他继续常规的启动进程。
加密一个现在的设备
这种情况发生在你加密一个未加密的Android k或更早版本的设备,该设备被一直到Android L的时候。注意,这个和在K中使用的流是一样的。
这个进程是用户初始化的,并且在代码中被引用作为”就地加密”。当一个空户选择去加密一个设备的时候,UI确保电量是完全充电状态并且AC适配器被插入,所以有足够的变量来完成加密进程。
警告:如果设备在完成加密之前耗尽电量并且关机了,在部分加密状态下会留下文件数据。设备必须要工厂重置,所有的数据都会丢失。
为了使能就地加密,vold开始一个循环来读取真实块设备的每一个扇区,然后将他写到加密块设备中。vold在读取和写数据之前,检查扇区是否正在使用,这会使得在几乎没有数据的新设备上加密会很快。
设备状态:设置ro.crypto.state = "unencrypted" 并且运行 on nonencrypted init触发器来继续启动。
检查密码UI在passwd是用户锁屏密码的地方调用带有命令cryptfs enablecrypto inplace的vold。
卸载框架vold检查错误,如果不能被加密,返回-1,并且在日志中打印原因。如果能够加密,设置属性 vold.decrypt为trigger_shutdown_framework。这会使init.rc停止位于类late_start和main中的服务。
卸载/datavold卸载/mnt/sdcard,然后卸载/data。
开始加密/datavold然后设置加密映射,该映射创建一个虚拟加密块设备,该设备映射到真实的块设备上,但是当写入的时候加密每一个扇区,当读取的时候解密每一个扇区。vold然后创建和编写加密元数据。
当加密的时候,挂载tmpfsvold挂载一个tmpfs /data(从ro.crypto.tmpfs_options中使用tmpfs选项),并且设置属性vold.encrypt_progress为0.vold为启动一个加密系统准备tmpfs /data,并且设置属性vold.decrypt为trigger_restart_min_framework。
提出框架,显示进度trigger_restart_min_framework会使init.rc开始一个服务的main类。当框架看到vold.encrypt_progress被设置为0,他就会显示进度条UI,他每5秒钟查询一下属性然后更新进度条。每次他加密了一部分分区,加密程序就会更新 vold.encrypt_progress。
当/data被加密,重启当/data被成功加密了,vold会清除位于元数据中的标志ENCRYPTION_IN_PROGRESS,然后重启。
如果某些原因重启失败,vold会设置属性 vold.encrypt_progress为 error_reboot_failed,并且UI应该会展示一个信息询问用户按下按钮重启。这种情况永远也不期望发生。
开启一个带有默认加密的加密设备这种情况发生在当你想启动一个没有密码的加密设备的时候。因为Android 5.0设备在首次启动的时候被加密,应该没有设置密码,因此应该是默认加密状态。
检测加密的没有密码的/data检测Android设备已被加密,因为/data不能被挂载,并且标志flagsencryptable 或forceencrypt 之一被设置了。vold设置 vold.decrypt为
trigger_default_encryption,他用于启动defaultcrypto 。trigger_default_encryption 检查加密类型来查看/data有无密码加密。
解密/data在块设备中,创建dm-crypt设备,所以设备已经可以使用。
挂载/datavold挂载加密的/data分区,然后准备一个新的分区。他设置属性vold.post_fs_data_done 为0,并且设置vold.decrypt为trigger_post_fs_data. 这使得 init.rc运行他的post-fs-data命令。他们会创建必要的目录和链接,然后设置vold.post_fs_data_done为1.
一旦vold在那个属性中看到1,他设置属性vold.decrypt为 trigger_restart_framework。这会使得init.rc再次启动位于类main中的服务。然后自从启动后,第一次开启位于类late_start中的服务。
开启框架