From ba95ad18ac950af740ef0938d178e0c18f789419 Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Mon, 18 Jan 2016 15:18:15 -0600 Subject: Update qcom hardware crypto code Change-Id: I4608c45b3f71b53e0988ca0248d3438110a40149 --- crypto/lollipop/cryptfs.c | 248 ++++++++++++++++++++++++++++++++++++---------- crypto/lollipop/cryptfs.h | 9 +- 2 files changed, 206 insertions(+), 51 deletions(-) diff --git a/crypto/lollipop/cryptfs.c b/crypto/lollipop/cryptfs.c index 515a06b2e..1e65a2263 100644 --- a/crypto/lollipop/cryptfs.c +++ b/crypto/lollipop/cryptfs.c @@ -100,6 +100,124 @@ static char key_fname[PROPERTY_VALUE_MAX] = ""; static char real_blkdev[PROPERTY_VALUE_MAX] = ""; static char file_system[PROPERTY_VALUE_MAX] = ""; +#ifdef CONFIG_HW_DISK_ENCRYPTION +#define DEFAULT_HEX_PASSWORD "64656661756c745f70617373776f7264" +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 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)) { + printf("scrypt failed"); + } else { + rc = 0; + } + } + + return rc; +} + +static int verify_hw_fde_passwd(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(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) { + printf("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) { + printf("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) { + printf("System out of memory. Password verification incomplete"); + goto out; + } + convert_key_to_hex_ascii((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; + printf("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; + printf("Ascii password recorded and updated"); + } else { + printf("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: + // DO NOT update footer before leaving + // put_crypt_ftr_and_key(crypt_ftr); + return key_index; +} +#endif + void set_partition_data(const char* block_device, const char* key_location, const char* fs) { strcpy(key_fname, key_location); @@ -869,23 +987,22 @@ static unsigned char* convert_hex_ascii_to_key(const char* master_key_ascii, /* Convert a binary key of specified length into an ascii hex string equivalent, * without the leading 0x and with null termination */ -static void convert_key_to_hex_ascii(unsigned char *master_key, unsigned int keysize, - char *master_key_ascii) -{ - unsigned int i, a; - unsigned char nibble; +static void convert_key_to_hex_ascii(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> 4) & 0xf; - master_key_ascii[a] = nibble + (nibble > 9 ? 0x37 : 0x30); + for (i=0, a=0; i> 4) & 0xf; + master_key_ascii[a] = nibble + (nibble > 9 ? 0x37 : 0x30); - nibble = master_key[i] & 0xf; - master_key_ascii[a+1] = nibble + (nibble > 9 ? 0x37 : 0x30); - } + nibble = master_key[i] & 0xf; + master_key_ascii[a+1] = nibble + (nibble > 9 ? 0x37 : 0x30); + } - /* Add the null termination */ - master_key_ascii[a] = '\0'; + /* Add the null termination */ + master_key_ascii[a] = '\0'; } @@ -911,15 +1028,20 @@ static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, unsigned c tgt->sector_start = 0; tgt->length = crypt_ftr->fs_size; #ifdef CONFIG_HW_DISK_ENCRYPTION - if(is_hw_disk_encryption((char*)crypt_ftr->crypto_type_name) && is_hw_fde_enabled()) { - printf("load_crypto_mapping_table using req-crypt\n"); - strlcpy(tgt->target_type, "req-crypt",DM_MAX_TYPE_NAME); - } else { - printf("load_crypto_mapping_table using crypt\n"); - strlcpy(tgt->target_type, "crypt", DM_MAX_TYPE_NAME); - } + if(is_hw_disk_encryption((char*)crypt_ftr->crypto_type_name)) { + strlcpy(tgt->target_type, "req-crypt",DM_MAX_TYPE_NAME); + if (is_ice_enabled()) + convert_key_to_hex_ascii(master_key, sizeof(int), master_key_ascii); + else + convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii); + } + else { + convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii); + strlcpy(tgt->target_type, "crypt", DM_MAX_TYPE_NAME); + } #else - strcpy(tgt->target_type, "crypt"); + convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii); + strlcpy(tgt->target_type, "crypt", DM_MAX_TYPE_NAME); #endif crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec); @@ -1037,28 +1159,27 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor); #ifdef CONFIG_HW_DISK_ENCRYPTION - if (is_hw_fde_enabled() && is_hw_disk_encryption((char*) crypt_ftr->crypto_type_name)) { - /* Set fde_enabled if either FDE completed or in-progress */ - property_get("ro.crypto.state", encrypted_state, ""); /* FDE completed */ - property_get("vold.encrypt_progress", progress, ""); /* FDE in progress */ - if (!strcmp(encrypted_state, "encrypted") || strcmp(progress, "")) { - extra_params = "fde_enabled"; - printf("create_crypto_blk_dev extra_params set to fde_enabled\n"); - } else { - extra_params = "fde_disabled"; - printf("create_crypto_blk_dev extra_params set to fde_disabled\n"); - } + if(is_hw_disk_encryption((char*)crypt_ftr->crypto_type_name)) { + /* Set fde_enabled if either FDE completed or in-progress */ + property_get("ro.crypto.state", encrypted_state, ""); /* FDE completed */ + property_get("vold.encrypt_progress", progress, ""); /* FDE in progress */ + if (!strcmp(encrypted_state, "encrypted") || strcmp(progress, "")) { + if (is_ice_enabled()) + extra_params = "fde_enabled ice"; + else + extra_params = "fde_enabled"; + } else + extra_params = "fde_disabled"; } else { - extra_params = ""; - printf("create_crypto_blk_dev extra_params set to empty string\n"); - if (!get_dm_crypt_version(fd, name, version)) { - /* Support for allow_discards was added in version 1.11.0 */ - if ((version[0] >= 2) || - ((version[0] == 1) && (version[1] >= 11))) { - extra_params = "1 allow_discards"; - printf("Enabling support for allow_discards in dmcrypt.\n"); - } + extra_params = ""; + if (! get_dm_crypt_version(fd, name, version)) { + /* Support for allow_discards was added in version 1.11.0 */ + if ((version[0] >= 2) || + ((version[0] == 1) && (version[1] >= 11))) { + extra_params = "1 allow_discards"; + printf("Enabling support for allow_discards in dmcrypt.\n"); } + } } #else extra_params = ""; @@ -1422,17 +1543,43 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, } #ifdef CONFIG_HW_DISK_ENCRYPTION - if (is_hw_fde_enabled()) { - if(is_hw_disk_encryption((char*) crypt_ftr->crypto_type_name)) { - if (!set_hw_device_encryption_key(passwd, (char*) crypt_ftr->crypto_type_name)) { - rc = -1; - printf("Failed to set_hw_device_encryption_key\n"); - goto errout; + 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)) { + printf("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)) { + printf("Error creating decrypted block device"); + rc = -1; + goto errout; + } } } + } else { + /* in case HW FDE is delivered through OTA and device is already encrypted + * using SW FDE, we should let user continue using SW FDE until userdata is + * wiped. + */ + if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key, + real_blkdev, crypto_blkdev, label)) { + printf("Error creating decrypted block device"); + rc = -1; + goto errout; + } } -#endif - +#else // Create crypto block device - all (non fatal) code paths // need it if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key, @@ -1441,6 +1588,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, rc = -1; goto errout; } +#endif /* Work out if the problem is the password or the data */ unsigned char scrypted_intermediate_key[sizeof(crypt_ftr-> diff --git a/crypto/lollipop/cryptfs.h b/crypto/lollipop/cryptfs.h index bc8b463ee..67ebbba95 100644 --- a/crypto/lollipop/cryptfs.h +++ b/crypto/lollipop/cryptfs.h @@ -52,7 +52,14 @@ correctly marked partial encryption */ #define CRYPT_DATA_CORRUPT 0x8 /* Set when encryption is fine, but the underlying volume is corrupt */ - +#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 /* Allowed values for type in the structure below */ #define CRYPT_TYPE_PASSWORD 0 /* master_key is encrypted with a password * Must be zero to be compatible with pre-L -- cgit v1.2.3