引入文件级加密 (FBE) 和新 API 后,便可以将应用设为加密感知型应用,这样一来,它们将能够在受限环境中运行。这些应用将可以在用户提供凭据之前运行,同时系统仍能保护私密用户信息。
在启用了 FBE 的设备上,每位用户均有两个可供应用使用的存储位置:
凭据加密 (CE) 存储空间:这是默认存储位置,只有在用户解锁设备后才可用。
设备加密 (DE) 存储空间:在直接启动模式期间以及用户解锁设备后均可用。
这种区分能够使工作资料更加安全,因为这样一来,加密不再只基于启动时密码,从而能够同时保护多位用户。
Direct Boot API 允许加密感知型应用访问上述每个区域。应用生命周期会发生一些变化,以便在用户的 CE 存储空间因用户在锁定屏幕上首次输入凭据而解锁时,或者在工作资料提供工作挑战时,通知应用。无论是否实现了 FBE,运行 Android 7.0 的设备都必须要支持这些新的 API 和生命周期。不过,如果没有 FBE,DE 和 CE 存储空间将始终处于解锁状态。
首次创建设备的 userdata 分区时,会由 init 脚本应用基本结构和政策。这些脚本将触发创建首位用户(用户 0)的 CE 密钥和 DE 密钥,并定义要使用这些密钥加密哪些目录。创建其他用户和资料时,会生成必要的其他密钥并将其存储在密钥代码库中;接下来会创建它们的凭据和设备存储位 置,并且加密政策会将这些密钥关联到相应目录。
DE密钥
触发 late-init action
// 开机执行init.cpp,int main(int argc, char** argv) {
......
// 解析 init.rc file
Parser& parser = Parser::GetInstance();
parser.ParseConfig("/init.rc");
// Don't mount filesystems or start core system services in charger mode.std::string bootmode = property_get("ro.bootmode");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
// 触发 late-init action
am.QueueEventTrigger("late-init");
}
......
}
这个方法定义在文件 system/core/init/init.cpp 中。
触发 post-fs-data
on late-init
.....
trigger post-fs
# Now we can mount /data. File encryption requires keymaster to decrypt# /data, which in turn can only be loaded when system properties are present
trigger post-fs-data
.....
这个 action 定义在文件 system/core/rootdir/init.rc 中。
执行 installkey 命令
on post-fs-data
chown system system /data
chmod 0771 /data
# Make sure we have the device encryption key.
start vold
#执行 installkey 命令
installkey /data
int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
.....
} elseif (subcommand == "init_user0") {
if (!check_argc(cli, subcommand, argc, 2, "")) return0;
//执行函数 e4crypt_init_user0()return sendGenericOkFailOnBool(cli, e4crypt_init_user0());
.....
}
这个方法定义在文件 system/vold/CryptCommandListener.cpp 中。
函数 e4crypt_init_user0() 定义如下
bool e4crypt_init_user0() {
LOG(DEBUG) << "e4crypt_init_user0";
if (e4crypt_is_native()) {
// user_key_dir 等于 data/misc/vold/user_keysif (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) returnfalse;
if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) returnfalse;
if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) returnfalse;
if (!path_exists(get_de_key_path(0))) {
//创建和安装 CD keys, user 为 0, 即开机默认的 userif (!create_and_install_user_keys(0, false)) returnfalse;
}
// TODO: switch to loading only DE_0 here once framework makes// explicit calls to install DE keys for secondary usersif (!load_all_de_keys()) returnfalse;
}
// We can only safely prepare DE storage here, since CE keys are probably// entangled with user credentials. The framework will always prepare CE// storage once CE keys are installed.if (!e4crypt_prepare_user_storage(nullptr, 0, 0, FLAG_STORAGE_DE)) {
LOG(ERROR) << "Failed to prepare user 0 storage";
returnfalse;
}
// If this is a non-FBE device that recently left an emulated mode,// restore user data directories to known-good state.if (!e4crypt_is_native() && !e4crypt_is_emulated()) {
e4crypt_unlock_user_key(0, 0, "!", "!");
}
returntrue;
}
这个方法定义在文件 system/vold/Ext4Crypt.cpp 中。
函数 create_and_install_user_keys() 定义如下
staticbool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
std::string de_key, ce_key;
//创建 DE 密钥if (!random_key(&de_key)) returnfalse;
//创建 CE 密钥if (!random_key(&ce_key)) returnfalse;
.....
std::string de_raw_ref;
// 存储 DE 密钥到密钥代码库if (!install_key(de_key, &de_raw_ref)) returnfalse;
s_de_key_raw_refs[user_id] = de_raw_ref;
std::string ce_raw_ref;
// 存储 CE 密钥到密钥代码库if (!install_key(ce_key, &ce_raw_ref)) returnfalse;
s_ce_keys[user_id] = ce_key;
s_ce_key_raw_refs[user_id] = ce_raw_ref;
LOG(DEBUG) << "Created keys for user " << user_id;
returntrue;
}
这个方法定义在文件 system/vold/Ext4Crypt.cpp 中。
再看看密钥的真正生成过程 random_key()
staticbool random_key(std::string* key) {
// 读取随机密钥if (android::vold::ReadRandomBytes(EXT4_AES_256_XTS_KEY_SIZE, *key) != 0) {
// TODO status_t plays badly with PLOG, fix it.
LOG(ERROR) << "Random read failed";
returnfalse;
}
returntrue;
}
mkdir /data/system_de 0770 system system
on post-fs-data
mkdir /data/system_ce 0770 system system
mkdir /data/misc_de 01771 system misc
mkdir /data/misc_ce 01771 system misc
//用户数据路径
mkdir /data/user 0711 system system
// 用户 DE 空间
mkdir /data/user_de 0711 system system
// /data/data 连接到目录 /data/user/0// /data/user 和 /data/data 都是 CE 空间
symlink /data/data /data/user/0
publicvoidsystemReady(final Runnable goingCallback) {
.....
synchronized (this) {
// Only start up encryption-aware persistent apps; once user is// unlocked we'll come back around and start unaware apps//启动 persistent app,注意参数 PackageManager.MATCH_DIRECT_BOOT_AWARE
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
}
.....