android fbe分析,(原创)Android FBE加密源码分析(二)
上一篇最后讲到,dispatchCommand是通过调用runCommand来执行具体的CMD操作,这一篇会接着说明。在进行说明前,需要先了解FBE的一些内容,为什么需要这些内容呢?因为在接下来的分析会涉及到CE、DE的存储位置,所以需要先了解。
全盘加密和文件级加密的区别
借助文件级加密,Android 7.0 中引入了一项称为直接启动的新功能。该功能处于启用状态时,已加密设备在启动后将直接进入锁定屏幕。之前,在使用全盘加密 (FDE) 的已加密设备上,用户在访问任何数据之前都需要先提供凭据,从而导致手机无法执行除最基本操作之外的所有其他操作。例如,闹钟无法运行,无障碍服务不可用,手机无法接电话,而只能进行基本的紧急拨号操作。
文件级加密概述
引入文件级加密 (FBE) 和新 API 后,便可以将应用设为加密感知型应用,这样一来,它们将能够在受限环境中运行。这些应用将可以在用户提供凭据之前运行,同时系统仍能保护私密用户信息。
在启用了 FBE 的设备上,每位用户均有两个可供应用使用的存储位置:
凭据加密 (CE) 存储空间:这是默认存储位置,只有在用户解锁设备后才可用。
设备加密 (DE) 存储空间:在直接启动模式期间以及用户解锁设备后均可用。
这种区分能够使工作资料更加安全,因为这样一来,加密不再只基于启动时密码,从而能够同时保护多位用户。好了,这里就先了解这么多,如果需要更详细的分析大家可以看Android文档的描述或者找其他博客看看。
帅气分割线
根据虚函数和继承关系,最后调用的runCommand是CryptCommandListener::CryptfsCmd::runCommand,另外大家回想下,之前在client端传进来command是CMD=”PID cryptfs enablefilecrypto”,记住这个下面要对这个CMD进行解析了。
CryptCommandListener::CryptfsCmd::runCommand
int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
// 验证执行操作的进行的用户的权限
if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
return 0;
}
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing subcommand", false);
return 0;
}
int rc = 0;
std::string subcommand(argv[1]);
// 根据subcommand进行选择,这里是"enablefilecrypto",下面直接分析这个CMD
if (subcommand == "checkpw") {
if (!check_argc(cli, subcommand, argc, 3, "")) return 0;
dumpArgs(argc, argv, 2);
..................
} else if (subcommand == "enablefilecrypto") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
dumpArgs(argc, argv, -1);
// easy,什么都不做,调用e4crypt_initialize_global_de来完成
rc = e4crypt_initialize_global_de();
} else if (subcommand == "changepw") {
.................
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
intCryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
intargc,char**argv){
// 验证执行操作的进行的用户的权限
if((cli->getUid()!=0)&&(cli->getUid()!=AID_SYSTEM)){
cli->sendMsg(ResponseCode::CommandNoPermission,"No permission to run cryptfs commands",false);
return0;
}
if(argc<2){
cli->sendMsg(ResponseCode::CommandSyntaxError,"Missing subcommand",false);
return0;
}
intrc=0;
std::stringsubcommand(argv[1]);
// 根据subcommand进行选择,这里是"enablefilecrypto",下面直接分析这个CMD
if(subcommand=="checkpw"){
if(!check_argc(cli,subcommand,argc,3,""))return0;
dumpArgs(argc,argv,2);
..................
}elseif(subcommand=="enablefilecrypto"){
if(!check_argc(cli,subcommand,argc,2,""))return0;
dumpArgs(argc,argv,-1);
// easy,什么都不做,调用e4crypt_initialize_global_de来完成
rc=e4crypt_initialize_global_de();
}elseif(subcommand=="changepw"){
.................
runCommand –> e4crypt_initialize_global_de
bool e4crypt_initialize_global_de() {
LOG(INFO) << "e4crypt_initialize_global_de";
if (s_global_de_initialized) {
LOG(INFO) << "Already initialized";
return true;
}
/*
* 最后经过函数调用和赋值后
* contents_mode = "ice"
* filenames_mode = "aes-256-cts"
* mode_filename = /data/unencrypted/mode
*/
const char *contents_mode;
const char *filenames_mode;
cryptfs_get_file_encryption_modes(&contents_mode, &filenames_mode);
std::string modestring = std::string(contents_mode) + ":" + filenames_mode;
std::string mode_filename = std::string("/data") + e4crypt_key_mode;
if (!android::base::WriteStringToFile(modestring, mode_filename)) {
PLOG(ERROR) << "Cannot save type";
return false;
}
std::string device_key_ref;
// 调用retrieveAndInstallKey创建秘钥
if (!android::vold::retrieveAndInstallKey(true,
device_key_path, device_key_temp, &device_key_ref)) return false;
// 最后应用秘钥
std::string ref_filename = std::string("/data") + e4crypt_key_ref;
if (!android::base::WriteStringToFile(device_key_ref, ref_filename)) {
PLOG(ERROR) << "Cannot save key reference to:" << ref_filename;
return false;
}
LOG(INFO) << "Wrote system DE key reference to:" << ref_filename;
s_global_de_initialized = true;
return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
boole4crypt_initialize_global_de(){
LOG(INFO)<
if(s_global_de_initialized){
LOG(INFO)<
returntrue;
}
/*
* 最后经过函数调用和赋值后
* contents_mode = "ice"
* filenames_mode = "aes-256-cts"
* mode_filename = /data/unencrypted/mode
*/
constchar*contents_mode;
constchar*filenames_mode;
cryptfs_get_file_encryption_modes(&contents_mode,&filenames_mode);
std::stringmodestring=std::string(contents_mode)+":"+filenames_mode;
std::stringmode_filename=std::string("/data")+e4crypt_key_mode;
if(!android::base::WriteStringToFile(modestring,mode_filename)){
PLOG(ERROR)<
returnfalse;
}
std::stringdevice_key_ref;
// 调用retrieveAndInstallKey创建秘钥
if(!android::vold::retrieveAndInstallKey(true,
device_key_path,device_key_temp,&device_key_ref))returnfalse;
// 最后应用秘钥
std::stringref_filename=std::string("/data")+e4crypt_key_ref;
if(!android::base::WriteStringToFile(device_key_ref,ref_filename)){
PLOG(ERROR)<
returnfalse;
}
LOG(INFO)<
s_global_de_initialized=true;
returntrue;
}
e4crypt_initialize_global_de –> retrieveAndInstallKey
/*
* create_if_absent = true
* key_path = /data/unencrypted/key
* tmp_path = /data/unencrypted/tmp
*/
bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path,
const std::string& tmp_path, std::string* key_ref) {
KeyBuffer key;
// 路径已存在
if (pathExists(key_path)) {
LOG(DEBUG) << "Key exists, using: " << key_path;
if (!retrieveKey(key_path, kEmptyAuthentication, &key)) return false;
} else {
if (!create_if_absent) {
LOG(ERROR) << "No key found in " << key_path;
return false;
}
LOG(INFO) << "Creating new key in " << key_path;
// 创建DE秘钥
if (!randomKey(&key)) return false;
// 保存DE秘钥
if (!storeKeyAtomically(key_path, tmp_path,
kEmptyAuthentication, key)) return false;
}
// 存储秘钥到秘钥库中
if (!installKey(key, key_ref)) {
LOG(ERROR) << "Failed to install key in " << key_path;
return false;
}
return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
* create_if_absent = true
* key_path = /data/unencrypted/key
* tmp_path = /data/unencrypted/tmp
*/
boolretrieveAndInstallKey(boolcreate_if_absent,conststd::string&key_path,
conststd::string&tmp_path,std::string*key_ref){
KeyBufferkey;
// 路径已存在
if(pathExists(key_path)){
LOG(DEBUG)<
if(!retrieveKey(key_path,kEmptyAuthentication,&key))returnfalse;
}else{
if(!create_if_absent){
LOG(ERROR)<
returnfalse;
}
LOG(INFO)<
// 创建DE秘钥
if(!randomKey(&key))returnfalse;
// 保存DE秘钥
if(!storeKeyAtomically(key_path,tmp_path,
kEmptyAuthentication,key))returnfalse;
}
// 存储秘钥到秘钥库中
if(!installKey(key,key_ref)){
LOG(ERROR)<
returnfalse;
}
returntrue;
}
这样,DE key就创建完成了。至于installKey、retrieveKey之类的函数具体是怎么样产生key的留做以后学习分析。有兴趣的童鞋也可以自行看,这里就先不扩展讲解了。接下来看看CE key是如何生成的。
回到post-fs-data阶段
在post-fs-data阶段的最后部分,有一个init_user0的动作
on post-fs-data
.......
mkdir /data/cache/backup 0700 system system
init_user0
# Set SELinux security contexts on upgrade or policy update.
restorecon --recursive --skip-ce /data
.......
1
2
3
4
5
6
7
8
9
onpost-fs-data
.......
mkdir/data/cache/backup0700systemsystem
init_user0
# Set SELinux security contexts on upgrade or policy update.
restorecon--recursive--skip-ce/data
.......
这里init_user0对应的函数是do_init_user0
do_init_user0
static int do_init_user0(const std::vector<:string>& args) {
std::vector<:string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
"init_user0"};
return do_exec(exec_args);
}
1
2
3
4
5
staticintdo_init_user0(conststd::vector<:string>&args){
std::vector<:string>exec_args={"exec","/system/bin/vdc","--wait","cryptfs",
"init_user0"};
returndo_exec(exec_args);
}
看这个代码和上一篇博客中do_installKey的代码是类似的,最后也是通过vdc,传送init_user0进行最后的操作。调用启动过程这里就简略了,直接分析CryptCommandListener的runCommand是如何处理init_user0的。
CryptCommandListener::runCommand
int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
.................
rc = cryptfs_isConvertibleToFBE();
} else if (subcommand == "init_user0") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
// sendGenericOkFailOnBool会根据e4crypt_init_user0调用返回值给client端发送对应的信息
return sendGenericOkFailOnBool(cli, e4crypt_init_user0());
} else if (subcommand == "create_user_key") {
................
}
1
2
3
4
5
6
7
8
9
10
11
12
13
intCryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
intargc,char**argv){
.................
rc=cryptfs_isConvertibleToFBE();
}elseif(subcommand=="init_user0"){
if(!check_argc(cli,subcommand,argc,2,""))return0;
// sendGenericOkFailOnBool会根据e4crypt_init_user0调用返回值给client端发送对应的信息
returnsendGenericOkFailOnBool(cli,e4crypt_init_user0());
}elseif(subcommand=="create_user_key"){
................
}
runCommand –> e4crypt_init_user0
bool e4crypt_init_user0() {
LOG(DEBUG) << "e4crypt_init_user0";
if (e4crypt_is_native()) {
// 准备存储key的文件夹,user_key_dir = "/data/misc/vold/user_keys"
if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return false;
if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return false;
if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return false;
if (!android::vold::pathExists(get_de_key_path(0))) {
// 创建user0使用的key
if (!create_and_install_user_keys(0, false)) return false;
}
// 加载所有用户使用的DE key
if (!load_all_de_keys()) return false;
}
// 准备user的DE存储空间
if (!e4crypt_prepare_user_storage(nullptr, 0, 0, FLAG_STORAGE_DE)) {
LOG(ERROR) << "Failed to prepare user 0 storage";
return false;
}
// 不是用FBE就解锁
if (!e4crypt_is_native() && !e4crypt_is_emulated()) {
e4crypt_unlock_user_key(0, 0, "!", "!");
}
return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
boole4crypt_init_user0(){
LOG(DEBUG)<
if(e4crypt_is_native()){
// 准备存储key的文件夹,user_key_dir = "/data/misc/vold/user_keys"
if(!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(!android::vold::pathExists(get_de_key_path(0))){
// 创建user0使用的key
if(!create_and_install_user_keys(0,false))returnfalse;
}
// 加载所有用户使用的DE key
if(!load_all_de_keys())returnfalse;
}
// 准备user的DE存储空间
if(!e4crypt_prepare_user_storage(nullptr,0,0,FLAG_STORAGE_DE)){
LOG(ERROR)<
returnfalse;
}
// 不是用FBE就解锁
if(!e4crypt_is_native()&&!e4crypt_is_emulated()){
e4crypt_unlock_user_key(0,0,"!","!");
}
returntrue;
}
e4crypt_init_user0 –> create_and_install_user_keys
// NB this assumes that there is only one thread listening for crypt commands, because
// it creates keys in a fixed location.
static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
KeyBuffer de_key, ce_key;
// 产生CE和DE key
if (!android::vold::randomKey(&de_key)) return false;
if (!android::vold::randomKey(&ce_key)) return false;
// create_ephemeral为false
if (create_ephemeral) {
// If the key should be created as ephemeral, don't store it.
s_ephemeral_users.insert(user_id);
} else {
// 获取CE key保存的路径
auto const directory_path = get_ce_key_directory_path(user_id);
if (!prepare_dir(directory_path, 0700, AID_ROOT, AID_ROOT)) return false;
auto const paths = get_ce_key_paths(directory_path);
std::string ce_key_path;
// 获取CE key保存路径
if (!get_ce_key_new_path(directory_path, paths, &ce_key_path)) return false;
// 保存CE key
if (!android::vold::storeKeyAtomically(ce_key_path, user_key_temp,
kEmptyAuthentication, ce_key)) return false;
fixate_user_ce_key(directory_path, ce_key_path, paths);
// 保存DE key
if (!android::vold::storeKeyAtomically(get_de_key_path(user_id), user_key_temp,
kEmptyAuthentication, de_key)) return false;
}
std::string de_raw_ref;
// 存储DE key到秘钥库
if (!android::vold::installKey(de_key, &de_raw_ref)) return false;
s_de_key_raw_refs[user_id] = de_raw_ref;
std::string ce_raw_ref;
// 存储CE key到秘钥库
if (!android::vold::installKey(ce_key, &ce_raw_ref)) return false;
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;
return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// NB this assumes that there is only one thread listening for crypt commands, because
// it creates keys in a fixed location.
staticboolcreate_and_install_user_keys(userid_tuser_id,boolcreate_ephemeral){
KeyBufferde_key,ce_key;
// 产生CE和DE key
if(!android::vold::randomKey(&de_key))returnfalse;
if(!android::vold::randomKey(&ce_key))returnfalse;
// create_ephemeral为false
if(create_ephemeral){
// If the key should be created as ephemeral, don't store it.
s_ephemeral_users.insert(user_id);
}else{
// 获取CE key保存的路径
autoconstdirectory_path=get_ce_key_directory_path(user_id);
if(!prepare_dir(directory_path,0700,AID_ROOT,AID_ROOT))returnfalse;
autoconstpaths=get_ce_key_paths(directory_path);
std::stringce_key_path;
// 获取CE key保存路径
if(!get_ce_key_new_path(directory_path,paths,&ce_key_path))returnfalse;
// 保存CE key
if(!android::vold::storeKeyAtomically(ce_key_path,user_key_temp,
kEmptyAuthentication,ce_key))returnfalse;
fixate_user_ce_key(directory_path,ce_key_path,paths);
// 保存DE key
if(!android::vold::storeKeyAtomically(get_de_key_path(user_id),user_key_temp,
kEmptyAuthentication,de_key))returnfalse;
}
std::stringde_raw_ref;
// 存储DE key到秘钥库
if(!android::vold::installKey(de_key,&de_raw_ref))returnfalse;
s_de_key_raw_refs[user_id]=de_raw_ref;
std::stringce_raw_ref;
// 存储CE key到秘钥库
if(!android::vold::installKey(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)<
returntrue;
}
到这里,用户的DE和CE key都已经有了。问题是,在installKey的时候也已经产生过DE key了,这里为什么还需要再生成一次DE key呢?这里留个疑问,具体到时候还得看看,不过看回installKey部分的代码,猜测installkey生成的DE key应该是全局DE key,init_user0的DE key是用户DE key,所以是两组不同的key。
key已经有了,接下来就是使用key对文件进行加解密了。判断哪些文件需要进行加解密实在init.rc中通过mkdir的时候记性的,init.rc中mkdir动作,是通过do_mkdir函数进行的。
do_mkdir
static int do_mkdir(const std::vector<:string>& args) {
mode_t mode = 0755;
int ret;
...............
// 如果使用FBE
if (e4crypt_is_native()) {
// 设置文件目录加密规则
if (e4crypt_set_directory_policy(args[1].c_str())) {
// 设置失败需要进入recovery模式
const std::vector<:string> options = {
"--prompt_and_wipe_data",
"--reason=set_policy_failed:"s + args[1]};
reboot_into_recovery(options);
return 0;
}
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
staticintdo_mkdir(conststd::vector<:string>&args){
mode_tmode=0755;
intret;
...............
// 如果使用FBE
if(e4crypt_is_native()){
// 设置文件目录加密规则
if(e4crypt_set_directory_policy(args[1].c_str())){
// 设置失败需要进入recovery模式
conststd::vector<:string>options={
"--prompt_and_wipe_data",
"--reason=set_policy_failed:"s+args[1]};
reboot_into_recovery(options);
return0;
}
}
return0;
}
do_mkdir函数前面的代码基本就是判断参数,根据参数创建对应的文件夹,而对应加密规则的设置则是在最后面部分。我们只分析最后面部分即可。
do_mkdir –> e4crypt_set_directory_policy
int e4crypt_set_directory_policy(const char* dir)
{
// 判断是否在/data/路径
if (!dir || strncmp(dir, "/data/", 6)) {
return 0;
}
// Special-case /data/media/obb per b/64566063
if (strcmp(dir, "/data/media/obb") == 0) {
// Try to set policy on this directory, but if it is non-empty this may fail.
set_system_de_policy_on(dir);
return 0;
}
if (strchr(dir + 6, '/')) {
return 0;
}
// 不需要处理的文件夹集合,但是底下的文件夹还是会被加密
std::vector<:string> directories_to_exclude = {
"lost+found",
"system_ce", "system_de",
"misc_ce", "misc_de",
"media",
"data", "user", "user_de",
};
std::string prefix = "/data/";
for (auto d: directories_to_exclude) {
if ((prefix + d) == dir) {
LOG(INFO) << "Not setting policy on " << dir;
return 0;
}
}
// 对不在directories_to_exclude的文件夹进行处理
return set_system_de_policy_on(dir);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
inte4crypt_set_directory_policy(constchar*dir)
{
// 判断是否在/data/路径
if(!dir||strncmp(dir,"/data/",6)){
return0;
}
// Special-case /data/media/obb per b/64566063
if(strcmp(dir,"/data/media/obb")==0){
// Try to set policy on this directory, but if it is non-empty this may fail.
set_system_de_policy_on(dir);
return0;
}
if(strchr(dir+6,'/')){
return0;
}
// 不需要处理的文件夹集合,但是底下的文件夹还是会被加密
std::vector<:string>directories_to_exclude={
"lost+found",
"system_ce","system_de",
"misc_ce","misc_de",
"media",
"data","user","user_de",
};
std::stringprefix="/data/";
for(autod:directories_to_exclude){
if((prefix+d)==dir){
LOG(INFO)<
return0;
}
}
// 对不在directories_to_exclude的文件夹进行处理
returnset_system_de_policy_on(dir);
}
e4crypt_set_directory_policy —> set_system_de_policy_on
static int set_system_de_policy_on(char const* dir) {
// 秘钥引用,ref_filename=/data/unencrypted/ref
std::string ref_filename = std::string("/data") + e4crypt_key_ref;
std::string policy;
// 读取秘钥应用内容到policy
if (!android::base::ReadFileToString(ref_filename, &policy)) {
LOG(ERROR) << "Unable to read system policy to set on " << dir;
return -1;
}
// 获取加密模式
auto type_filename = std::string("/data") + e4crypt_key_mode;
std::string modestring;
if (!android::base::ReadFileToString(type_filename, &modestring)) {
LOG(ERROR) << "Cannot read mode";
}
std::vector<:string> modes = android::base::Split(modestring, ":");
if (modes.size() < 1 || modes.size() > 2) {
LOG(ERROR) << "Invalid encryption mode string: " << modestring;
return -1;
}
LOG(INFO) << "Setting policy on " << dir;
// 设置加密
int result = e4crypt_policy_ensure(dir, policy.c_str(), policy.length(),
modes[0].c_str(),
modes.size() >= 2 ?
modes[1].c_str() : "aes-256-cts");
if (result) {
LOG(ERROR) << android::base::StringPrintf(
"Setting %02x%02x%02x%02x policy on %s failed!",
policy[0], policy[1], policy[2], policy[3], dir);
return -1;
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
staticintset_system_de_policy_on(charconst*dir){
// 秘钥引用,ref_filename=/data/unencrypted/ref
std::stringref_filename=std::string("/data")+e4crypt_key_ref;
std::stringpolicy;
// 读取秘钥应用内容到policy
if(!android::base::ReadFileToString(ref_filename,&policy)){
LOG(ERROR)<
return-1;
}
// 获取加密模式
autotype_filename=std::string("/data")+e4crypt_key_mode;
std::stringmodestring;
if(!android::base::ReadFileToString(type_filename,&modestring)){
LOG(ERROR)<
}
std::vector<:string>modes=android::base::Split(modestring,":");
if(modes.size()<1||modes.size()>2){
LOG(ERROR)<
return-1;
}
LOG(INFO)<
// 设置加密
intresult=e4crypt_policy_ensure(dir,policy.c_str(),policy.length(),
modes[0].c_str(),
modes.size()>=2?
modes[1].c_str():"aes-256-cts");
if(result){
LOG(ERROR)<<:base::stringprintf>
"Setting %02x%02x%02x%02x policy on %s failed!",
policy[0],policy[1],policy[2],policy[3],dir);
return-1;
}
return0;
}
set_system_de_policy_on —> e4crypt_policy_ensure
int e4crypt_policy_ensure(const char *directory, const char *policy,
size_t policy_length,
const char *contents_encryption_mode,
const char *filenames_encryption_mode) {
int contents_mode = 0;
int filenames_mode = 0;
if (!strcmp(contents_encryption_mode, "software") ||
!strcmp(contents_encryption_mode, "aes-256-xts")) {
contents_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
} else if (!strcmp(contents_encryption_mode, "ice")) {
contents_mode = EXT4_ENCRYPTION_MODE_PRIVATE;
} else {
LOG(ERROR) << "Invalid file contents encryption mode: "
<< contents_encryption_mode;
return -1;
}
if (!strcmp(filenames_encryption_mode, "aes-256-cts")) {
filenames_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
} else if (!strcmp(filenames_encryption_mode, "aes-256-heh")) {
filenames_mode = EXT4_ENCRYPTION_MODE_AES_256_HEH;
} else {
LOG(ERROR) << "Invalid file names encryption mode: "
<< filenames_encryption_mode;
return -1;
}
bool is_empty;
if (!is_dir_empty(directory, &is_empty)) return -1;
if (is_empty) {
// 设置加密
if (!e4crypt_policy_set(directory, policy, policy_length,
contents_mode, filenames_mode)) return -1;
} else {
if (!e4crypt_policy_check(directory, policy, policy_length,
contents_mode, filenames_mode)) return -1;
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
inte4crypt_policy_ensure(constchar*directory,constchar*policy,
size_tpolicy_length,
constchar*contents_encryption_mode,
constchar*filenames_encryption_mode){
intcontents_mode=0;
intfilenames_mode=0;
if(!strcmp(contents_encryption_mode,"software")||
!strcmp(contents_encryption_mode,"aes-256-xts")){
contents_mode=EXT4_ENCRYPTION_MODE_AES_256_XTS;
}elseif(!strcmp(contents_encryption_mode,"ice")){
contents_mode=EXT4_ENCRYPTION_MODE_PRIVATE;
}else{
LOG(ERROR)<
<
return-1;
}
if(!strcmp(filenames_encryption_mode,"aes-256-cts")){
filenames_mode=EXT4_ENCRYPTION_MODE_AES_256_CTS;
}elseif(!strcmp(filenames_encryption_mode,"aes-256-heh")){
filenames_mode=EXT4_ENCRYPTION_MODE_AES_256_HEH;
}else{
LOG(ERROR)<
<
return-1;
}
boolis_empty;
if(!is_dir_empty(directory,&is_empty))return-1;
if(is_empty){
// 设置加密
if(!e4crypt_policy_set(directory,policy,policy_length,
contents_mode,filenames_mode))return-1;
}else{
if(!e4crypt_policy_check(directory,policy,policy_length,
contents_mode,filenames_mode))return-1;
}
return0;
}
contents_encryption_mode和filenames_mode在installKey的时候就有设置过了,类似于contents_mode = “ice”,filenames_mode = “aes-256-cts”。
e4crypt_policy_ensure —> e4crypt_policy_set
static bool e4crypt_policy_set(const char *directory, const char *policy,
size_t policy_length,
int contents_encryption_mode,
int filenames_encryption_mode) {
if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
LOG(ERROR) << "Policy wrong length: " << policy_length;
return false;
}
int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
if (fd == -1) {
PLOG(ERROR) << "Failed to open directory " << directory;
return false;
}
// 设置ext4加密规则
ext4_encryption_policy eep;
eep.version = 0;
eep.contents_encryption_mode = contents_encryption_mode;
eep.filenames_encryption_mode = filenames_encryption_mode;
eep.flags = e4crypt_get_policy_flags(filenames_encryption_mode);
memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE);
// 调用IOCTL设置加密规则
if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) {
PLOG(ERROR) << "Failed to set encryption policy for " << directory;
close(fd);
return false;
}
close(fd);
char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
policy_to_hex(policy, policy_hex);
LOG(INFO) << "Policy for " << directory << " set to " << policy_hex;
return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
staticboole4crypt_policy_set(constchar*directory,constchar*policy,
size_tpolicy_length,
intcontents_encryption_mode,
intfilenames_encryption_mode){
if(policy_length!=EXT4_KEY_DESCRIPTOR_SIZE){
LOG(ERROR)<
returnfalse;
}
intfd=open(directory,O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
if(fd==-1){
PLOG(ERROR)<
returnfalse;
}
// 设置ext4加密规则
ext4_encryption_policyeep;
eep.version=0;
eep.contents_encryption_mode=contents_encryption_mode;
eep.filenames_encryption_mode=filenames_encryption_mode;
eep.flags=e4crypt_get_policy_flags(filenames_encryption_mode);
memcpy(eep.master_key_descriptor,policy,EXT4_KEY_DESCRIPTOR_SIZE);
// 调用IOCTL设置加密规则
if(ioctl(fd,EXT4_IOC_SET_ENCRYPTION_POLICY,&eep)){
PLOG(ERROR)<
close(fd);
returnfalse;
}
close(fd);
charpolicy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
policy_to_hex(policy,policy_hex);
LOG(INFO)<
returntrue;
}
到这里设置就做完了。FBE大概就了解这么多,但是感觉还是不够深入,后续有机会再多做些分析吧。
赞过:
赞 正在加载……
相关
android fbe分析,(原创)Android FBE加密源码分析(二)相关推荐
- Android 9 (P)之init进程启动源码分析指南之三
Android 9 (P)之init进程启动源码分析指南之三 Android 9 (P)系统启动及进程创建源码分析目录: Android 9 (P)之init进程启动源码分析指南之一 An ...
- Android源码分析-PackageManagerService(PMS)源码分析(三)- queryIntentActivities函数来查找activity
queryIntentActivities函数的作用: 在Android应用程序开发中,用startActivity可以开启另外一个Activity或应用.startActivity函数必须包含Int ...
- Android 9(P)之init进程启动源码分析指南之一
Android 9 之init进程启动源码分析指南之一 Android 9 (P) 系统启动及进程创建源码分析目录: Android 9 (P)之init进程启动源码分析指南之一 Andro ...
- Android 8.1/9.0 MTK Camera源码分析之录像快门声音控制流程
前面已经针对拍照快门声音控制流程进行了分析,接下来分析一下录像快门声音的控制流程. Android 8.1/9.0 MTK Camera源码分析之快门声音控制流程 这两篇文章其实都是相对于手机系统RO ...
- Android 8.1/9.0 MTK Camera源码分析之快门声音控制流程
Android 8.1/9.0 MTK Camera源码分析之快门声音控制 在Android 8.1上mtk camera有控制快门声音的接口,但是并没有了控制录像快门声音的接口.之所以会有这个现象, ...
- 解密android日志xlog,XLog 详解及源码分析
一.前言 这里的 XLog 不是微信 Mars 里面的 xLog,而是elvishew的xLog.感兴趣的同学可以看看作者 elvishwe 的官文史上最强的 Android 日志库 XLog.这里先 ...
- 【Android Protobuf 序列化】Protobuf 使用 ( Protobuf 源码分析 | 创建 Protobuf 对象 )
文章目录 一.Protobuf 源码分析 二.创建 Protobuf 对象 三.完整代码示例 四.参考资料 一.Protobuf 源码分析 Protobuf 源文件如下 : addressbook.p ...
- 【C++】Android (Light)RefBase-sp-wp引用计数-智能指针源码分析
文章目录 1.RefBase简介 2.RefBase源码分析 3.RefBase使用注意事项 4.总结 1.RefBase简介 什么是RefBase?RefBase是Android中的一个C++类,用 ...
- Android SQLite多线程读写和线程同步源码分析
没啥诀窍,只需保证几个线程都是用的一个SQLiteDataBase对象就行了. 如果我们非要在不同线程中用两个或更多的SQLiteDataBase对象呢,当然这些SQLiteDataBase对象所操作 ...
- Android 8.0系统源码分析--Camera processCaptureResult结果回传源码分析
相机,从上到下概览一下,真是太大了,上面的APP->Framework->CameraServer->CameraHAL,HAL进程中Pipeline.接各种算法的Node.再往下的 ...
最新文章
- 怎么制作铁闸门_红茶拿铁
- 计算机打印机用户,如何:在 Windows 窗体中选择连接到用户计算机的打印机
- Android 9 带着 AI 来了,为什么我们还停留在 6?
- Hotmail怎么进不去?!
- ELK(ElasticSearch, Logstash, Kibana)实时日志分析平台部署
- mysql 判断当前星期_MySQL数据库如何获取一个日期所对应的星期数呢?
- 使用A2P2V针对特定目标生成攻击序列
- 腾讯云— LAMP 架构个人实践分享
- 前端css 宠物列表
- 用户个人隐私保密协议
- 新媒体营销方式的优势
- 三菱plc支持c语言,5.三菱FX系列PLC支持哪种编程方式.
- abb机器人常见维故障现象
- 廊坊金盾说手脚冰冷先暖胃
- java string 去掉某个字符_JAVA String 如何去掉指定字符
- 利用 Lanczos 方法实现张量的 HOSVD 分解
- 如何看待Facebook 中国程序员之死:年仅 38 岁跳楼轻生,浙大 EE 毕业生,去年刚入职...
- matlab卡农,又用Mathematica写了一段卡农
- 海驾学车过程全揭秘——第三篇:重要的法培
- 动态数据库工具——Database Inspector