声明
- 最近工作上涉及到对Android系统安全性的改造,在改造之前先分析整理下目前Android系统自身的安全性;
- 参考了一些文章及书籍,在这里大部分是对别人描述的提炼,我挑出一些对我有用的内容整理;
- 本文使用的代码是LineageOS的cm-14.1,对应Android 7.1.2,可以参考我的另一篇博客:如何下载Nexus5的LineageOS14.1(cm-14.1)系统源码并编译、刷机
1 加密/data分区
Android系统目前采用的加密机制为dm-crypt机制,其架构如下图所示:
Android系统也有“全盘加密”这个概念,但是严格来说这个全盘指的是/data分区。相对于加密整个Flash存储,只加密/data分区更具有现实意义,因为/system分区中并不会存储任何敏感数据,而对/system也加密的话,其中大量可执行文件执行前会因解密操作使系统性能受到拖累。
/data分区的加密密钥不能放在手机里,而是需要在系统启动时,通过与用户进行交互,根据用户的屏幕解锁密码推导出/data分区的加密密钥。这就需要对Android系统的启动流程以及init和vold之间的交互操作进行修改。Android 6 时为dm-crypt机制增加了“adoptable storage”特性,它使用户能进一步把Android的文件系统加密功能用在扩展存储(USB存储设备)上。
1.1 关于dm-crypt机制
Android中使用的这一解决方案也是一个Linux的通用解决方案,那么有几个问题:
- dm-crypt解决方案中用来加密/data分区的秘钥从何而来呢?
dm-crypt解决方案需要一个主密钥,在设备第一次启动时会随机生成这个128位的主密钥,此主密钥会被一个默认口令“default password”加密,再外加一个会被存储下来的salt。当用户设置/修改他们的PIN码/口令/图形锁时,系统会利用这个PIN码/口令/图形锁重新对主密钥进行加密。
- 这样的方式安全吗?
dm-crypt 使用的主密钥实质上就是用用户的PIN 码/口令/图形锁加密的,如果用户设置的PIN码/口令太简单的话攻击者可以反复调用vold自身代码中的cryptfs_check+passwd()函数就能逐个验证所有可能的口令【此函数会在mount文件系统之前,用用户提供的口令进行解密操作,检查dm-crypt尾部的数据是否正确,这样就能判断出用户提供的口令是不是正确口令了】。
- 加入TEE的配合
为了增加这种攻击的难度,Android还将设备可信执行环境(TEE,Trusted Execution Environment)整合了进来,会有一个存储在TEE中的次级密钥,参与到对主密钥的加密和解密的过程中。
1.2 加解密对系统性能的影响
加密必然需要更多的CPU 时间去完成解密和重新加密数据的操作,这一定会影响系统的性能,而且也更加耗电。不过在各种因素的作用下,总的来说,加密对系统性能的影响应该说是在微不足道到的:
- 尽管加/解密函数会把每次访问所需的时间再拖慢上几微秒,但是存储设备读写速度相对于CPU慢了了太多,这几微秒其实不算什么。
- Linux 内核己经使用缓存对访问做了优化:Linux 内核己经用过缓存存储设备上的数据的方式,优化了数据访问方式。因为dm-crypt显示为一个块设备,它位于缓存层的下方,所以,数据只需要解密一次,然后所有对该数据进行的读/写操作,就直接对缓存中(已经解密出来〉的数据进行就可以了。只有当数据需要刷回到下方的设备中去时,它才会被再次加密回去,然后再写回到更底层的物理闪存设备中去。
- 对/data分区的访问并不像对/system分区的访问那样频繁:Linux 系统对存储着A ndroid的各种框架和静态配置信息的/system分区的访问是非常频繁的。相对而言,对/data分区的访问就少多了,只有在要加载某个App或者偶尔在某些“运行时配置信息”需要变更时,才会要访问/data分区。
2 基于文件的加密
基于文件系统的加密有一个弱点,一旦设备被解锁,文件系统被mount上来,以设备上所运行的代码来说,加密是不存在的,恶意的APP依然能够访问用户敏感数据。所以 Android 7.0进一步采用了基于文件的加密技术,此模式下会给每个文件都分配一个必须用用户的passcode推导出来的密钥,通过使用Linux内核中的EXT4_FS_ENCRYPTION特性,再辅以Keymaster 和硬件(TrustZone)的支持,特定的文件在屏幕被锁定之后,直到用户下一次解锁屏幕这期间就不能访问了。
3 系统启动各阶段的验证过程
系统启动过程中有一条信任链,从ROM到Boot Loader,再到内核和root文件系统(也就是boot分区)。
。。。以后涉及到了再分析。。。