上一篇最后讲到,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加密源码分析(二)相关推荐

  1. Android 9 (P)之init进程启动源码分析指南之三

          Android 9 (P)之init进程启动源码分析指南之三 Android 9 (P)系统启动及进程创建源码分析目录: Android 9 (P)之init进程启动源码分析指南之一 An ...

  2. Android源码分析-PackageManagerService(PMS)源码分析(三)- queryIntentActivities函数来查找activity

    queryIntentActivities函数的作用: 在Android应用程序开发中,用startActivity可以开启另外一个Activity或应用.startActivity函数必须包含Int ...

  3. Android 9(P)之init进程启动源码分析指南之一

         Android 9 之init进程启动源码分析指南之一 Android 9 (P) 系统启动及进程创建源码分析目录: Android 9 (P)之init进程启动源码分析指南之一 Andro ...

  4. Android 8.1/9.0 MTK Camera源码分析之录像快门声音控制流程

    前面已经针对拍照快门声音控制流程进行了分析,接下来分析一下录像快门声音的控制流程. Android 8.1/9.0 MTK Camera源码分析之快门声音控制流程 这两篇文章其实都是相对于手机系统RO ...

  5. Android 8.1/9.0 MTK Camera源码分析之快门声音控制流程

    Android 8.1/9.0 MTK Camera源码分析之快门声音控制 在Android 8.1上mtk camera有控制快门声音的接口,但是并没有了控制录像快门声音的接口.之所以会有这个现象, ...

  6. 解密android日志xlog,XLog 详解及源码分析

    一.前言 这里的 XLog 不是微信 Mars 里面的 xLog,而是elvishew的xLog.感兴趣的同学可以看看作者 elvishwe 的官文史上最强的 Android 日志库 XLog.这里先 ...

  7. 【Android Protobuf 序列化】Protobuf 使用 ( Protobuf 源码分析 | 创建 Protobuf 对象 )

    文章目录 一.Protobuf 源码分析 二.创建 Protobuf 对象 三.完整代码示例 四.参考资料 一.Protobuf 源码分析 Protobuf 源文件如下 : addressbook.p ...

  8. 【C++】Android (Light)RefBase-sp-wp引用计数-智能指针源码分析

    文章目录 1.RefBase简介 2.RefBase源码分析 3.RefBase使用注意事项 4.总结 1.RefBase简介 什么是RefBase?RefBase是Android中的一个C++类,用 ...

  9. Android SQLite多线程读写和线程同步源码分析

    没啥诀窍,只需保证几个线程都是用的一个SQLiteDataBase对象就行了. 如果我们非要在不同线程中用两个或更多的SQLiteDataBase对象呢,当然这些SQLiteDataBase对象所操作 ...

  10. Android 8.0系统源码分析--Camera processCaptureResult结果回传源码分析

    相机,从上到下概览一下,真是太大了,上面的APP->Framework->CameraServer->CameraHAL,HAL进程中Pipeline.接各种算法的Node.再往下的 ...

最新文章

  1. 怎么制作铁闸门_红茶拿铁
  2. 计算机打印机用户,如何:在 Windows 窗体中选择连接到用户计算机的打印机
  3. Android 9 带着 AI 来了,为什么我们还停留在 6?
  4. Hotmail怎么进不去?!
  5. ELK(ElasticSearch, Logstash, Kibana)实时日志分析平台部署
  6. mysql 判断当前星期_MySQL数据库如何获取一个日期所对应的星期数呢?
  7. 使用A2P2V针对特定目标生成攻击序列
  8. 腾讯云— LAMP 架构个人实践分享
  9. 前端css 宠物列表
  10. 用户个人隐私保密协议
  11. 新媒体营销方式的优势
  12. 三菱plc支持c语言,5.三菱FX系列PLC支持哪种编程方式.
  13. abb机器人常见维故障现象
  14. 廊坊金盾说手脚冰冷先暖胃
  15. java string 去掉某个字符_JAVA String 如何去掉指定字符
  16. 利用 Lanczos 方法实现张量的 HOSVD 分解
  17. 如何看待Facebook 中国程序员之死:年仅 38 岁跳楼轻生,浙大 EE 毕业生,去年刚入职...
  18. matlab卡农,又用Mathematica写了一段卡农
  19. 海驾学车过程全揭秘——第三篇:重要的法培
  20. 动态数据库工具——Database Inspector

热门文章

  1. jsp与servlet的联系与区别
  2. Python 博客园快速备份脚本
  3. 画质超高的仙侠java游戏_画质超高的仙侠手游
  4. 画质、分辨率、帧率之间有什么关系与区别?
  5. C#中服务器端以太网通讯(一对一)
  6. PMP证书到期,有必要续证吗?
  7. wpe解密系列001
  8. [Spring] [最佳实践] 如何对 @Async 标记的异步方法进行单元测试
  9. 个人日记系统,记录点滴小事,记录生活点点滴滴
  10. 12306的自动化登录