cryptfs: major overhaul and cleanup
- Don't upgrade HW encrypted Lollipop devices to Marshmallow crypto - Fix support for passwords and patterns with an odd number of elements - Remove unused code - Fix build warnings Change-Id: I25f015085e5c859d0353f42f6a2fbc7ccecd48ed
This commit is contained in:
+31
-574
@@ -74,9 +74,6 @@
|
||||
|
||||
#define KEY_IN_FOOTER "footer"
|
||||
|
||||
// "default_password" encoded into hex (d=0x64 etc)
|
||||
#define DEFAULT_PASSWORD "64656661756c745f70617373776f7264"
|
||||
|
||||
#define EXT4_FS 1
|
||||
#define F2FS_FS 2
|
||||
|
||||
@@ -101,13 +98,10 @@ 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)
|
||||
@@ -140,82 +134,6 @@ static int verify_hw_fde_passwd(char *passwd, struct crypt_mnt_ftr* crypt_ftr)
|
||||
(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)
|
||||
@@ -853,23 +771,6 @@ static int get_crypt_ftr_info(char **metadata_fname, off64_t *off)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int unix_read(int fd, void* buff, int len)
|
||||
{
|
||||
return TEMP_FAILURE_RETRY(read(fd, buff, len));
|
||||
}
|
||||
|
||||
static inline int unix_write(int fd, const void* buff, int len)
|
||||
{
|
||||
return TEMP_FAILURE_RETRY(write(fd, buff, len));
|
||||
}
|
||||
|
||||
static void init_empty_persist_data(struct crypt_persist_data *pdata, int len)
|
||||
{
|
||||
memset(pdata, 0, len);
|
||||
pdata->persist_magic = PERSIST_DATA_MAGIC;
|
||||
pdata->persist_valid_entries = 0;
|
||||
}
|
||||
|
||||
static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr)
|
||||
{
|
||||
int fd;
|
||||
@@ -941,49 +842,6 @@ errout:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int hexdigit (char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
c = tolower(c);
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned char* convert_hex_ascii_to_key(const char* master_key_ascii,
|
||||
unsigned int* out_keysize)
|
||||
{
|
||||
unsigned int i;
|
||||
*out_keysize = 0;
|
||||
|
||||
size_t size = strlen (master_key_ascii);
|
||||
if (size % 2) {
|
||||
printf("Trying to convert ascii string of odd length\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char* master_key = (unsigned char*) malloc(size / 2);
|
||||
if (master_key == 0) {
|
||||
printf("Cannot allocate\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += 2) {
|
||||
int high_nibble = hexdigit (master_key_ascii[i]);
|
||||
int low_nibble = hexdigit (master_key_ascii[i + 1]);
|
||||
|
||||
if(high_nibble < 0 || low_nibble < 0) {
|
||||
printf("Invalid hex string\n");
|
||||
free (master_key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
master_key[*out_keysize] = high_nibble * 16 + low_nibble;
|
||||
(*out_keysize)++;
|
||||
}
|
||||
|
||||
return master_key;
|
||||
}
|
||||
|
||||
/* Convert a binary key of specified length into an ascii hex string equivalent,
|
||||
* without the leading 0x and with null termination
|
||||
*/
|
||||
@@ -1006,8 +864,8 @@ static void convert_key_to_hex_ascii(const unsigned char *master_key,
|
||||
|
||||
}
|
||||
|
||||
static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
|
||||
char *real_blk_name, const char *name, int fd,
|
||||
static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, const unsigned char *master_key,
|
||||
const char *real_blk_name, const char *name, int fd,
|
||||
char *extra_params)
|
||||
{
|
||||
char buffer[DM_CRYPT_BUF_SIZE];
|
||||
@@ -1117,8 +975,8 @@ static int get_dm_crypt_version(int fd, const char *name, int *version)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
|
||||
char *real_blk_name, char *crypto_blk_name, const char *name)
|
||||
static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, const unsigned char *master_key,
|
||||
const char *real_blk_name, char *crypto_blk_name, const char *name)
|
||||
{
|
||||
char buffer[DM_CRYPT_BUF_SIZE];
|
||||
char master_key_ascii[129]; /* Large enough to hold 512 bit key and null */
|
||||
@@ -1256,14 +1114,9 @@ static int pbkdf2(const char *passwd, const unsigned char *salt,
|
||||
printf("Using pbkdf2 for cryptfs KDF\n");
|
||||
|
||||
/* Turn the password into a key and IV that can decrypt the master key */
|
||||
unsigned int keysize;
|
||||
char* master_key = (char*)convert_hex_ascii_to_key(passwd, &keysize);
|
||||
if (!master_key) return -1;
|
||||
PKCS5_PBKDF2_HMAC_SHA1(master_key, keysize, salt, SALT_LEN,
|
||||
PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), salt, SALT_LEN,
|
||||
HASH_COUNT, KEY_LEN_BYTES+IV_LEN_BYTES, ikey);
|
||||
|
||||
memset(master_key, 0, keysize);
|
||||
free (master_key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1279,14 +1132,9 @@ static int scrypt(const char *passwd, const unsigned char *salt,
|
||||
int p = 1 << ftr->p_factor;
|
||||
|
||||
/* Turn the password into a key and IV that can decrypt the master key */
|
||||
unsigned int keysize;
|
||||
unsigned char* master_key = convert_hex_ascii_to_key(passwd, &keysize);
|
||||
if (!master_key) return -1;
|
||||
crypto_scrypt(master_key, keysize, salt, SALT_LEN, N, r, p, ikey,
|
||||
KEY_LEN_BYTES + IV_LEN_BYTES);
|
||||
crypto_scrypt((const uint8_t *)passwd, strlen(passwd), salt, SALT_LEN,
|
||||
N, r, p, ikey, KEY_LEN_BYTES + IV_LEN_BYTES);
|
||||
|
||||
memset(master_key, 0, keysize);
|
||||
free (master_key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1305,16 +1153,8 @@ static int scrypt_keymaster(const char *passwd, const unsigned char *salt,
|
||||
int r = 1 << ftr->r_factor;
|
||||
int p = 1 << ftr->p_factor;
|
||||
|
||||
unsigned char* master_key = convert_hex_ascii_to_key(passwd, &key_size);
|
||||
if (!master_key) {
|
||||
printf("Failed to convert passwd from hex\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = crypto_scrypt(master_key, key_size, salt, SALT_LEN,
|
||||
rc = crypto_scrypt((const uint8_t *)passwd, strlen(passwd), salt, SALT_LEN,
|
||||
N, r, p, ikey, KEY_LEN_BYTES + IV_LEN_BYTES);
|
||||
memset(master_key, 0, key_size);
|
||||
free(master_key);
|
||||
|
||||
if (rc) {
|
||||
printf("scrypt failed\n");
|
||||
@@ -1339,94 +1179,6 @@ static int scrypt_keymaster(const char *passwd, const unsigned char *salt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */
|
||||
EVP_CIPHER_CTX e_ctx;
|
||||
int encrypted_len, final_len;
|
||||
int rc = 0;
|
||||
|
||||
/* Turn the password into an intermediate key and IV that can decrypt the master key */
|
||||
get_device_scrypt_params(crypt_ftr);
|
||||
|
||||
switch (crypt_ftr->kdf_type) {
|
||||
case KDF_SCRYPT_KEYMASTER_UNPADDED:
|
||||
case KDF_SCRYPT_KEYMASTER_BADLY_PADDED:
|
||||
case KDF_SCRYPT_KEYMASTER:
|
||||
if (keymaster_create_key(crypt_ftr)) {
|
||||
printf("keymaster_create_key failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (scrypt_keymaster(passwd, salt, ikey, crypt_ftr)) {
|
||||
printf("scrypt failed\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case KDF_SCRYPT:
|
||||
if (scrypt(passwd, salt, ikey, crypt_ftr)) {
|
||||
printf("scrypt failed\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Invalid kdf_type\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize the decryption engine */
|
||||
if (! EVP_EncryptInit(&e_ctx, EVP_aes_128_cbc(), ikey, ikey+KEY_LEN_BYTES)) {
|
||||
printf("EVP_EncryptInit failed\n");
|
||||
return -1;
|
||||
}
|
||||
EVP_CIPHER_CTX_set_padding(&e_ctx, 0); /* Turn off padding as our data is block aligned */
|
||||
|
||||
/* Encrypt the master key */
|
||||
if (! EVP_EncryptUpdate(&e_ctx, encrypted_master_key, &encrypted_len,
|
||||
decrypted_master_key, KEY_LEN_BYTES)) {
|
||||
printf("EVP_EncryptUpdate failed\n");
|
||||
return -1;
|
||||
}
|
||||
#ifndef TW_CRYPTO_HAVE_KEYMASTERX
|
||||
if (! EVP_EncryptFinal(&e_ctx, encrypted_master_key + encrypted_len, &final_len)) {
|
||||
#else
|
||||
if (! EVP_EncryptFinal_ex(&e_ctx, encrypted_master_key + encrypted_len, &final_len)) {
|
||||
#endif
|
||||
printf("EVP_EncryptFinal failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (encrypted_len + final_len != KEY_LEN_BYTES) {
|
||||
printf("EVP_Encryption length check failed with %d, %d bytes\n", encrypted_len, final_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Store the scrypt of the intermediate key, so we can validate if it's a
|
||||
password error or mount error when things go wrong.
|
||||
Note there's no need to check for errors, since if this is incorrect, we
|
||||
simply won't wipe userdata, which is the correct default behavior
|
||||
*/
|
||||
int N = 1 << crypt_ftr->N_factor;
|
||||
int r = 1 << crypt_ftr->r_factor;
|
||||
int p = 1 << crypt_ftr->p_factor;
|
||||
|
||||
rc = crypto_scrypt(ikey, KEY_LEN_BYTES,
|
||||
crypt_ftr->salt, sizeof(crypt_ftr->salt), N, r, p,
|
||||
crypt_ftr->scrypted_intermediate_key,
|
||||
sizeof(crypt_ftr->scrypted_intermediate_key));
|
||||
|
||||
if (rc) {
|
||||
printf("encrypt_master_key: crypto_scrypt failed\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decrypt_master_key_aux(char *passwd, unsigned char *salt,
|
||||
unsigned char *encrypted_master_key,
|
||||
unsigned char *decrypted_master_key,
|
||||
@@ -1522,7 +1274,6 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr,
|
||||
unsigned char decrypted_master_key[32];
|
||||
char crypto_blkdev[MAXPATHLEN];
|
||||
char tmp_mount_point[64];
|
||||
unsigned int orig_failed_decrypt_count;
|
||||
int rc = 0;
|
||||
kdf_func kdf;
|
||||
void *kdf_params;
|
||||
@@ -1532,7 +1283,6 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr,
|
||||
size_t intermediate_key_size = 0;
|
||||
|
||||
printf("crypt_ftr->fs_size = %lld\n", crypt_ftr->fs_size);
|
||||
orig_failed_decrypt_count = crypt_ftr->failed_decrypt_count;
|
||||
|
||||
if (! (crypt_ftr->flags & CRYPT_MNT_KEY_UNENCRYPTED) ) {
|
||||
if (decrypt_master_key(passwd, decrypted_master_key, crypt_ftr,
|
||||
@@ -1546,9 +1296,10 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr,
|
||||
#ifdef CONFIG_HW_DISK_ENCRYPTION
|
||||
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);
|
||||
key_index = verify_hw_fde_passwd(passwd, crypt_ftr);
|
||||
|
||||
if (key_index < 0) {
|
||||
rc = crypt_ftr->failed_decrypt_count;
|
||||
rc = 1;
|
||||
goto errout;
|
||||
}
|
||||
else {
|
||||
@@ -1617,9 +1368,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr,
|
||||
if (mount(crypto_blkdev, tmp_mount_point, file_system, 0, NULL) != 0) {
|
||||
printf("Error temp mounting decrypted block device '%s'\n", crypto_blkdev);
|
||||
delete_crypto_blk_dev(label);
|
||||
|
||||
rc = ++crypt_ftr->failed_decrypt_count;
|
||||
//put_crypt_ftr_and_key(crypt_ftr); // Do not penalize for attempting to decrypt in recovery
|
||||
rc = 1;
|
||||
} else {
|
||||
/* Success! */
|
||||
printf("Password did not match but decrypted drive mounted - continue\n");
|
||||
@@ -1629,54 +1378,14 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr,
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
/*crypt_ftr->failed_decrypt_count = 0;
|
||||
if (orig_failed_decrypt_count != 0) {
|
||||
put_crypt_ftr_and_key(crypt_ftr);
|
||||
}*/
|
||||
// Don't increment the failed attempt counter as it doesn't
|
||||
// make sense to do so in TWRP
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Also save a the master key so we can reencrypted the key
|
||||
* the key when we want to change the password on it. */
|
||||
/*memcpy(saved_master_key, decrypted_master_key, KEY_LEN_BYTES);
|
||||
saved_mount_point = strdup(mount_point);
|
||||
master_key_saved = 1;
|
||||
printf("%s(): Master key saved\n", __FUNCTION__);*/
|
||||
rc = 0;
|
||||
|
||||
// Upgrade if we're not using the latest KDF.
|
||||
/*use_keymaster = keymaster_check_compatibility();
|
||||
if (crypt_ftr->kdf_type == KDF_SCRYPT_KEYMASTER) {
|
||||
// Don't allow downgrade
|
||||
} else if (use_keymaster == 1 && crypt_ftr->kdf_type != KDF_SCRYPT_KEYMASTER) {
|
||||
crypt_ftr->kdf_type = KDF_SCRYPT_KEYMASTER;
|
||||
upgrade = 1;
|
||||
} else if (use_keymaster == 0 && crypt_ftr->kdf_type != KDF_SCRYPT) {
|
||||
crypt_ftr->kdf_type = KDF_SCRYPT;
|
||||
upgrade = 1;
|
||||
}
|
||||
|
||||
if (upgrade) {
|
||||
rc = encrypt_master_key(passwd, crypt_ftr->salt, saved_master_key,
|
||||
crypt_ftr->master_key, crypt_ftr);
|
||||
if (!rc) {
|
||||
rc = put_crypt_ftr_and_key(crypt_ftr);
|
||||
}
|
||||
printf("Key Derivation Function upgrade: rc=%d\n", rc);
|
||||
|
||||
// Do not fail even if upgrade failed - machine is bootable
|
||||
// Note that if this code is ever hit, there is a *serious* problem
|
||||
// since KDFs should never fail. You *must* fix the kdf before
|
||||
// proceeding!
|
||||
if (rc) {
|
||||
printf("Upgrade failed with error %d,"
|
||||
" but continuing with previous state\n",
|
||||
rc);
|
||||
rc = 0;
|
||||
}
|
||||
}*/
|
||||
// TWRP shouldn't change the stored key
|
||||
}
|
||||
|
||||
errout:
|
||||
@@ -1687,15 +1396,6 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Called by vold when it wants to undo the crypto mapping of a volume it
|
||||
* manages. This is usually in response to a factory reset, when we want
|
||||
* to undo the crypto mapping so the volume is formatted in the clear.
|
||||
*/
|
||||
int cryptfs_revert_volume(const char *label)
|
||||
{
|
||||
return delete_crypto_blk_dev((char *)label);
|
||||
}
|
||||
|
||||
int check_unmounted_and_get_ftr(struct crypt_mnt_ftr* crypt_ftr)
|
||||
{
|
||||
char encrypted_state[PROPERTY_VALUE_MAX];
|
||||
@@ -1714,107 +1414,6 @@ int check_unmounted_and_get_ftr(struct crypt_mnt_ftr* crypt_ftr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO - transition patterns to new format in calling code
|
||||
* and remove this vile hack, and the use of hex in
|
||||
* the password passing code.
|
||||
*
|
||||
* Patterns are passed in zero based (i.e. the top left dot
|
||||
* is represented by zero, the top middle one etc), but we want
|
||||
* to store them '1' based.
|
||||
* This is to allow us to migrate the calling code to use this
|
||||
* convention. It also solves a nasty problem whereby scrypt ignores
|
||||
* trailing zeros, so patterns ending at the top left could be
|
||||
* truncated, and similarly, you could add the top left to any
|
||||
* pattern and still match.
|
||||
* adjust_passwd is a hack function that returns the alternate representation
|
||||
* if the password appears to be a pattern (hex numbers all less than 09)
|
||||
* If it succeeds we need to try both, and in particular try the alternate
|
||||
* first. If the original matches, then we need to update the footer
|
||||
* with the alternate.
|
||||
* All code that accepts passwords must adjust them first. Since
|
||||
* cryptfs_check_passwd is always the first function called after a migration
|
||||
* (and indeed on any boot) we only need to do the double try in this
|
||||
* function.
|
||||
*/
|
||||
char* adjust_passwd(const char* passwd)
|
||||
{
|
||||
size_t index, length;
|
||||
|
||||
if (!passwd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check even length. Hex encoded passwords are always
|
||||
// an even length, since each character encodes to two characters.
|
||||
length = strlen(passwd);
|
||||
if (length % 2) {
|
||||
printf("Password not correctly hex encoded.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check password is old-style pattern - a collection of hex
|
||||
// encoded bytes less than 9 (00 through 08)
|
||||
for (index = 0; index < length; index +=2) {
|
||||
if (passwd[index] != '0'
|
||||
|| passwd[index + 1] < '0' || passwd[index + 1] > '8') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate room for adjusted passwd and null terminate
|
||||
char* adjusted = malloc(length + 1);
|
||||
adjusted[length] = 0;
|
||||
|
||||
// Add 0x31 ('1') to each character
|
||||
for (index = 0; index < length; index += 2) {
|
||||
// output is 31 through 39 so set first byte to three, second to src + 1
|
||||
adjusted[index] = '3';
|
||||
adjusted[index + 1] = passwd[index + 1] + 1;
|
||||
}
|
||||
|
||||
return adjusted;
|
||||
}
|
||||
|
||||
/*
|
||||
* Passwords in L get passed from Android to cryptfs in hex, so a '1'
|
||||
* gets converted to '31' where 31 is 0x31 which is the ascii character
|
||||
* code in hex of the character '1'. This function will convert the
|
||||
* regular character codes to their hexadecimal representation to make
|
||||
* decrypt work properly with Android 5.0 lollipop decryption.
|
||||
*/
|
||||
char* hexadj_passwd(const char* passwd, int has_hw_crypto)
|
||||
{
|
||||
size_t index, length;
|
||||
const char* ptr = passwd;
|
||||
|
||||
if (!passwd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = strlen(passwd);
|
||||
|
||||
// Allocate room for hex passwd and null terminate
|
||||
char* hex = malloc((length * 2) + 1);
|
||||
hex[length * 2] = 0;
|
||||
|
||||
// Convert to hex
|
||||
for (index = 0; index < length; index++) {
|
||||
sprintf(hex + (index * 2), "%02X", *ptr);
|
||||
ptr++;
|
||||
}
|
||||
#ifdef CONFIG_HW_DISK_ENCRYPTION
|
||||
if (has_hw_crypto) {
|
||||
printf("hexadj_passwd converting to lower case for hardware disk crypto.\n");
|
||||
length *= 2;
|
||||
for (index = 0; index < length; index++) {
|
||||
hex[index] = tolower(hex[index]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return hex;
|
||||
}
|
||||
|
||||
int cryptfs_check_footer()
|
||||
{
|
||||
int rc = -1;
|
||||
@@ -1829,178 +1428,36 @@ int cryptfs_check_passwd(char *passwd)
|
||||
{
|
||||
struct crypt_mnt_ftr crypt_ftr;
|
||||
int rc;
|
||||
int has_hw_crypto = 0;
|
||||
|
||||
if (!passwd) {
|
||||
printf("cryptfs_check_passwd: passwd is NULL!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = check_unmounted_and_get_ftr(&crypt_ftr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
#ifdef CONFIG_HW_DISK_ENCRYPTION
|
||||
printf("CONFIG_HW_DISK_ENCRYPTION present\n");
|
||||
if (is_hw_fde_enabled() && is_hw_disk_encryption((char*) crypt_ftr.crypto_type_name))
|
||||
has_hw_crypto = 1;
|
||||
#endif
|
||||
rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
|
||||
DATA_MNT_POINT, "userdata");
|
||||
|
||||
//if (passwd) printf("passwd: '%s'\n", passwd);
|
||||
char* adjusted_passwd;
|
||||
if (!has_hw_crypto)
|
||||
adjusted_passwd = adjust_passwd(passwd);
|
||||
//if (adjusted_passwd) printf("adjusted_passwd: '%s'\n", adjusted_passwd);
|
||||
char* hex_passwd = hexadj_passwd(passwd, has_hw_crypto);
|
||||
//if (hex_passwd) printf("hex_passwd: '%s'\n", hex_passwd);
|
||||
printf("has_hw_crypto is %i\n", has_hw_crypto);
|
||||
if (!has_hw_crypto && adjusted_passwd) {
|
||||
int failed_decrypt_count = crypt_ftr.failed_decrypt_count;
|
||||
//printf("trying adjusted password '%s'\n", adjusted_passwd);
|
||||
rc = test_mount_encrypted_fs(&crypt_ftr, hex_passwd,
|
||||
DATA_MNT_POINT, "userdata");
|
||||
|
||||
// Maybe the original one still works?
|
||||
if (rc) {
|
||||
// Don't double count this failure
|
||||
//printf("trying passwd '%s'\n", passwd);
|
||||
crypt_ftr.failed_decrypt_count = failed_decrypt_count;
|
||||
rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
|
||||
DATA_MNT_POINT, "userdata");
|
||||
if (!rc) {
|
||||
// cryptfs_changepw also adjusts so pass original
|
||||
// Note that adjust_passwd only recognises patterns
|
||||
// so we can safely use CRYPT_TYPE_PATTERN
|
||||
printf("TWRP NOT Updating pattern to new format\n");
|
||||
//cryptfs_changepw(CRYPT_TYPE_PATTERN, passwd);
|
||||
} else if (hex_passwd) {
|
||||
//printf("trying hex_passwd '%s'\n", hex_passwd);
|
||||
rc = test_mount_encrypted_fs(&crypt_ftr, hex_passwd,
|
||||
DATA_MNT_POINT, "userdata");
|
||||
}
|
||||
}
|
||||
free(adjusted_passwd);
|
||||
} else {
|
||||
// try falling back to Lollipop hex passwords
|
||||
if (rc) {
|
||||
int hex_pass_len = strlen(passwd) * 2 + 1;
|
||||
char *hex_passwd = (char *)malloc(hex_pass_len);
|
||||
if (hex_passwd) {
|
||||
//printf("2trying hex_passwd '%s'\n", hex_passwd);
|
||||
convert_key_to_hex_ascii((unsigned char *)passwd,
|
||||
strlen(passwd), hex_passwd);
|
||||
rc = test_mount_encrypted_fs(&crypt_ftr, hex_passwd,
|
||||
DATA_MNT_POINT, "userdata");
|
||||
} else {
|
||||
rc = 1;
|
||||
DATA_MNT_POINT, "userdata");
|
||||
memset(hex_passwd, 0, hex_pass_len);
|
||||
free(hex_passwd);
|
||||
}
|
||||
if (rc && passwd) {
|
||||
//printf("2trying passwd '%s'\n", passwd);
|
||||
rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
|
||||
DATA_MNT_POINT, "userdata");
|
||||
}
|
||||
}
|
||||
|
||||
if (hex_passwd)
|
||||
free(hex_passwd);
|
||||
|
||||
/*if (rc == 0 && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) {
|
||||
printf("cryptfs_check_passwd update expiry time?\n");
|
||||
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;
|
||||
}
|
||||
|
||||
int cryptfs_verify_passwd(char *passwd)
|
||||
{
|
||||
struct crypt_mnt_ftr crypt_ftr;
|
||||
/* Allocate enough space for a 256 bit key, but we may use less */
|
||||
unsigned char decrypted_master_key[32];
|
||||
char encrypted_state[PROPERTY_VALUE_MAX];
|
||||
int rc;
|
||||
|
||||
property_get("ro.crypto.state", encrypted_state, "");
|
||||
if (strcmp(encrypted_state, "encrypted") ) {
|
||||
printf("device not encrypted, aborting\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (!master_key_saved) {
|
||||
printf("encrypted fs not yet mounted, aborting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!saved_mount_point) {
|
||||
printf("encrypted fs failed to save mount point, aborting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_crypt_ftr_and_key(&crypt_ftr)) {
|
||||
printf("Error getting crypt footer and key\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (crypt_ftr.flags & CRYPT_MNT_KEY_UNENCRYPTED) {
|
||||
/* If the device has no password, then just say the password is valid */
|
||||
rc = 0;
|
||||
} else {
|
||||
char* adjusted_passwd = adjust_passwd(passwd);
|
||||
if (adjusted_passwd) {
|
||||
passwd = adjusted_passwd;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
free(adjusted_passwd);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Initialize a crypt_mnt_ftr structure. The keysize is
|
||||
* defaulted to 16 bytes, and the filesystem size to 0.
|
||||
* Presumably, at a minimum, the caller will update the
|
||||
* filesystem size and crypto_type_name after calling this function.
|
||||
*/
|
||||
static int cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr)
|
||||
{
|
||||
off64_t off;
|
||||
|
||||
memset(ftr, 0, sizeof(struct crypt_mnt_ftr));
|
||||
ftr->magic = CRYPT_MNT_MAGIC;
|
||||
ftr->major_version = CURRENT_MAJOR_VERSION;
|
||||
ftr->minor_version = CURRENT_MINOR_VERSION;
|
||||
ftr->ftr_size = sizeof(struct crypt_mnt_ftr);
|
||||
ftr->keysize = KEY_LEN_BYTES;
|
||||
|
||||
switch (keymaster_check_compatibility()) {
|
||||
case 1:
|
||||
ftr->kdf_type = KDF_SCRYPT_KEYMASTER;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
ftr->kdf_type = KDF_SCRYPT;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("keymaster_check_compatibility failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
get_device_scrypt_params(ftr);
|
||||
|
||||
ftr->persist_data_size = CRYPT_PERSIST_DATA_SIZE;
|
||||
if (get_crypt_ftr_info(NULL, &off) == 0) {
|
||||
ftr->persist_data_offset[0] = off + CRYPT_FOOTER_TO_PERSIST_OFFSET;
|
||||
ftr->persist_data_offset[1] = off + CRYPT_FOOTER_TO_PERSIST_OFFSET +
|
||||
ftr->persist_data_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns type of the password, default, pattern, pin or password.
|
||||
*/
|
||||
int cryptfs_get_password_type(void)
|
||||
|
||||
Reference in New Issue
Block a user