我在这里引用《 Android手册》,但是:
注意:
我使用的来源与棉花糖并不直接相关,但与棒棒糖及更高版本有关。
TL:DR
我现在就解决OP的问题。技术细节将在后面介绍。
默认加密密钥来自硬件源(类似于TPM芯片)和定义为AOSP的预设密码default_password
中cryptfs.c
的源文件,见下文。
是的,不仅是默认密码,而且所有密码都被设置为密钥,并存储在类似TPM的芯片上,称为TEE(“受信任的执行环境”的缩写,更多详细信息,请参见下文)。
通过UART / JTAG访问设备SoC芯片的黑客可以从技术上访问TEE密钥,或者自定义内核可以将该信息泄漏给黑客。一些阴谋论中的三字母代理机构可能可以与OEM合作,以将这些不安全的内核用于生产设备,但我不会为此而设很多商店。同样,请参见此答案的最后一节以获取更多详细信息。
阻止黑客访问密钥的唯一方法就是要做大量的工作。
- 实际上,默认情况下,在Lollipop上及以上(由JellyBean 4.3起可用)对固件(由Google 称为“验证启动”)的哈希(校验和)进行检查(实际上是在Lollipop上及以上)
dm-verity
。但是,这与加密状态无关。
来源: AOSP安全指南这里。
- 关于使用自定义密码解密系统所涉及的过程,请参见下文。我仅在此告诉您,密码的创建和使用都涉及用户密码。
总览
首次启动时,设备会创建一个随机生成的128位主密钥,然后使用默认密码和存储的盐对其进行哈希处理。默认密码为:“ default_password”但是,生成的哈希也通过TEE(例如TrustZone)进行签名,TEE使用签名的哈希来加密主密钥。
您可以在Android开放源代码项目cryptfs.c中找到定义的默认密码文件中。
当用户在设备上设置PIN /密码时,仅128位密钥被重新加密和存储。(即,用户PIN /通过/模式更改不会引起对用户数据分区的重新加密。)
使用默认加密启动加密设备
当您启动没有密码的加密设备时,就会发生这种情况。由于Android 5.0设备在首次启动时已加密,因此不应设置密码,因此这是默认的加密状态。
- 检测没有密码的加密/数据
检测到Android设备已加密,因为/ data无法挂载,并且其中一个标志encryptable
或forceencrypt
设置之一。
vold
设置vold.decrypt
为trigger_default_encryption
,将启动defaultcrypto
服务。trigger_default_encryption
检查加密类型以查看/ data是否使用密码进行了加密。
- 解密/数据
dm-crypt
在块设备上创建设备,以便可以使用该设备。
- 挂载/数据
vold
然后挂载解密的真实/ 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为开机以来的第一次。
- 启动框架
现在,框架使用解密的/ data引导所有服务,并且系统可以使用了。
启动没有默认加密的加密设备
这是当您启动具有设置密码的加密设备时发生的情况。设备的密码可以是大头针,图案或密码。
- 使用密码检测加密的设备
检测到Android设备已加密,因为该标志 ro.crypto.state = "encrypted"
vold
设置vold.decrypt
为,trigger_restart_min_framework
因为/ data使用密码加密。
- 挂载tmpfs
init
设置五个属性,以保存从/传递给/ data的初始安装选项init.rc
。vold
使用以下属性来设置加密映射:
ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags
(ASCII 8位十六进制数字,后跟0x)
- 启动框架以提示输入密码
框架启动,并看到将其vold.decrypt
设置为trigger_restart_min_framework
。这告诉框架它正在启动tmpfs /data
磁盘上并且需要获取用户密码。
但是,首先,需要确保磁盘已正确加密。它将命令发送cryptfs cryptocomplete
到vold
。vold
如果加密成功完成,则返回0;如果内部错误,则返回-1;如果加密未成功完成,则返回-2。vold
通过在加密元数据中查找CRYPTO_ENCRYPTION_IN_PROGRESS
标志。如果已设置,则加密过程被中断,并且设备上没有可用的数据。
如果vold
返回错误,则UI应向用户显示一条消息,以重新引导设备并将其恢复出厂设置,并为用户提供一个按此操作的按钮。
- 用密码解密数据
一旦cryptfs cryptocomplete
成功,该框架显示UI要求磁盘密码。所述UI检查通过发送该命令的密码cryptfs checkpw
来vold
。如果密码正确(这是通过/data
在一个临时位置成功安装解密的文件,然后再卸载来确定的),则vold将解密的块设备的名称保存在属性中ro.crypto.fs_crypto_blkdev
,并向UI返回状态0。如果密码不正确,它将返回-1。
- 停止框架
UI放置了一个加密启动图形,然后使用命令调用vold cryptfs restart
。vold
将属性设置vold.decrypt
为trigger_reset_main
,从而导致init.rc
这样做class_reset main
。这将停止main
该类中的所有服务,从而允许将tmpfs /data
其卸载。
- 挂载/数据
vold
然后挂载解密后的真实/data
分区并准备新分区(如果使用“擦除”选项加密了该分区,则该分区可能从未准备过,这在第一个发行版中不支持)。它将属性设置vold.post_fs_data_done
为0
,然后设置vold.decrypt
为trigger_post_fs_data
。这导致init.rc
运行它post-fs-data commands
。他们将创建任何必要的目录或链接,然后将其设置vold.post_fs_data_done
为1
。一旦在该属性中vold
看到1
,便将该属性设置vold.decrypt
为trigger_restart_framework
。这将导致init.rc
再次启动类服务,main
并且late_start
自启动以来首次启动类服务。
- 开始完整的框架
现在,该框架使用解密的/ data文件系统引导所有服务,并且该系统可以使用。
存储加密密钥
加密的密钥存储在加密元数据中。硬件支持是通过使用受信任的执行环境(TEE)签名功能来实现的。以前,我们使用通过应用scrypt
到用户的密码和存储的盐生成的密钥来加密主密钥。
为了使密钥对现成的攻击具有弹性,我们通过使用存储的TEE密钥对生成的密钥进行签名来扩展此算法。然后,通过再次应用,将生成的签名转换为适当的长度密钥scrypt
。然后,此密钥用于加密和解密主密钥。要存储此密钥:
- 生成随机的16字节磁盘加密密钥(DEK)和16字节盐。
- 应用于
scrypt
用户密码和盐,以生成32字节的中间密钥1(IK1)。
- 用零字节填充IK1,以达到硬件绑定私钥(HBK)的大小。具体来说,我们填充为:00 || IK1 || 00..00; 一个零字节,32个IK1字节,223个零字节。
- 用HBK对填充的IK1进行签名,以生成256字节的IK2。
- 将其
scrypt
应用于IK2和盐(与第2步相同的盐)以产生32字节的IK3。
- IK3的前16个字节用作KEK,后16个字节用作IV。
- 使用AES_CBC,密钥KEK和初始化向量IV加密DEK。