From 659d3765c0688b6ae38515a2e03d72270dd29beb Mon Sep 17 00:00:00 2001 From: AnilKumar Chimata Date: Fri, 11 May 2018 00:25:09 +0530 Subject: [PATCH] vold: Add Hardware FDE feature Add HW FDE changes to new tip along with soong rules for conditional compilation. Following changes for HW FDE as well ported: - Restart Android framework after HW FDE key has been created - Add support of Inline Cryto Engine - Use new HW FDE apis to update password - vold: Tie HW FDE keys with Root of Trust(ROT) - vold: Fix HW FDE OTA support on SW FDE encrypted device - vold: Fix return value from get_keymaster_hw_fde_passwd() - vold: Remove creation of new keymaster key for password update - vold: Fix password update issue with HW FDE - vold: hw_fde: fix OTA issues from L to M - vold: Branch out SW and HW FDE paths to improve boot up time - cryptfs: Use lower case alphabets for hex key during OTA upgrades - vold: Improve device boot up time (Tune sleep calls) - Retry mount if mount fails after setting HW FDE key - cryptfs: Fix compilation error - cryptfs: Fix mount failure when encryption triggered from settings - cryptfs: fix issue that caused problems with forced HW encryption - cryptfs: fix wrong password set by user during bootup. CRs-Fixed: 2210986 Change-Id: I77279fc7e309ac94535123a2b2dbcb228bb47251 --- Android.bp | 8 + VoldNativeService.cpp | 3 +- VoldNativeService.h | 4 +- binder/android/os/IVold.aidl | 2 +- cryptfs.cpp | 531 ++++++++++++++++++++++++++++++++++- cryptfs.h | 11 +- 6 files changed, 540 insertions(+), 19 deletions(-) diff --git a/Android.bp b/Android.bp index b033647..26c4745 100644 --- a/Android.bp +++ b/Android.bp @@ -161,6 +161,11 @@ cc_library_static { debuggable: { cppflags: ["-D__ANDROID_DEBUGGABLE__"], }, + device_support_hwfde: { + cflags: ["-DCONFIG_HW_DISK_ENCRYPTION"], + header_libs: ["libcryptfs_hw_headers"], + shared_libs: ["libcryptfs_hw"], + }, }, shared_libs: [ "android.hardware.health.storage@1.0", @@ -187,6 +192,9 @@ cc_binary { "libarcobbvolume", ], }, + device_support_hwfde: { + shared_libs: ["libcryptfs_hw"], + }, }, init_rc: [ "vold.rc", diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 0cb86ce..e1a7b6f 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -584,11 +584,12 @@ binder::Status VoldNativeService::fdeEnable(int32_t passwordType, const std::str } binder::Status VoldNativeService::fdeChangePassword(int32_t passwordType, + const std::string& currentPassword, const std::string& password) { ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; - return translate(cryptfs_changepw(passwordType, password.c_str())); + return translate(cryptfs_changepw(passwordType, currentPassword.c_str(), password.c_str())); } binder::Status VoldNativeService::fdeVerifyPassword(const std::string& password) { diff --git a/VoldNativeService.h b/VoldNativeService.h index 013d1c2..cb32db1 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -97,7 +97,9 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status fdeComplete(int32_t* _aidl_return); binder::Status fdeEnable(int32_t passwordType, const std::string& password, int32_t encryptionFlags); - binder::Status fdeChangePassword(int32_t passwordType, const std::string& password); + binder::Status fdeChangePassword(int32_t passwordType, + const std::string& currentPassword, + const std::string& password); binder::Status fdeVerifyPassword(const std::string& password); binder::Status fdeGetField(const std::string& key, std::string* _aidl_return); binder::Status fdeSetField(const std::string& key, const std::string& value); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 54b86d0..267cb6b 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -74,7 +74,7 @@ interface IVold { void fdeRestart(); int fdeComplete(); void fdeEnable(int passwordType, @utf8InCpp String password, int encryptionFlags); - void fdeChangePassword(int passwordType, @utf8InCpp String password); + void fdeChangePassword(int passwordType, @utf8InCpp String currentPassword, @utf8InCpp String password); void fdeVerifyPassword(@utf8InCpp String password); @utf8InCpp String fdeGetField(@utf8InCpp String key); void fdeSetField(@utf8InCpp String key, @utf8InCpp String value); diff --git a/cryptfs.cpp b/cryptfs.cpp index 8b7ac0a..b6dd5f3 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -70,6 +70,9 @@ #include #include +#ifdef CONFIG_HW_DISK_ENCRYPTION +#include +#endif extern "C" { #include } @@ -276,6 +279,7 @@ static_assert(INTERMEDIATE_BUF_SIZE == SCRYPT_LEN, "Mismatch of intermediate key #define KEY_IN_FOOTER "footer" +#define DEFAULT_HEX_PASSWORD "64656661756c745f70617373776f7264" #define DEFAULT_PASSWORD "default_password" #define CRYPTO_BLOCK_DEVICE "userdata" @@ -291,6 +295,7 @@ static_assert(INTERMEDIATE_BUF_SIZE == SCRYPT_LEN, "Mismatch of intermediate key #define RSA_KEY_SIZE_BYTES (RSA_KEY_SIZE / 8) #define RSA_EXPONENT 0x10001 #define KEYMASTER_CRYPTFS_RATE_LIMIT 1 // Maximum one try per second +#define KEY_LEN_BYTES 16 #define RETRY_MOUNT_ATTEMPTS 10 #define RETRY_MOUNT_DELAY_SECONDS 1 @@ -304,6 +309,151 @@ static char* saved_mount_point; static int master_key_saved = 0; static struct crypt_persist_data* persist_data = NULL; +static int previous_type; + +#ifdef CONFIG_HW_DISK_ENCRYPTION +static int scrypt_keymaster(const char *passwd, const unsigned char *salt, + unsigned char *ikey, void *params); +static void convert_key_to_hex_ascii(const unsigned char *master_key, + unsigned int keysize, char *master_key_ascii); +static int put_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr); +static int test_mount_hw_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, + const char *passwd, const char *mount_point, const char *label); +int cryptfs_changepw_hw_fde(int crypt_type, const char *currentpw, + const char *newpw); +int cryptfs_check_passwd_hw(char *passwd); +int cryptfs_get_master_key(struct crypt_mnt_ftr* ftr, const char* password, + unsigned char* master_key); + +static void convert_key_to_hex_ascii_for_upgrade(const unsigned char *master_key, + unsigned int keysize, char *master_key_ascii) +{ + unsigned int i, a; + unsigned char nibble; + + for (i = 0, a = 0; i < keysize; i++, a += 2) { + /* For each byte, write out two ascii hex digits */ + nibble = (master_key[i] >> 4) & 0xf; + master_key_ascii[a] = nibble + (nibble > 9 ? 0x57 : 0x30); + + nibble = master_key[i] & 0xf; + master_key_ascii[a + 1] = nibble + (nibble > 9 ? 0x57 : 0x30); + } + + /* Add the null termination */ + master_key_ascii[a] = '\0'; +} + +static int get_keymaster_hw_fde_passwd(const char* passwd, unsigned char* newpw, + unsigned char* salt, + const struct crypt_mnt_ftr *ftr) +{ + /* if newpw updated, return 0 + * if newpw not updated return -1 + */ + int rc = -1; + + if (should_use_keymaster()) { + if (scrypt_keymaster(passwd, salt, newpw, (void*)ftr)) { + SLOGE("scrypt failed"); + } else { + rc = 0; + } + } + + return rc; +} + +static int verify_hw_fde_passwd(const char *passwd, struct crypt_mnt_ftr* crypt_ftr) +{ + unsigned char newpw[32] = {0}; + int key_index; + if (get_keymaster_hw_fde_passwd(passwd, newpw, crypt_ftr->salt, crypt_ftr)) + key_index = set_hw_device_encryption_key(passwd, + (char*) crypt_ftr->crypto_type_name); + else + key_index = set_hw_device_encryption_key((const char*)newpw, + (char*) crypt_ftr->crypto_type_name); + return key_index; +} + +static int verify_and_update_hw_fde_passwd(const char *passwd, + struct crypt_mnt_ftr* crypt_ftr) +{ + char* new_passwd = NULL; + unsigned char newpw[32] = {0}; + int key_index = -1; + int passwd_updated = -1; + int ascii_passwd_updated = (crypt_ftr->flags & CRYPT_ASCII_PASSWORD_UPDATED); + + key_index = verify_hw_fde_passwd(passwd, crypt_ftr); + if (key_index < 0) { + ++crypt_ftr->failed_decrypt_count; + + if (ascii_passwd_updated) { + SLOGI("Ascii password was updated"); + } else { + /* Code in else part would execute only once: + * When device is upgraded from L->M release. + * Once upgraded, code flow should never come here. + * L release passed actual password in hex, so try with hex + * Each nible of passwd was encoded as a byte, so allocate memory + * twice of password len plus one more byte for null termination + */ + if (crypt_ftr->crypt_type == CRYPT_TYPE_DEFAULT) { + new_passwd = (char*)malloc(strlen(DEFAULT_HEX_PASSWORD) + 1); + if (new_passwd == NULL) { + SLOGE("System out of memory. Password verification incomplete"); + goto out; + } + strlcpy(new_passwd, DEFAULT_HEX_PASSWORD, strlen(DEFAULT_HEX_PASSWORD) + 1); + } else { + new_passwd = (char*)malloc(strlen(passwd) * 2 + 1); + if (new_passwd == NULL) { + SLOGE("System out of memory. Password verification incomplete"); + goto out; + } + convert_key_to_hex_ascii_for_upgrade((const unsigned char*)passwd, + strlen(passwd), new_passwd); + } + key_index = set_hw_device_encryption_key((const char*)new_passwd, + (char*) crypt_ftr->crypto_type_name); + if (key_index >=0) { + crypt_ftr->failed_decrypt_count = 0; + SLOGI("Hex password verified...will try to update with Ascii value"); + /* Before updating password, tie that with keymaster to tie with ROT */ + + if (get_keymaster_hw_fde_passwd(passwd, newpw, + crypt_ftr->salt, crypt_ftr)) { + passwd_updated = update_hw_device_encryption_key(new_passwd, + passwd, (char*)crypt_ftr->crypto_type_name); + } else { + passwd_updated = update_hw_device_encryption_key(new_passwd, + (const char*)newpw, (char*)crypt_ftr->crypto_type_name); + } + + if (passwd_updated >= 0) { + crypt_ftr->flags |= CRYPT_ASCII_PASSWORD_UPDATED; + SLOGI("Ascii password recorded and updated"); + } else { + SLOGI("Passwd verified, could not update...Will try next time"); + } + } else { + ++crypt_ftr->failed_decrypt_count; + } + free(new_passwd); + } + } else { + if (!ascii_passwd_updated) + crypt_ftr->flags |= CRYPT_ASCII_PASSWORD_UPDATED; + } +out: + // update footer before leaving + put_crypt_ftr_and_key(crypt_ftr); + return key_index; +} +#endif + constexpr CryptoType aes_128_cbc = CryptoType() .set_config_name("AES-128-CBC") .set_kernel_name("aes-cbc-essiv:sha256") @@ -1220,7 +1370,8 @@ static int scrypt_keymaster(const char* passwd, const unsigned char* salt, unsig static int encrypt_master_key(const char* passwd, const unsigned char* salt, const unsigned char* decrypted_master_key, - unsigned char* encrypted_master_key, struct crypt_mnt_ftr* crypt_ftr) { + unsigned char* encrypted_master_key, struct crypt_mnt_ftr* crypt_ftr, + bool create_keymaster_key) { unsigned char ikey[INTERMEDIATE_BUF_SIZE] = {0}; EVP_CIPHER_CTX e_ctx; int encrypted_len, final_len; @@ -1231,7 +1382,7 @@ static int encrypt_master_key(const char* passwd, const unsigned char* salt, switch (crypt_ftr->kdf_type) { case KDF_SCRYPT_KEYMASTER: - if (keymaster_create_key(crypt_ftr)) { + if (create_keymaster_key && keymaster_create_key(crypt_ftr)) { SLOGE("keymaster_create_key failed"); return -1; } @@ -1395,7 +1546,7 @@ static int create_encrypted_random_key(const char* passwd, unsigned char* master } /* Now encrypt it with the password */ - return encrypt_master_key(passwd, salt, key_buf, master_key, crypt_ftr); + return encrypt_master_key(passwd, salt, key_buf, master_key, crypt_ftr, true); } static void ensure_subdirectory_unmounted(const char *prefix) { @@ -1438,7 +1589,7 @@ static int wait_and_unmount(const char* mountpoint, bool kill) { // Subdirectory mount will cause a failure of umount. ensure_subdirectory_unmounted(mountpoint); -#define WAIT_UNMOUNT_COUNT 20 +#define WAIT_UNMOUNT_COUNT 200 /* Now umount the tmpfs filesystem */ for (i = 0; i < WAIT_UNMOUNT_COUNT; i++) { @@ -1455,18 +1606,18 @@ static int wait_and_unmount(const char* mountpoint, bool kill) { err = errno; - /* If allowed, be increasingly aggressive before the last two retries */ + /* If allowed, be increasingly aggressive before the last 2 seconds */ if (kill) { - if (i == (WAIT_UNMOUNT_COUNT - 3)) { + if (i == (WAIT_UNMOUNT_COUNT - 30)) { SLOGW("sending SIGHUP to processes with open files\n"); android::vold::KillProcessesWithOpenFiles(mountpoint, SIGTERM); - } else if (i == (WAIT_UNMOUNT_COUNT - 2)) { + } else if (i == (WAIT_UNMOUNT_COUNT - 20)) { SLOGW("sending SIGKILL to processes with open files\n"); android::vold::KillProcessesWithOpenFiles(mountpoint, SIGKILL); } } - sleep(1); + usleep(100000); } if (i < WAIT_UNMOUNT_COUNT) { @@ -1639,6 +1790,17 @@ static int cryptfs_restart_internal(int restart_main) { cryptfs_reboot(RebootType::reboot); } } else { +#ifdef CONFIG_HW_DISK_ENCRYPTION + if (--retries) { + sleep(RETRY_MOUNT_DELAY_SECONDS); + } else { + SLOGE("Failed to mount decrypted data"); + cryptfs_set_corrupt(); + cryptfs_trigger_restart_min_framework(); + SLOGI("Started framework to offer wipe"); + return -1; + } +#else SLOGE("Failed to mount decrypted data"); cryptfs_set_corrupt(); cryptfs_trigger_restart_min_framework(); @@ -1647,6 +1809,7 @@ static int cryptfs_restart_internal(int restart_main) { SLOGE("Failed to setexeccon"); } return -1; +#endif } } if (setexeccon(NULL)) { @@ -1739,6 +1902,65 @@ static int do_crypto_complete(const char* mount_point) { return CRYPTO_COMPLETE_ENCRYPTED; } +#ifdef CONFIG_HW_DISK_ENCRYPTION +static int test_mount_hw_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, + const char *passwd, const char *mount_point, const char *label) +{ + /* Allocate enough space for a 256 bit key, but we may use less */ + unsigned char decrypted_master_key[32]; + char crypto_blkdev[MAXPATHLEN]; + char real_blkdev[MAXPATHLEN]; + unsigned int orig_failed_decrypt_count; + int rc = 0; + + SLOGD("crypt_ftr->fs_size = %lld\n", crypt_ftr->fs_size); + orig_failed_decrypt_count = crypt_ftr->failed_decrypt_count; + + fs_mgr_get_crypt_info(fstab_default, 0, real_blkdev, sizeof(real_blkdev)); + + int key_index = 0; + if(is_hw_disk_encryption((char*)crypt_ftr->crypto_type_name)) { + key_index = verify_and_update_hw_fde_passwd(passwd, crypt_ftr); + if (key_index < 0) { + rc = crypt_ftr->failed_decrypt_count; + goto errout; + } + else { + if (is_ice_enabled()) { + if (create_crypto_blk_dev(crypt_ftr, (unsigned char*)&key_index, + real_blkdev, crypto_blkdev, label, 0)) { + SLOGE("Error creating decrypted block device"); + rc = -1; + goto errout; + } + } else { + if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key, + real_blkdev, crypto_blkdev, label, 0)) { + SLOGE("Error creating decrypted block device"); + rc = -1; + goto errout; + } + } + } + } + + if (rc == 0) { + crypt_ftr->failed_decrypt_count = 0; + if (orig_failed_decrypt_count != 0) { + put_crypt_ftr_and_key(crypt_ftr); + } + + /* Save the name of the crypto block device + * so we can mount it when restarting the framework. */ + property_set("ro.crypto.fs_crypto_blkdev", crypto_blkdev); + master_key_saved = 1; + } + + errout: + return rc; +} +#endif + static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, const char* passwd, const char* mount_point, const char* label) { unsigned char decrypted_master_key[MAX_KEY_LEN]; @@ -1842,7 +2064,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, const char* if (upgrade) { rc = encrypt_master_key(passwd, crypt_ftr->salt, saved_master_key, - crypt_ftr->master_key, crypt_ftr); + crypt_ftr->master_key, crypt_ftr, true); if (!rc) { rc = put_crypt_ftr_and_key(crypt_ftr); } @@ -1927,6 +2149,66 @@ int check_unmounted_and_get_ftr(struct crypt_mnt_ftr* crypt_ftr) { return 0; } +#ifdef CONFIG_HW_DISK_ENCRYPTION +int cryptfs_check_passwd_hw(const char* passwd) +{ + struct crypt_mnt_ftr crypt_ftr; + int rc; + unsigned char master_key[KEY_LEN_BYTES]; + + /* get key */ + if (get_crypt_ftr_and_key(&crypt_ftr)) { + SLOGE("Error getting crypt footer and key"); + return -1; + } + + /* + * in case of manual encryption (from GUI), the encryption is done with + * default password + */ + if (crypt_ftr.flags & CRYPT_FORCE_COMPLETE) { + /* compare scrypted_intermediate_key with stored scrypted_intermediate_key + * which was created with actual password before reboot. + */ + rc = cryptfs_get_master_key(&crypt_ftr, passwd, master_key); + if (rc) { + SLOGE("password doesn't match"); + rc = ++crypt_ftr.failed_decrypt_count; + put_crypt_ftr_and_key(&crypt_ftr); + return rc; + } + + rc = test_mount_hw_encrypted_fs(&crypt_ftr, DEFAULT_PASSWORD, + DATA_MNT_POINT, CRYPTO_BLOCK_DEVICE); + + if (rc) { + SLOGE("Default password did not match on reboot encryption"); + return rc; + } + + crypt_ftr.flags &= ~CRYPT_FORCE_COMPLETE; + put_crypt_ftr_and_key(&crypt_ftr); + rc = cryptfs_changepw(crypt_ftr.crypt_type, DEFAULT_PASSWORD, passwd); + if (rc) { + SLOGE("Could not change password on reboot encryption"); + return rc; + } + } else + rc = test_mount_hw_encrypted_fs(&crypt_ftr, passwd, + DATA_MNT_POINT, CRYPTO_BLOCK_DEVICE); + + if (crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) { + cryptfs_clear_password(); + password = strdup(passwd); + struct timespec now; + clock_gettime(CLOCK_BOOTTIME, &now); + password_expiry_time = now.tv_sec + password_max_age_seconds; + } + + return rc; +} +#endif + int cryptfs_check_passwd(const char* passwd) { SLOGI("cryptfs_check_passwd"); if (fscrypt_is_native()) { @@ -1943,6 +2225,11 @@ int cryptfs_check_passwd(const char* passwd) { return rc; } +#ifdef CONFIG_HW_DISK_ENCRYPTION + if (is_hw_disk_encryption((char*)crypt_ftr.crypto_type_name)) + return cryptfs_check_passwd_hw(passwd); +#endif + rc = test_mount_encrypted_fs(&crypt_ftr, passwd, DATA_MNT_POINT, CRYPTO_BLOCK_DEVICE); if (rc) { SLOGE("Password did not match"); @@ -1964,7 +2251,7 @@ int cryptfs_check_passwd(const char* passwd) { crypt_ftr.flags &= ~CRYPT_FORCE_COMPLETE; put_crypt_ftr_and_key(&crypt_ftr); - rc = cryptfs_changepw(crypt_ftr.crypt_type, passwd); + rc = cryptfs_changepw(crypt_ftr.crypt_type, DEFAULT_PASSWORD, passwd); if (rc) { SLOGE("Could not change password on reboot encryption"); return rc; @@ -2013,6 +2300,24 @@ int cryptfs_verify_passwd(const char* passwd) { /* If the device has no password, then just say the password is valid */ rc = 0; } else { +#ifdef CONFIG_HW_DISK_ENCRYPTION + if(is_hw_disk_encryption((char*)crypt_ftr.crypto_type_name)) { + if (verify_hw_fde_passwd(passwd, &crypt_ftr) >= 0) + rc = 0; + else + rc = -1; + } else { + decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0); + if (!memcmp(decrypted_master_key, saved_master_key, crypt_ftr.keysize)) { + /* They match, the password is correct */ + rc = 0; + } else { + /* If incorrect, sleep for a bit to prevent dictionary attacks */ + sleep(1); + rc = 1; + } + } +#else decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0); if (!memcmp(decrypted_master_key, saved_master_key, crypt_ftr.keysize)) { /* They match, the password is correct */ @@ -2022,6 +2327,7 @@ int cryptfs_verify_passwd(const char* passwd) { sleep(1); rc = 1; } +#endif } return rc; @@ -2143,6 +2449,11 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { off64_t previously_encrypted_upto = 0; bool rebootEncryption = false; bool onlyCreateHeader = false; +#ifdef CONFIG_HW_DISK_ENCRYPTION + unsigned char newpw[32]; + int key_index = 0; +#endif + int index = 0; std::unique_ptr wakeLock = nullptr; if (get_crypt_ftr_and_key(&crypt_ftr) == 0) { @@ -2284,8 +2595,13 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE; } crypt_ftr.crypt_type = crypt_type; +#ifdef CONFIG_HW_DISK_ENCRYPTION + strlcpy((char*)crypt_ftr.crypto_type_name, "aes-xts", + MAX_CRYPTO_TYPE_NAME_LEN); +#else strlcpy((char*)crypt_ftr.crypto_type_name, get_crypto_type().get_kernel_name(), MAX_CRYPTO_TYPE_NAME_LEN); +#endif /* Make an encrypted master key */ if (create_encrypted_random_key(onlyCreateHeader ? DEFAULT_PASSWORD : passwd, @@ -2300,7 +2616,7 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { unsigned char encrypted_fake_master_key[MAX_KEY_LEN]; memset(fake_master_key, 0, sizeof(fake_master_key)); encrypt_master_key(passwd, crypt_ftr.salt, fake_master_key, encrypted_fake_master_key, - &crypt_ftr); + &crypt_ftr, true); } /* Write the key to the end of the partition */ @@ -2321,12 +2637,57 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { } } + /* When encryption triggered from settings, encryption starts after reboot. + So set the encryption key when the actual encryption starts. + */ +#ifdef CONFIG_HW_DISK_ENCRYPTION + if (previously_encrypted_upto == 0) { + if (!rebootEncryption) + clear_hw_device_encryption_key(); + + if (get_keymaster_hw_fde_passwd( + onlyCreateHeader ? DEFAULT_PASSWORD : passwd, + newpw, crypt_ftr.salt, &crypt_ftr)) + key_index = set_hw_device_encryption_key( + onlyCreateHeader ? DEFAULT_PASSWORD : passwd, + (char*)crypt_ftr.crypto_type_name); + else + key_index = set_hw_device_encryption_key((const char*)newpw, + (char*) crypt_ftr.crypto_type_name); + if (key_index < 0) + goto error_shutting_down; + + crypt_ftr.flags |= CRYPT_ASCII_PASSWORD_UPDATED; + put_crypt_ftr_and_key(&crypt_ftr); + } +#endif + if (onlyCreateHeader) { sleep(2); cryptfs_reboot(RebootType::reboot); - } + } else { + /* Do extra work for a better UX when doing the long inplace encryption */ + /* Now that /data is unmounted, we need to mount a tmpfs + * /data, set a property saying we're doing inplace encryption, + * and restart the framework. + */ + if (fs_mgr_do_tmpfs_mount(DATA_MNT_POINT)) { + goto error_shutting_down; + } + /* Tells the framework that inplace encryption is starting */ + property_set("vold.encrypt_progress", "0"); + + /* restart the framework. */ + /* Create necessary paths on /data */ + prep_data_fs(); + + /* Ugh, shutting down the framework is not synchronous, so until it + * can be fixed, this horrible hack will wait a moment for it all to + * shut down before proceeding. Without it, some devices cannot + * restart the graphics services. + */ + sleep(2); - if (!no_ui || rebootEncryption) { /* startup service classes main and late_start */ property_set("vold.decrypt", "trigger_restart_min_framework"); SLOGD("Just triggered restart_min_framework\n"); @@ -2339,8 +2700,17 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { } decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0); +#ifdef CONFIG_HW_DISK_ENCRYPTION + if (is_hw_disk_encryption((char*)crypt_ftr.crypto_type_name) && is_ice_enabled()) + create_crypto_blk_dev(&crypt_ftr, (unsigned char*)&key_index, real_blkdev.c_str(), &crypto_blkdev, + CRYPTO_BLOCK_DEVICE, 0); + else + create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev.c_str(), &crypto_blkdev, + CRYPTO_BLOCK_DEVICE, 0); +#else create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev.c_str(), &crypto_blkdev, CRYPTO_BLOCK_DEVICE, 0); +#endif /* If we are continuing, check checksums match */ rc = 0; @@ -2466,7 +2836,7 @@ int cryptfs_enable_default(int no_ui) { return cryptfs_enable_internal(CRYPT_TYPE_DEFAULT, DEFAULT_PASSWORD, no_ui); } -int cryptfs_changepw(int crypt_type, const char* newpw) { +int cryptfs_changepw(int crypt_type, const char* currentpw, const char* newpw) { if (fscrypt_is_native()) { SLOGE("cryptfs_changepw not valid for file encryption"); return -1; @@ -2492,10 +2862,33 @@ int cryptfs_changepw(int crypt_type, const char* newpw) { return -1; } +#ifdef CONFIG_HW_DISK_ENCRYPTION + if(is_hw_disk_encryption((char*)crypt_ftr.crypto_type_name)) + return cryptfs_changepw_hw_fde(crypt_type, currentpw, newpw); + else { + crypt_ftr.crypt_type = crypt_type; + + rc = encrypt_master_key(crypt_type == CRYPT_TYPE_DEFAULT ? + DEFAULT_PASSWORD : newpw, + crypt_ftr.salt, + saved_master_key, + crypt_ftr.master_key, + &crypt_ftr, false); + if (rc) { + SLOGE("Encrypt master key failed: %d", rc); + return -1; + } + /* save the key */ + put_crypt_ftr_and_key(&crypt_ftr); + + return 0; + } +#else crypt_ftr.crypt_type = crypt_type; rc = encrypt_master_key(crypt_type == CRYPT_TYPE_DEFAULT ? DEFAULT_PASSWORD : newpw, - crypt_ftr.salt, saved_master_key, crypt_ftr.master_key, &crypt_ftr); + crypt_ftr.salt, saved_master_key, crypt_ftr.master_key, &crypt_ftr, + false); if (rc) { SLOGE("Encrypt master key failed: %d", rc); return -1; @@ -2504,8 +2897,57 @@ int cryptfs_changepw(int crypt_type, const char* newpw) { put_crypt_ftr_and_key(&crypt_ftr); return 0; +#endif } +#ifdef CONFIG_HW_DISK_ENCRYPTION +int cryptfs_changepw_hw_fde(int crypt_type, const char *currentpw, const char *newpw) +{ + struct crypt_mnt_ftr crypt_ftr; + int rc; + int previous_type; + + /* get key */ + if (get_crypt_ftr_and_key(&crypt_ftr)) { + SLOGE("Error getting crypt footer and key"); + return -1; + } + + previous_type = crypt_ftr.crypt_type; + int rc1; + unsigned char tmp_curpw[32] = {0}; + rc1 = get_keymaster_hw_fde_passwd(crypt_ftr.crypt_type == CRYPT_TYPE_DEFAULT ? + DEFAULT_PASSWORD : currentpw, tmp_curpw, + crypt_ftr.salt, &crypt_ftr); + + crypt_ftr.crypt_type = crypt_type; + + int ret, rc2; + unsigned char tmp_newpw[32] = {0}; + + rc2 = get_keymaster_hw_fde_passwd(crypt_type == CRYPT_TYPE_DEFAULT ? + DEFAULT_PASSWORD : newpw , tmp_newpw, + crypt_ftr.salt, &crypt_ftr); + + if (is_hw_disk_encryption((char*)crypt_ftr.crypto_type_name)) { + ret = update_hw_device_encryption_key( + rc1 ? (previous_type == CRYPT_TYPE_DEFAULT ? DEFAULT_PASSWORD : currentpw) : (const char*)tmp_curpw, + rc2 ? (crypt_type == CRYPT_TYPE_DEFAULT ? DEFAULT_PASSWORD : newpw): (const char*)tmp_newpw, + (char*)crypt_ftr.crypto_type_name); + if (ret) { + SLOGE("Error updating device encryption hardware key ret %d", ret); + return -1; + } else { + SLOGI("Encryption hardware key updated"); + } + } + + /* save the key */ + put_crypt_ftr_and_key(&crypt_ftr); + return 0; +} +#endif + static unsigned int persist_get_max_entries(int encrypted) { struct crypt_mnt_ftr crypt_ftr; unsigned int dsize; @@ -2897,3 +3339,62 @@ int cryptfs_isConvertibleToFBE() { auto entry = GetEntryForMountPoint(&fstab_default, DATA_MNT_POINT); return entry && entry->fs_mgr_flags.force_fde_or_fbe; } + +int cryptfs_create_default_ftr(struct crypt_mnt_ftr* crypt_ftr, __attribute__((unused))int key_length) +{ + if (cryptfs_init_crypt_mnt_ftr(crypt_ftr)) { + SLOGE("Failed to initialize crypt_ftr"); + return -1; + } + + if (create_encrypted_random_key(DEFAULT_PASSWORD, crypt_ftr->master_key, + crypt_ftr->salt, crypt_ftr)) { + SLOGE("Cannot create encrypted master key\n"); + return -1; + } + + //crypt_ftr->keysize = key_length / 8; + return 0; +} + +int cryptfs_get_master_key(struct crypt_mnt_ftr* ftr, const char* password, + unsigned char* master_key) +{ + int rc; + + unsigned char* intermediate_key = 0; + size_t intermediate_key_size = 0; + + if (password == 0 || *password == 0) { + password = DEFAULT_PASSWORD; + } + + rc = decrypt_master_key(password, master_key, ftr, &intermediate_key, + &intermediate_key_size); + + if (rc) { + SLOGE("Can't calculate intermediate key"); + return rc; + } + + int N = 1 << ftr->N_factor; + int r = 1 << ftr->r_factor; + int p = 1 << ftr->p_factor; + + unsigned char scrypted_intermediate_key[sizeof(ftr->scrypted_intermediate_key)]; + + rc = crypto_scrypt(intermediate_key, intermediate_key_size, + ftr->salt, sizeof(ftr->salt), N, r, p, + scrypted_intermediate_key, + sizeof(scrypted_intermediate_key)); + + free(intermediate_key); + + if (rc) { + SLOGE("Can't scrypt intermediate key"); + return rc; + } + + return memcmp(scrypted_intermediate_key, ftr->scrypted_intermediate_key, + intermediate_key_size); +} diff --git a/cryptfs.h b/cryptfs.h index 872806e..d9ccff9 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -30,6 +30,15 @@ #define CRYPT_FOOTER_OFFSET 0x4000 +#ifdef CONFIG_HW_DISK_ENCRYPTION +/* This flag is used to transition from L->M upgrade. L release passed + * a byte for every nible of user password while M release is passing + * ascii value of user password. + * Random flag value is chosen so that it does not conflict with other use cases + */ +#define CRYPT_ASCII_PASSWORD_UPDATED 0x1000 +#endif + /* Return values for cryptfs_crypto_complete */ #define CRYPTO_COMPLETE_NOT_ENCRYPTED 1 #define CRYPTO_COMPLETE_ENCRYPTED 0 @@ -63,7 +72,7 @@ int cryptfs_check_passwd(const char* pw); int cryptfs_verify_passwd(const char* pw); int cryptfs_restart(void); int cryptfs_enable(int type, const char* passwd, int no_ui); -int cryptfs_changepw(int type, const char* newpw); +int cryptfs_changepw(int type, const char* currentpw, const char* newpw); int cryptfs_enable_default(int no_ui); int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const android::vold::KeyBuffer& key, std::string* out_crypto_blkdev);