Android FDE 加密过程
来源:互联网 发布:淘宝页面设计代码 编辑:程序博客网 时间:2024/06/05 02:01
- Android Full Disk Encryption
- Settings中加密入口
- 调用关系
- 加密实现
- 参考
- Vold properties
- init properties
- init actions
Android Full Disk Encryption
FDE是android设备全盘加密的简称;主要用于对Android设备userdata分区数据的加密,以实现数据保护的目的
- FDE是什么
- FDE是Full Disk Encrypt的缩写
- 保护/data 分区数据
- 参考google的官方介绍(需要访问google网络) encryption
- 一种保护user data的机制。例如:联系人,图片,视频等等
- 截止当前,Android支持加密userdata分区的数据以及不可移除sdcard的数据
- 不支持其他分区的加密
- FDE如何工作
- 基于android kernel的dm-crypt feature 实现
- 128 Advanced Encryption Standard(AES) with cipher-block chaining(CBD)and ESSIV:SHA256
- Android5.0之后,首次开机会加密
- 加密之后,将/data挂在到dm的虚拟节点上
- FDE是Full Disk Encrypt的缩写
- 首次启动
- fstab.qcom 标志
- encryptable manually encrypt
- foeceencrypted encrypt in fist boot
- 使用默认的密码获得master key
- 默认密码是”default_password”
- Keymaster(HW/SW) general key blob,存储在footer中
- default_password_salt(random)–>scrypt–>derived key
- Derived+keypair–>sign–>intermedia key(ikey)
- salt,keybob,derived key stored in footer
- set ikey to TZ
- Hardware Crypto
- TZ generates an encrypt key derived from new password,set to crypto enginee
- Software Crypto
- Call APU to set key with ikey(security_hw.c)
- fstab.qcom 标志
- 非首次开机
- 如果用户设置了pin/或者密码
- 弹出提示用于输入密码
- 使用默认的密码获得master key
- 从footer中读取salt,keyblob,derived key
- 从输入或者salt中获得derivedkey,并进行比较
- Derived+keypair–>sign–>intermedia key(ikey)
- salt,keybob,derived key stored in footer
- set ikey to TZ
- 升级相关
- 如果使用了软件加密,可以直接软件升级
- 如果使用了硬件加密,不可以直接软件升级
- 如果用户设置了pin/或者密码
- init.rc
- on property:vold.decrypt=trigger_default_encryption
- start defaultcrypto
- service defaultcrypto /system/bin/vdc –wait cryptfs mountdefaultencrypted
- disable
- oneshot
- #vold will set vold.decrypt to trigger_restart_framework(default encryption) or trigger_restart_min_framework(other encryption)
- on property:vold.decrypt=trigger_default_encryption
- FDE 启动总结
- init 进程读取fstab中,并依据fstab中的配置进行挂载
- 在挂载过程中发现该分区标记了encrypted,使用property触发一个属性
- vdc服务传递命令给cryptd socket
- 监听器接收到该socket,然后触发encrypt/decrypt 动作
- 重要的函数
- CryptCommandListener::CryptfsCmd::runCommand
- get_keymaster_hw_fde_password
- set_hw_device_encryption_key
- create_crypto_blk_dev
- update_hw_device_encryption_key
Settings中加密入口
//package/apps/SettingsCryptKeeper.javaCryptKeeperSettings.javaCryptKeeperConfirm.java
调试加密过程显示的UI
//正常显示进度条adb shell pm enable com.android.settings/.CryptKeeperadb shell am start -e "com.android.settings.CryptKeeper.DEBUG_FORCE_VIEW" "progress" -n com.android.settings/.CryptKeeper//提示输入密码adb shell am start -e "com.android.settings.CryptKeeper.DEBUG_FORCE_VIEW" "password" -n com.android.settings/.CryptKeeper//出现错误adb shell am start -e "com.android.settings.CryptKeeper.DEBUG_FORCE_VIEW" "error" -n com.android.settings/.CryptKeeper
调用关系
MountService 启动后,会创建两个Thread 一个用于处理同底层vold的交互的、一个用于处理加密 。启动NativeDaemonConnector Thread 之后,对socket进行监听
调用流程:
NativeDaemonConnector.run() public int encryptStorage(int type, String password) -->mCryptConnector.execute("cryptfs", "enablecrypto", "inplace", …); --> CryptCommandListener::CryptfsCmd::runCommand(SocketClient*, argc, **argv) -->cryptfs_enable_default(char *howarg, int allow_reboot) -->cryptfs_enable_internal(char*,int,char*,int)
主要代码解释int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli, int argc, char **argv) {} else if (!strcmp(argv[1], "cryptocomplete")) { int type = getType(argv[3]); if (type == -1) { } else if (type == CRYPT_TYPE_DEFAULT) { rc = cryptfs_enable_default(argv[2],/*allow_reboot*/false); } else { rc = cryptfs_enable(argv[2], type, argv[4], /*allow_reboot*/false); } } else if (!strcmp(argv[1], "changepw")) {}
//比较文件系统的和分区的大小int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd, int allow_reboot) /* Get the size of the real block device */ int fd = open(real_blkdev, O_RDONLY|O_CLOEXEC); get_blkdev_size(fd, &nr_sec); fs_size_sec = get_fs_size(real_blkdev); if (fs_size_sec > max_fs_size_sec) { SLOGE("Orig filesystem overlaps crypto footer region. Cannot encrypt in place.");
/*获得一个随机的密钥对和盐,作为加密的密码。将密钥对和盐存储在data 分区的footer中*/static int create_encrypted_random_key(char *passwd, unsigned char *master_key, unsigned char *salt,crypt_mnt_ftr *crypt_ftr) { /* Get some random bits for a key */ fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC); read(fd, key_buf, sizeof(key_buf)); read(fd, salt, SALT_LEN); close(fd); /* Now encrypt it with the password */ return encrypt_master_key(passwd, salt, key_buf, master_key, crypt_ftr);}
/* Create mapped block device /dev/dm-0 with key_index which retrieved from set_hw_device_encryption_key*/decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0);create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev, crypto_blkdev, "userdata");rc = cryptfs_enable_all_volumes(&crypt_ftr, how, crypto_blkdev, real_blkdev, previously_encrypted_upto);cryptfs_enable_all_volumes--->cryptfs_enable_inplace ------> cryptfs_enable_inplace_ext4
//加密进程从真实的设备节点读取数据并将其写入到mapper的设备节点中static int cryptfs_enable_inplace_ext4(char *crypto_blkdev, char *real_blkdev, off64_t size, off64_t *size_already_done, off64_t tot_size, off64_t previously_encrypted_upto){ encrypt_groups(&data);}
加密实现
//判定当前设备是否正在被加密或者曾经加密过程被中断了。if (how == CRYPTO_ENABLE_INPLACE && get_crypt_ftr_and_key(&crypt_ftr) == 0 && (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS)) { previously_encrypted_upto = crypt_ftr.encrypted_upto; crypt_ftr.encrypted_upto = 0; crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS; //加密的状态是一直不确定的。直到加密完成,然后重启。所以,这里首先将flag设置为CRYPT_INCONSISTENT_STATE。 //待加密完成之后,将CRYPT_INCONSISTENT_STATE标志移除 crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE; put_crypt_ftr_and_key(&crypt_ftr);}//判断当前加密状态,通过ro.crypto.state属性来感知//计算real block device的大小//申请一个wakelock,这里可以根据需求申请partial或者full wake locksnprintf(lockid, sizeof(lockid), "enablecrypto%d", (int) getpid());acquire_wake_lock(PARTIAL_WAKE_LOCK, lockid);/* The init files are setup to stop the class main and late start when * vold sets trigger_shutdown_framework. *///设置vold.decrypt属性的值为trigger_shutdown_framework,触发init进程shutdown class mainproperty_set("vold.decrypt", "trigger_shutdown_framework");SLOGD("Just asked init to shut down class main\n");/* Ask vold to unmount all devices that it manages *///unmount 被管理的所有设备if (vold_unmountAll()) { SLOGE("Failed to unmount all vold managed devices");}/* Now unmount the /data partition. *///挂在data分区if (wait_and_unmount(DATA_MNT_POINT, false)) { if (allow_reboot) { goto error_shutting_down; } else { goto error_unencrypted; }}//为了提升体验,这里所做的一些额外工作/* Do extra work for a better UX when doing the long inplace encryption */if (how == CRYPTO_ENABLE_INPLACE) { ///data分区已经被卸载了,这里需要将tmpfs挂在到/data并且设置一个系统属性告诉系统,我们要开始加密啦。。 if (fs_mgr_do_tmpfs_mount(DATA_MNT_POINT)) { goto error_shutting_down; }else { SLOGD("Successful: mount tmpfs for '%s'\n", DATA_MNT_POINT); //.. } //告诉framework,我们要开始加密啦。framework property_set("vold.encrypt_progress", "0");//在/data上座一些必要的准备。//设置vold.decryp=trigger_post_fs_data来触发系列动作。 //动作完成之后,会将vold.post_fs_data_done设置为1,这里等待50s /* *property_set("vold.post_fs_data_done", "0"); *property_set("vold.decrypt", "trigger_post_fs_data"); *SLOGD("Just triggered post_fs_data\n"); */ if (prep_data_fs()) { goto error_shutting_down; } //等待2s,shutting down framework并不是同步进行。//故,需要等待一段时间。否则在某些设备上,图形相关的服务有有问题。 sleep(2);}/* Start the actual work of making an encrypted filesystem *//* Initialize a crypt_mnt_ftr for the partition *///开始真正的加密前的初始化。首先初始化得到crypt_mnt_ftr.if (previously_encrypted_upto == 0) { if (cryptfs_init_crypt_mnt_ftr(&crypt_ftr)) { goto error_shutting_down; } if (!strcmp(key_loc, KEY_IN_FOOTER)) { crypt_ftr.fs_size = nr_sec - (CRYPT_FOOTER_OFFSET / CRYPT_SECTOR_SIZE); } else { crypt_ftr.fs_size = nr_sec; } //加密的状态是一直不确定的。直到加密完成,然后重启。所以,这里首先将flag设置为CRYPT_INCONSISTENT_STATE。 //待加密完成之后,将CRYPT_INCONSISTENT_STATE标志移除 crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE; crypt_ftr.crypt_type = crypt_type; //选择不同的加密方式 "aes-xts"(使用软件加密) "aes-cbc-essiv:sha256"(使用硬件加密) //设置秘钥,将秘钥存储在分区的尾部。#ifndef CONFIG_HW_DISK_ENCRYPTION strlcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", MAX_CRYPTO_TYPE_NAME_LEN);#else strlcpy((char *)crypt_ftr.crypto_type_name, "aes-xts", MAX_CRYPTO_TYPE_NAME_LEN); rc = clear_hw_device_encryption_key(); rc = set_hw_device_encryption_key(passwd,#endif /* Make an encrypted master key */ if (create_encrypted_random_key(passwd, crypt_ftr.master_key, crypt_ftr.salt, &crypt_ftr)) { SLOGE("Cannot create encrypted master key\n"); goto error_shutting_down; } //将key写入到分区结尾 put_crypt_ftr_and_key(&crypt_ftr);}if (how == CRYPTO_ENABLE_INPLACE) { /* startup service classes main and late_start */ //启动services class main以及late_start property_set("vold.decrypt", "trigger_restart_min_framework"); SLOGD("Just triggered restart_min_framework\n"); //framework正在重启。稍等就可以看到进度条的显示了。 //进度条显示的含义是:正在加密的进度或者加密映射的文件进度}//创建master key//将‘userdata’映射到加密节点上decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0);create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev, crypto_blkdev, "userdata");/* If we are continuing, check checksums match *///读取的sha256值,同计算得到的sha256值进行比较rc = 0;if (previously_encrypted_upto) { __le8 hash_first_block[SHA256_DIGEST_LENGTH]; rc = cryptfs_SHA256_fileblock(crypto_blkdev, hash_first_block); if (!rc && memcmp(hash_first_block, crypt_ftr.hash_first_block, sizeof(hash_first_block)) != 0) { SLOGE("Checksums do not match - trigger wipe"); rc = -1; }}if (!rc) { rc = cryptfs_enable_all_volumes(&crypt_ftr, how, crypto_blkdev, real_blkdev, previously_encrypted_upto);}/* Calculate checksum if we are not finished */if (!rc && how == CRYPTO_ENABLE_INPLACE && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) { rc = cryptfs_SHA256_fileblock(crypto_blkdev, crypt_ftr.hash_first_block); if (rc) { SLOGE("Error calculating checksum for continuing encryption"); rc = -1; }}/* Undo the dm-crypt mapping whether we succeed or not */delete_crypto_blk_dev("userdata");if (! rc) {//条件判断ok /* Success */ crypt_ftr.flags &= ~CRYPT_INCONSISTENT_STATE; if (how == CRYPTO_ENABLE_INPLACE && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) { SLOGD("Encrypted up to sector %lld - will continue after reboot", crypt_ftr.encrypted_upto); crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS; } put_crypt_ftr_and_key(&crypt_ftr);#ifdef MTK_EMMC_SUPPORT { struct phone_encrypt_state ps; ps.state = PHONE_ENCRYPTED; if (misc_set_phone_encrypt_state(&ps, fstab) < 0) { SLOGE("Failed to set encrypted status to 0x%x in MISC\n", ps.state); } else { SLOGD("Success: Set encrypted status to 0x%x in MISC\n", ps.state); } }#endif //判断ro.crypted.state的值是否为encrypted(代表加密成功) if (how == CRYPTO_ENABLE_WIPE || crypt_ftr.encrypted_upto == crypt_ftr.fs_size) { char value[PROPERTY_VALUE_MAX]; property_get("ro.crypto.state", value, ""); if (!strcmp(value, "")) { /* default encryption - continue first boot sequence */ property_set("ro.crypto.state", "encrypted"); release_wake_lock(lockid); cryptfs_check_passwd(DEFAULT_PASSWORD); property_set("vold.encrypt_progress", ""); cryptfs_restart_internal(1); return 0; } else { sleep(2); /* Give the UI a chance to show 100% progress */ cryptfs_reboot(reboot); } } else { sleep(2); /* Partially encrypted, ensure writes flushed to ssd */ cryptfs_reboot(shutdown); }} else {//初始条件判断失败。 char value[PROPERTY_VALUE_MAX]; property_get("ro.vold.wipe_on_crypt_fail", value, "0"); if (!strcmp(value, "1")) { /* wipe data if encryption failed */ SLOGE("encryption failed - rebooting into recovery to wipe data\n"); mkdir("/cache/recovery", 0700); int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0600); if (fd >= 0) { write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1); write(fd, "--reason=cryptfs_enable_internal\n", strlen("--reason=cryptfs_enable_internal\n") + 1); close(fd); } else { SLOGE("could not open /cache/recovery/command\n"); } cryptfs_reboot(recovery); } else { /* set property to trigger dialog */ property_set("vold.encrypt_progress", "error_partially_encrypted"); release_wake_lock(lockid); } return -1;}
参考
Vold properties
init properties
init actions
on post-fs-data
on nonencrypted
on property:vold.decrypt=trigger_reset_main
on property:vold.decrypt=trigger_post_fs_data
on property:vold.decrypt=trigger_restart_min_framework
on property:vold.decrypt=trigger_restart_framework
on property:vold.decrypt=trigger_shutdown_framework
on property:vold.decrypt=trigger_encryption
on property:vold.decrypt=trigger_default_encryption
0 0
- Android FDE 加密过程
- FDE之加密流程
- Full Disk Encryption(FDE)全盘加密开关
- Android 5.0中的FDE功能实现
- FDE概况
- 【android】几个和密码相关的问题分析(开机密码输入无效、FDE后改变密码无效、FDE后解密失败)
- 加密过程
- 加密过程
- Android 5.0 启动过程中磁盘加密流程
- android 端RSA加密过程中遇到的坑
- Java、Android开发过程中需要用到的加密详解
- 破解加密存储过程
- 破解加密存储过程
- 加密所有存含储过程
- 简单密码加密过程
- 破解加密存储过程
- 加密存储过程
- 加密oracle存储过程
- 2017 Pycharm激活码
- maven 的配置
- C语言之字符串、字符数组,字符串函数
- Linux中JDK安装与配置
- 为什么IOS的安装包比Android大
- Android FDE 加密过程
- 关于PHP写APP接口的安全问题探讨(一)
- 余弦计算相似度度量【转】
- map的keySet entrySet
- (转)Android中ListView分页加载数据
- 微信公众号微信红包开发 PHP代码
- PHP 获取服务器信息
- git 中分支管理工程的思路
- Cloudera在Ubuntu的安装部署