From 253368a0726120efa57664cdd1d088af099a3d81 Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Tue, 25 Nov 2014 15:00:52 -0600 Subject: Reduce libs needed for decrypt and clean up old decypt files Trim cryptfs.c to remove functions that TWRP does not use for decrypt and remove the need for libfs_mgr from cryptfs.c by passing some items to cryptfs.c from the partition manager. Add support for new fstab flags: encryptable and forceencrypt=/path/to/cryptokey For example: flags=forceencrypt=/dev/block/platform/sdhci-tegra.3/by-name/MD1 Note that "footer" is the default, so you do not need to set this flag on devices that use the footer for the crypto key. Also add mounttodecrypt if you need to mount a partition during the decrypt cycle for firmware of proprietary libs. Clean up decrypt and only support one version Android 5.0 lollipop decrypt should be backwards compatible with older versions so we will only support one version, 1.3 that came with 5.0 lollipop. Remove support for Samsung TouchWiz decrypt. It does not work with the latest versions of Samsung encryption anyway and it has not been updated to work with any AOSP decryption higher than 1.1 Change-Id: I2d9c6e31df50268c91ee642c2fa090f901d9d5c9 --- crypto/lollipop/Android.mk | 26 +- crypto/lollipop/cryptfs.c | 2299 ++------------------------------------------ crypto/lollipop/cryptfs.h | 17 +- 3 files changed, 87 insertions(+), 2255 deletions(-) (limited to 'crypto/lollipop') diff --git a/crypto/lollipop/Android.mk b/crypto/lollipop/Android.mk index 40b4d5f95..da25eac30 100644 --- a/crypto/lollipop/Android.mk +++ b/crypto/lollipop/Android.mk @@ -21,16 +21,17 @@ common_shared_libraries := \ libcutils \ liblog \ libdiskconfig \ - libhardware_legacy \ liblogwrap \ libext4_utils \ libf2fs_sparseblock \ libcrypto \ libselinux \ libutils \ - libhardware \ + libminhardware \ libsoftkeymaster +common_shared_libraries := libcrypto libselinux libhardware libsoftkeymaster libcutils + LOCAL_MODULE := libcryptfslollipop LOCAL_MODULE_TAGS := eng optional LOCAL_CFLAGS := @@ -44,9 +45,26 @@ LOCAL_SRC_FILES = cryptfs.c # hardware/libhardware/include/hardware \ # system/security/softkeymaster/include/keymaster #LOCAL_SHARED_LIBRARIES += libc liblog libcutils libcrypto libext4_utils -LOCAL_SHARED_LIBRARIES := $(common_shared_libraries) libmincrypttwrp liblogwrap +LOCAL_SHARED_LIBRARIES := $(common_shared_libraries) libmincrypttwrp LOCAL_C_INCLUDES := external/openssl/include $(common_c_includes) -LOCAL_WHOLE_STATIC_LIBRARIES += libfs_mgr libscrypt_static +LOCAL_WHOLE_STATIC_LIBRARIES += libscrypttwrp_static + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_SHARED_LIBRARIES := libcutils liblog + +LOCAL_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)\libminhardware + +LOCAL_CFLAGS += -DQEMU_HARDWARE +QEMU_HARDWARE := true + +LOCAL_SHARED_LIBRARIES += libdl + +LOCAL_SRC_FILES += libminhardware/hardware.c + +LOCAL_MODULE:= libminhardware include $(BUILD_SHARED_LIBRARY) endif diff --git a/crypto/lollipop/cryptfs.c b/crypto/lollipop/cryptfs.c index 0277c78ef..90f1523d3 100644 --- a/crypto/lollipop/cryptfs.c +++ b/crypto/lollipop/cryptfs.c @@ -37,27 +37,17 @@ #include #include #include -#include #include -#include #include #include "cryptfs.h" -#define LOG_TAG "Cryptfs" -#include "cutils/log.h" #include "cutils/properties.h" -#include "cutils/android_reboot.h" -#include "hardware_legacy/power.h" -#include -//#include "VolumeManager.h" -//#include "VoldUtil.h" #include "crypto_scrypt.h" -#include "ext4_utils.h" -#include "f2fs_sparseblock.h" -//#include "CheckBattery.h" -//#include "Process.h" - #include +#ifndef min /* already defined by windows.h */ +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + #define UNUSED __attribute__((unused)) #define UNUSED __attribute__((unused)) @@ -91,6 +81,16 @@ static unsigned char saved_master_key[KEY_LEN_BYTES]; static char *saved_mount_point; static int master_key_saved = 0; static struct crypt_persist_data *persist_data = NULL; +static char key_fname[PROPERTY_VALUE_MAX] = ""; +static char real_blkdev[PROPERTY_VALUE_MAX] = ""; +static char file_system[PROPERTY_VALUE_MAX] = ""; + +void set_partition_data(const char* block_device, const char* key_location, const char* fs) +{ + strcpy(key_fname, key_location); + strcpy(real_blkdev, block_device); + strcpy(file_system, fs); +} static int keymaster_init(keymaster_device_t **keymaster_dev) { @@ -291,31 +291,6 @@ static char* password = 0; static int password_expiry_time = 0; static const int password_max_age_seconds = 60; -struct fstab *fstab; - -enum RebootType {reboot, recovery, shutdown}; -static void cryptfs_reboot(enum RebootType rt) -{ - switch(rt) { - case reboot: - property_set(ANDROID_RB_PROPERTY, "reboot"); - break; - - case recovery: - property_set(ANDROID_RB_PROPERTY, "reboot,recovery"); - break; - - case shutdown: - property_set(ANDROID_RB_PROPERTY, "shutdown"); - break; - } - - sleep(20); - - /* Shouldn't get here, reboot should happen before sleep times out */ - return; -} - static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags) { memset(io, 0, dataSize); @@ -380,41 +355,6 @@ static void get_device_scrypt_params(struct crypt_mnt_ftr *ftr) { ftr->p_factor = params[2]; } -static unsigned int get_fs_size(char *dev) -{ - int fd, block_size; - struct ext4_super_block sb; - off64_t len; - - if ((fd = open(dev, O_RDONLY)) < 0) { - printf("Cannot open device to get filesystem size "); - return 0; - } - - if (lseek64(fd, 1024, SEEK_SET) < 0) { - printf("Cannot seek to superblock"); - return 0; - } - - if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) { - printf("Cannot read superblock"); - return 0; - } - - close(fd); - - if (le32_to_cpu(sb.s_magic) != EXT4_SUPER_MAGIC) { - printf("Not a valid ext4 superblock"); - return 0; - } - block_size = 1024 << sb.s_log_block_size; - /* compute length in bytes */ - len = ( ((off64_t)sb.s_blocks_count_hi << 32) + sb.s_blocks_count_lo) * block_size; - - /* return length in sectors */ - return (unsigned int) (len / 512); -} - static unsigned int get_blkdev_size(int fd) { unsigned int nr_sec; @@ -432,15 +372,12 @@ static int get_crypt_ftr_info(char **metadata_fname, off64_t *off) static off64_t cached_off = 0; static char cached_metadata_fname[PROPERTY_VALUE_MAX] = ""; int fd; - char key_loc[PROPERTY_VALUE_MAX]; - char real_blkdev[PROPERTY_VALUE_MAX]; unsigned int nr_sec; int rc = -1; if (!cached_data) { - fs_mgr_get_crypt_info(fstab, key_loc, real_blkdev, sizeof(key_loc)); - printf("get_crypt_ftr_info crypto key location: '%s'\n", key_loc); - if (!strcmp(key_loc, KEY_IN_FOOTER)) { + printf("get_crypt_ftr_info crypto key location: '%s'\n", key_fname); + if (!strcmp(key_fname, KEY_IN_FOOTER)) { if ( (fd = open(real_blkdev, O_RDWR)) < 0) { printf("Cannot open real block device %s\n", real_blkdev); return -1; @@ -459,7 +396,7 @@ static int get_crypt_ftr_info(char **metadata_fname, off64_t *off) } close(fd); } else { - strlcpy(cached_metadata_fname, key_loc, sizeof(cached_metadata_fname)); + strlcpy(cached_metadata_fname, key_fname, sizeof(cached_metadata_fname)); cached_off = 0; cached_data = 1; } @@ -478,65 +415,6 @@ static int get_crypt_ftr_info(char **metadata_fname, off64_t *off) return rc; } -/* key or salt can be NULL, in which case just skip writing that value. Useful to - * update the failed mount count but not change the key. - */ -static int put_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr) -{ - printf("TWRP NOT putting crypt footer and key\n"); - return 0; - int fd; - unsigned int nr_sec, cnt; - /* starting_off is set to the SEEK_SET offset - * where the crypto structure starts - */ - off64_t starting_off; - int rc = -1; - char *fname = NULL; - struct stat statbuf; - - if (get_crypt_ftr_info(&fname, &starting_off)) { - printf("Unable to get crypt_ftr_info\n"); - return -1; - } - if (fname[0] != '/') { - printf("Unexpected value for crypto key location\n"); - return -1; - } - if ( (fd = open(fname, O_RDWR | O_CREAT, 0600)) < 0) { - printf("Cannot open footer file %s for put\n", fname); - return -1; - } - - /* Seek to the start of the crypt footer */ - if (lseek64(fd, starting_off, SEEK_SET) == -1) { - printf("Cannot seek to real block device footer\n"); - goto errout; - } - - if ((cnt = write(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr))) != sizeof(struct crypt_mnt_ftr)) { - printf("Cannot write real block device footer\n"); - goto errout; - } - - fstat(fd, &statbuf); - /* If the keys are kept on a raw block device, do not try to truncate it. */ - if (S_ISREG(statbuf.st_mode)) { - if (ftruncate(fd, 0x4000)) { - printf("Cannot set footer file size\n"); - goto errout; - } - } - - /* Success! */ - rc = 0; - -errout: - close(fd); - return rc; - -} - static inline int unix_read(int fd, void* buff, int len) { return TEMP_FAILURE_RETRY(read(fd, buff, len)); @@ -554,75 +432,6 @@ static void init_empty_persist_data(struct crypt_persist_data *pdata, int len) pdata->persist_valid_entries = 0; } -/* A routine to update the passed in crypt_ftr to the lastest version. - * fd is open read/write on the device that holds the crypto footer and persistent - * data, crypt_ftr is a pointer to the struct to be updated, and offset is the - * absolute offset to the start of the crypt_mnt_ftr on the passed in fd. - */ -static void upgrade_crypt_ftr(int fd, struct crypt_mnt_ftr *crypt_ftr, off64_t offset) -{ - int orig_major = crypt_ftr->major_version; - int orig_minor = crypt_ftr->minor_version; -printf("TWRP NOT upgrading crypto footer\n"); -return; // do not upgrade in recovery - if ((crypt_ftr->major_version == 1) && (crypt_ftr->minor_version == 0)) { - struct crypt_persist_data *pdata; - off64_t pdata_offset = offset + CRYPT_FOOTER_TO_PERSIST_OFFSET; - - printf("upgrading crypto footer to 1.1"); - - pdata = malloc(CRYPT_PERSIST_DATA_SIZE); - if (pdata == NULL) { - printf("Cannot allocate persisent data\n"); - return; - } - memset(pdata, 0, CRYPT_PERSIST_DATA_SIZE); - - /* Need to initialize the persistent data area */ - if (lseek64(fd, pdata_offset, SEEK_SET) == -1) { - printf("Cannot seek to persisent data offset\n"); - return; - } - /* Write all zeros to the first copy, making it invalid */ - unix_write(fd, pdata, CRYPT_PERSIST_DATA_SIZE); - - /* Write a valid but empty structure to the second copy */ - init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE); - unix_write(fd, pdata, CRYPT_PERSIST_DATA_SIZE); - - /* Update the footer */ - crypt_ftr->persist_data_size = CRYPT_PERSIST_DATA_SIZE; - crypt_ftr->persist_data_offset[0] = pdata_offset; - crypt_ftr->persist_data_offset[1] = pdata_offset + CRYPT_PERSIST_DATA_SIZE; - crypt_ftr->minor_version = 1; - } - - if ((crypt_ftr->major_version == 1) && (crypt_ftr->minor_version == 1)) { - printf("upgrading crypto footer to 1.2"); - /* But keep the old kdf_type. - * It will get updated later to KDF_SCRYPT after the password has been verified. - */ - crypt_ftr->kdf_type = KDF_PBKDF2; - get_device_scrypt_params(crypt_ftr); - crypt_ftr->minor_version = 2; - } - - if ((crypt_ftr->major_version == 1) && (crypt_ftr->minor_version == 2)) { - printf("upgrading crypto footer to 1.3"); - crypt_ftr->crypt_type = CRYPT_TYPE_PASSWORD; - crypt_ftr->minor_version = 3; - } - - if ((orig_major != crypt_ftr->major_version) || (orig_minor != crypt_ftr->minor_version)) { - if (lseek64(fd, offset, SEEK_SET) == -1) { - printf("Cannot seek to crypt footer\n"); - return; - } - unix_write(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr)); - } -} - - static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr) { int fd; @@ -682,9 +491,9 @@ static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr) /* If this is a verion 1.0 crypt_ftr, make it a 1.1 crypt footer, and update the * copy on disk before returning. */ - if (crypt_ftr->minor_version < CURRENT_MINOR_VERSION) { + /*if (crypt_ftr->minor_version < CURRENT_MINOR_VERSION) { upgrade_crypt_ftr(fd, crypt_ftr, starting_off); - } + }*/ /* Success! */ rc = 0; @@ -694,229 +503,6 @@ errout: return rc; } -static int validate_persistent_data_storage(struct crypt_mnt_ftr *crypt_ftr) -{ - if (crypt_ftr->persist_data_offset[0] + crypt_ftr->persist_data_size > - crypt_ftr->persist_data_offset[1]) { - printf("Crypt_ftr persist data regions overlap"); - return -1; - } - - if (crypt_ftr->persist_data_offset[0] >= crypt_ftr->persist_data_offset[1]) { - printf("Crypt_ftr persist data region 0 starts after region 1"); - return -1; - } - - if (((crypt_ftr->persist_data_offset[1] + crypt_ftr->persist_data_size) - - (crypt_ftr->persist_data_offset[0] - CRYPT_FOOTER_TO_PERSIST_OFFSET)) > - CRYPT_FOOTER_OFFSET) { - printf("Persistent data extends past crypto footer"); - return -1; - } - - return 0; -} - -static int load_persistent_data(void) -{ - struct crypt_mnt_ftr crypt_ftr; - struct crypt_persist_data *pdata = NULL; - char encrypted_state[PROPERTY_VALUE_MAX]; - char *fname; - int found = 0; - int fd; - int ret; - int i; - - if (persist_data) { - /* Nothing to do, we've already loaded or initialized it */ - return 0; - } - - - /* If not encrypted, just allocate an empty table and initialize it */ - property_get("ro.crypto.state", encrypted_state, ""); - if (strcmp(encrypted_state, "encrypted") ) { - pdata = malloc(CRYPT_PERSIST_DATA_SIZE); - if (pdata) { - init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE); - persist_data = pdata; - return 0; - } - return -1; - } - - if(get_crypt_ftr_and_key(&crypt_ftr)) { - return -1; - } - - if ((crypt_ftr.major_version < 1) - || (crypt_ftr.major_version == 1 && crypt_ftr.minor_version < 1)) { - printf("Crypt_ftr version doesn't support persistent data"); - return -1; - } - - if (get_crypt_ftr_info(&fname, NULL)) { - return -1; - } - - ret = validate_persistent_data_storage(&crypt_ftr); - if (ret) { - return -1; - } - - fd = open(fname, O_RDONLY); - if (fd < 0) { - printf("Cannot open %s metadata file", fname); - return -1; - } - - if (persist_data == NULL) { - pdata = malloc(crypt_ftr.persist_data_size); - if (pdata == NULL) { - printf("Cannot allocate memory for persistent data"); - goto err; - } - } - - for (i = 0; i < 2; i++) { - if (lseek64(fd, crypt_ftr.persist_data_offset[i], SEEK_SET) < 0) { - printf("Cannot seek to read persistent data on %s", fname); - goto err2; - } - if (unix_read(fd, pdata, crypt_ftr.persist_data_size) < 0){ - printf("Error reading persistent data on iteration %d", i); - goto err2; - } - if (pdata->persist_magic == PERSIST_DATA_MAGIC) { - found = 1; - break; - } - } - - if (!found) { - printf("Could not find valid persistent data, creating"); - init_empty_persist_data(pdata, crypt_ftr.persist_data_size); - } - - /* Success */ - persist_data = pdata; - close(fd); - return 0; - -err2: - free(pdata); - -err: - close(fd); - return -1; -} - -static int save_persistent_data(void) -{ - struct crypt_mnt_ftr crypt_ftr; - struct crypt_persist_data *pdata; - char *fname; - off64_t write_offset; - off64_t erase_offset; - int found = 0; - int fd; - int ret; - - if (persist_data == NULL) { - printf("No persistent data to save"); - return -1; - } - - if(get_crypt_ftr_and_key(&crypt_ftr)) { - return -1; - } - - if ((crypt_ftr.major_version < 1) - || (crypt_ftr.major_version == 1 && crypt_ftr.minor_version < 1)) { - printf("Crypt_ftr version doesn't support persistent data"); - return -1; - } - - ret = validate_persistent_data_storage(&crypt_ftr); - if (ret) { - return -1; - } - - if (get_crypt_ftr_info(&fname, NULL)) { - return -1; - } - - fd = open(fname, O_RDWR); - if (fd < 0) { - printf("Cannot open %s metadata file", fname); - return -1; - } - - pdata = malloc(crypt_ftr.persist_data_size); - if (pdata == NULL) { - printf("Cannot allocate persistant data"); - goto err; - } - - if (lseek64(fd, crypt_ftr.persist_data_offset[0], SEEK_SET) < 0) { - printf("Cannot seek to read persistent data on %s", fname); - goto err2; - } - - if (unix_read(fd, pdata, crypt_ftr.persist_data_size) < 0) { - printf("Error reading persistent data before save"); - goto err2; - } - - if (pdata->persist_magic == PERSIST_DATA_MAGIC) { - /* The first copy is the curent valid copy, so write to - * the second copy and erase this one */ - write_offset = crypt_ftr.persist_data_offset[1]; - erase_offset = crypt_ftr.persist_data_offset[0]; - } else { - /* The second copy must be the valid copy, so write to - * the first copy, and erase the second */ - write_offset = crypt_ftr.persist_data_offset[0]; - erase_offset = crypt_ftr.persist_data_offset[1]; - } - - /* Write the new copy first, if successful, then erase the old copy */ - if (lseek(fd, write_offset, SEEK_SET) < 0) { - printf("Cannot seek to write persistent data"); - goto err2; - } - if (unix_write(fd, persist_data, crypt_ftr.persist_data_size) == - (int) crypt_ftr.persist_data_size) { - if (lseek(fd, erase_offset, SEEK_SET) < 0) { - printf("Cannot seek to erase previous persistent data"); - goto err2; - } - fsync(fd); - memset(pdata, 0, crypt_ftr.persist_data_size); - if (unix_write(fd, pdata, crypt_ftr.persist_data_size) != - (int) crypt_ftr.persist_data_size) { - printf("Cannot write to erase previous persistent data"); - goto err2; - } - fsync(fd); - } else { - printf("Cannot write to save persistent data"); - goto err2; - } - - /* Success */ - free(pdata); - close(fd); - return 0; - -err2: - free(pdata); -err: - close(fd); - return -1; -} - static int hexdigit (char c) { if (c >= '0' && c <= '9') return c - '0'; @@ -1424,360 +1010,49 @@ static int decrypt_master_key(char *passwd, unsigned char *decrypted_master_key, return ret; } -static int create_encrypted_random_key(char *passwd, unsigned char *master_key, unsigned char *salt, - struct crypt_mnt_ftr *crypt_ftr) { - int fd; - unsigned char key_buf[KEY_LEN_BYTES]; - EVP_CIPHER_CTX e_ctx; - int encrypted_len, final_len; - - /* Get some random bits for a key */ - fd = open("/dev/urandom", O_RDONLY); - 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); -} - -static int wait_and_unmount(char *mountpoint, bool kill) +static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, + char *passwd, char *mount_point, char *label) { - int i, err, rc; -#define WAIT_UNMOUNT_COUNT 20 - - /* Now umount the tmpfs filesystem */ - for (i=0; ifs_size = %lld\n", crypt_ftr->fs_size); + orig_failed_decrypt_count = crypt_ftr->failed_decrypt_count; - if (i < WAIT_UNMOUNT_COUNT) { - printf("unmounting %s succeeded\n", mountpoint); - rc = 0; - } else { - //vold_killProcessesWithOpenFiles(mountpoint, 0); - printf("unmounting %s failed: %s\n", mountpoint, strerror(err)); + if (! (crypt_ftr->flags & CRYPT_MNT_KEY_UNENCRYPTED) ) { + if (decrypt_master_key(passwd, decrypted_master_key, crypt_ftr, + &intermediate_key, &intermediate_key_size)) { + printf("Failed to decrypt master key\n"); rc = -1; + goto errout; } + } - return rc; -} + // Create crypto block device - all (non fatal) code paths + // need it + if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key, + real_blkdev, crypto_blkdev, label)) { + printf("Error creating decrypted block device\n"); + rc = -1; + goto errout; + } -#define DATA_PREP_TIMEOUT 200 -static int prep_data_fs(void) -{ - int i; - - /* Do the prep of the /data filesystem */ - property_set("vold.post_fs_data_done", "0"); - property_set("vold.decrypt", "trigger_post_fs_data"); - printf("Just triggered post_fs_data\n"); - - /* Wait a max of 50 seconds, hopefully it takes much less */ - for (i=0; i 0 && atoi(ro_prop)) { - struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT); - rec->flags |= MS_RDONLY; - } - - /* If that succeeded, then mount the decrypted filesystem */ - int retries = RETRY_MOUNT_ATTEMPTS; - int mount_rc; - while ((mount_rc = fs_mgr_do_mount(fstab, DATA_MNT_POINT, - crypto_blkdev, 0)) - != 0) { - if (mount_rc == FS_MGR_DOMNT_BUSY) { - /* TODO: invoke something similar to - Process::killProcessWithOpenFiles(DATA_MNT_POINT, - retries > RETRY_MOUNT_ATTEMPT/2 ? 1 : 2 ) */ - printf("Failed to mount %s because it is busy - waiting", - crypto_blkdev); - if (--retries) { - sleep(RETRY_MOUNT_DELAY_SECONDS); - } else { - /* Let's hope that a reboot clears away whatever is keeping - the mount busy */ - cryptfs_reboot(reboot); - } - } else { - printf("Failed to mount decrypted data"); - cryptfs_set_corrupt(); - cryptfs_trigger_restart_min_framework(); - printf("Started framework to offer wipe"); - return -1; - } - } - - property_set("vold.decrypt", "trigger_load_persist_props"); - /* Create necessary paths on /data */ - if (prep_data_fs()) { - return -1; - } - - /* startup service classes main and late_start */ - property_set("vold.decrypt", "trigger_restart_framework"); - printf("Just triggered restart_framework\n"); - - /* Give it a few moments to get started */ - sleep(1); - } - - if (rc == 0) { - restart_successful = 1; - } - - return rc; -} - -int cryptfs_restart(void) -{ - /* Call internal implementation forcing a restart of main service group */ - return cryptfs_restart_internal(1); -} - -static int do_crypto_complete(char *mount_point UNUSED) -{ - struct crypt_mnt_ftr crypt_ftr; - char encrypted_state[PROPERTY_VALUE_MAX]; - char key_loc[PROPERTY_VALUE_MAX]; - - property_get("ro.crypto.state", encrypted_state, ""); - if (strcmp(encrypted_state, "encrypted") ) { - printf("not running with encryption, aborting"); - return CRYPTO_COMPLETE_NOT_ENCRYPTED; - } - - if (get_crypt_ftr_and_key(&crypt_ftr)) { - fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc)); - - /* - * Only report this error if key_loc is a file and it exists. - * If the device was never encrypted, and /data is not mountable for - * some reason, returning 1 should prevent the UI from presenting the - * a "enter password" screen, or worse, a "press button to wipe the - * device" screen. - */ - if ((key_loc[0] == '/') && (access("key_loc", F_OK) == -1)) { - printf("master key file does not exist, aborting"); - return CRYPTO_COMPLETE_NOT_ENCRYPTED; - } else { - printf("Error getting crypt footer and key\n"); - return CRYPTO_COMPLETE_BAD_METADATA; - } - } - - // Test for possible error flags - if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS){ - printf("Encryption process is partway completed\n"); - return CRYPTO_COMPLETE_PARTIAL; - } - - if (crypt_ftr.flags & CRYPT_INCONSISTENT_STATE){ - printf("Encryption process was interrupted but cannot continue\n"); - return CRYPTO_COMPLETE_INCONSISTENT; - } - - if (crypt_ftr.flags & CRYPT_DATA_CORRUPT){ - printf("Encryption is successful but data is corrupt\n"); - return CRYPTO_COMPLETE_CORRUPT; - } - - /* We passed the test! We shall diminish, and return to the west */ - return CRYPTO_COMPLETE_ENCRYPTED; -} - -static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, - char *passwd, char *mount_point, 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]; - char tmp_mount_point[64]; - unsigned int orig_failed_decrypt_count; - int rc; - kdf_func kdf; - void *kdf_params; - int use_keymaster = 0; - int upgrade = 0; - unsigned char* intermediate_key = 0; - 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, - &intermediate_key, &intermediate_key_size)) { - printf("Failed to decrypt master key\n"); - rc = -1; - goto errout; - } - } - - fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev)); - - // Create crypto block device - all (non fatal) code paths - // need it - if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key, - real_blkdev, crypto_blkdev, label)) { - printf("Error creating decrypted block device\n"); - rc = -1; - goto errout; - } - - /* Work out if the problem is the password or the data */ - unsigned char scrypted_intermediate_key[sizeof(crypt_ftr-> - scrypted_intermediate_key)]; - int N = 1 << crypt_ftr->N_factor; - int r = 1 << crypt_ftr->r_factor; - int p = 1 << crypt_ftr->p_factor; + /* Work out if the problem is the password or the data */ + unsigned char scrypted_intermediate_key[sizeof(crypt_ftr-> + scrypted_intermediate_key)]; + int N = 1 << crypt_ftr->N_factor; + int r = 1 << crypt_ftr->r_factor; + int p = 1 << crypt_ftr->p_factor; rc = crypto_scrypt(intermediate_key, intermediate_key_size, crypt_ftr->salt, sizeof(crypt_ftr->salt), @@ -1795,7 +1070,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, * the footer, not the key. */ sprintf(tmp_mount_point, "%s/tmp_mnt", mount_point); mkdir(tmp_mount_point, 0755); - if (fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) { + if (mount(crypto_blkdev, tmp_mount_point, file_system, NULL, NULL) != 0) { printf("Error temp mounting decrypted block device '%s'\n", crypto_blkdev); delete_crypto_blk_dev(label); @@ -1877,52 +1152,6 @@ int cryptfs_revert_volume(const char *label) return delete_crypto_blk_dev((char *)label); } -/* - * Called by vold when it's asked to mount an encrypted, nonremovable volume. - * Setup a dm-crypt mapping, use the saved master key from - * setting up the /data mapping, and return the new device path. - */ -int cryptfs_setup_volume(const char *label, int major, int minor, - char *crypto_sys_path, unsigned int max_path, - int *new_major, int *new_minor) -{ - char real_blkdev[MAXPATHLEN], crypto_blkdev[MAXPATHLEN]; - struct crypt_mnt_ftr sd_crypt_ftr; - struct stat statbuf; - int nr_sec, fd; - - sprintf(real_blkdev, "/dev/block/vold/%d:%d", major, minor); - - get_crypt_ftr_and_key(&sd_crypt_ftr); - - /* Update the fs_size field to be the size of the volume */ - fd = open(real_blkdev, O_RDONLY); - nr_sec = get_blkdev_size(fd); - close(fd); - if (nr_sec == 0) { - printf("Cannot get size of volume %s\n", real_blkdev); - return -1; - } - - sd_crypt_ftr.fs_size = nr_sec; - create_crypto_blk_dev(&sd_crypt_ftr, saved_master_key, real_blkdev, - crypto_blkdev, label); - - stat(crypto_blkdev, &statbuf); - *new_major = MAJOR(statbuf.st_rdev); - *new_minor = MINOR(statbuf.st_rdev); - - /* Create path to sys entry for this block device */ - snprintf(crypto_sys_path, max_path, "/devices/virtual/block/%s", strrchr(crypto_blkdev, '/')+1); - - return 0; -} - -int cryptfs_crypto_complete(void) -{ - return do_crypto_complete("/data"); -} - int check_unmounted_and_get_ftr(struct crypt_mnt_ftr* crypt_ftr) { char encrypted_state[PROPERTY_VALUE_MAX]; @@ -2034,24 +1263,11 @@ char* hexadj_passwd(const char* passwd) return hex; } -#define FSTAB_PREFIX "/fstab." - -int cryptfs_check_footer(void) +int cryptfs_check_footer() { int rc = -1; - char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; - char propbuf[PROPERTY_VALUE_MAX]; struct crypt_mnt_ftr crypt_ftr; - property_get("ro.hardware", propbuf, ""); - snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); - - fstab = fs_mgr_read_fstab(fstab_filename); - if (!fstab) { - printf("failed to open %s\n", fstab_filename); - return -1; - } - rc = get_crypt_ftr_and_key(&crypt_ftr); return rc; @@ -2061,17 +1277,6 @@ int cryptfs_check_passwd(char *passwd) { struct crypt_mnt_ftr crypt_ftr; int rc; - char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; - char propbuf[PROPERTY_VALUE_MAX]; - - property_get("ro.hardware", propbuf, ""); - snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); - - fstab = fs_mgr_read_fstab(fstab_filename); - if (!fstab) { - printf("failed to open %s\n", fstab_filename); - return -1; - } rc = check_unmounted_and_get_ftr(&crypt_ftr); if (rc) @@ -2223,1398 +1428,20 @@ static int cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr) return 0; } -static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type) -{ - const char *args[10]; - char size_str[32]; /* Must be large enough to hold a %lld and null byte */ - int num_args; - int status; - int tmp; - int rc = -1; - - if (type == EXT4_FS) { - args[0] = "/system/bin/make_ext4fs"; - args[1] = "-a"; - args[2] = "/data"; - args[3] = "-l"; - snprintf(size_str, sizeof(size_str), "%" PRId64, size * 512); - args[4] = size_str; - args[5] = crypto_blkdev; - num_args = 6; - printf("Making empty filesystem with command %s %s %s %s %s %s\n", - args[0], args[1], args[2], args[3], args[4], args[5]); - } else if (type == F2FS_FS) { - args[0] = "/system/bin/mkfs.f2fs"; - args[1] = "-t"; - args[2] = "-d1"; - args[3] = crypto_blkdev; - snprintf(size_str, sizeof(size_str), "%" PRId64, size); - args[4] = size_str; - num_args = 5; - printf("Making empty filesystem with command %s %s %s %s %s\n", - args[0], args[1], args[2], args[3], args[4]); - } else { - printf("cryptfs_enable_wipe(): unknown filesystem type %d\n", type); - return -1; - } - - tmp = android_fork_execvp(num_args, (char **)args, &status, false, true); - - if (tmp != 0) { - printf("Error creating empty filesystem on %s due to logwrap error\n", crypto_blkdev); - } else { - if (WIFEXITED(status)) { - if (WEXITSTATUS(status)) { - printf("Error creating filesystem on %s, exit status %d ", - crypto_blkdev, WEXITSTATUS(status)); - } else { - printf("Successfully created filesystem on %s\n", crypto_blkdev); - rc = 0; - } - } else { - printf("Error creating filesystem on %s, did not exit normally\n", crypto_blkdev); - } - } - - return rc; -} - -#define CRYPT_INPLACE_BUFSIZE 4096 -#define CRYPT_SECTORS_PER_BUFSIZE (CRYPT_INPLACE_BUFSIZE / CRYPT_SECTOR_SIZE) -#define CRYPT_SECTOR_SIZE 512 - -/* aligned 32K writes tends to make flash happy. - * SD card association recommends it. +/* Returns type of the password, default, pattern, pin or password. */ -#define BLOCKS_AT_A_TIME 8 - -struct encryptGroupsData -{ - int realfd; - int cryptofd; - off64_t numblocks; - off64_t one_pct, cur_pct, new_pct; - off64_t blocks_already_done, tot_numblocks; - off64_t used_blocks_already_done, tot_used_blocks; - char* real_blkdev, * crypto_blkdev; - int count; - off64_t offset; - char* buffer; - off64_t last_written_sector; - int completed; - time_t time_started; - int remaining_time; -}; - -static void update_progress(struct encryptGroupsData* data, int is_used) -{ - data->blocks_already_done++; - - if (is_used) { - data->used_blocks_already_done++; - } - if (data->tot_used_blocks) { - data->new_pct = data->used_blocks_already_done / data->one_pct; - } else { - data->new_pct = data->blocks_already_done / data->one_pct; - } - - if (data->new_pct > data->cur_pct) { - char buf[8]; - data->cur_pct = data->new_pct; - snprintf(buf, sizeof(buf), "%" PRId64, data->cur_pct); - property_set("vold.encrypt_progress", buf); - } - - if (data->cur_pct >= 5) { - struct timespec time_now; - if (clock_gettime(CLOCK_MONOTONIC, &time_now)) { - printf("Error getting time"); - } else { - double elapsed_time = difftime(time_now.tv_sec, data->time_started); - off64_t remaining_blocks = data->tot_used_blocks - - data->used_blocks_already_done; - int remaining_time = (int)(elapsed_time * remaining_blocks - / data->used_blocks_already_done); - - // Change time only if not yet set, lower, or a lot higher for - // best user experience - if (data->remaining_time == -1 - || remaining_time < data->remaining_time - || remaining_time > data->remaining_time + 60) { - char buf[8]; - snprintf(buf, sizeof(buf), "%d", remaining_time); - property_set("vold.encrypt_time_remaining", buf); - data->remaining_time = remaining_time; - } - } - } -} - -static void log_progress(struct encryptGroupsData const* data, bool completed) -{ - // Precondition - if completed data = 0 else data != 0 - - // Track progress so we can skip logging blocks - static off64_t offset = -1; - - // Need to close existing 'Encrypting from' log? - if (completed || (offset != -1 && data->offset != offset)) { - printf("Encrypted to sector %" PRId64, - offset / info.block_size * CRYPT_SECTOR_SIZE); - offset = -1; - } - - // Need to start new 'Encrypting from' log? - if (!completed && offset != data->offset) { - printf("Encrypting from sector %" PRId64, - data->offset / info.block_size * CRYPT_SECTOR_SIZE); - } - - // Update offset - if (!completed) { - offset = data->offset + (off64_t)data->count * info.block_size; - } -} - -static int flush_outstanding_data(struct encryptGroupsData* data) +int cryptfs_get_password_type(void) { - if (data->count == 0) { - return 0; - } - - printf("Copying %d blocks at offset %" PRIx64, data->count, data->offset); - - if (pread64(data->realfd, data->buffer, - info.block_size * data->count, data->offset) - <= 0) { - printf("Error reading real_blkdev %s for inplace encrypt", - data->real_blkdev); - return -1; - } + struct crypt_mnt_ftr crypt_ftr; - if (pwrite64(data->cryptofd, data->buffer, - info.block_size * data->count, data->offset) - <= 0) { - printf("Error writing crypto_blkdev %s for inplace encrypt", - data->crypto_blkdev); + if (get_crypt_ftr_and_key(&crypt_ftr)) { + printf("Error getting crypt footer and key\n"); return -1; - } else { - log_progress(data, false); - } - - data->count = 0; - data->last_written_sector = (data->offset + data->count) - / info.block_size * CRYPT_SECTOR_SIZE - 1; - return 0; -} - -static int encrypt_groups(struct encryptGroupsData* data) -{ - unsigned int i; - u8 *block_bitmap = 0; - unsigned int block; - off64_t ret; - int rc = -1; - - data->buffer = malloc(info.block_size * BLOCKS_AT_A_TIME); - if (!data->buffer) { - printf("Failed to allocate crypto buffer"); - goto errout; - } - - block_bitmap = malloc(info.block_size); - if (!block_bitmap) { - printf("failed to allocate block bitmap"); - goto errout; - } - - for (i = 0; i < aux_info.groups; ++i) { - printf("Encrypting group %d", i); - - u32 first_block = aux_info.first_data_block + i * info.blocks_per_group; - u32 block_count = min(info.blocks_per_group, - aux_info.len_blocks - first_block); - - off64_t offset = (u64)info.block_size - * aux_info.bg_desc[i].bg_block_bitmap; - - ret = pread64(data->realfd, block_bitmap, info.block_size, offset); - if (ret != (int)info.block_size) { - printf("failed to read all of block group bitmap %d", i); - goto errout; - } - - offset = (u64)info.block_size * first_block; - - data->count = 0; - - for (block = 0; block < block_count; block++) { - int used = bitmap_get_bit(block_bitmap, block); - update_progress(data, used); - if (used) { - if (data->count == 0) { - data->offset = offset; - } - data->count++; - } else { - if (flush_outstanding_data(data)) { - goto errout; - } - } - - offset += info.block_size; - - /* Write data if we are aligned or buffer size reached */ - if (offset % (info.block_size * BLOCKS_AT_A_TIME) == 0 - || data->count == BLOCKS_AT_A_TIME) { - if (flush_outstanding_data(data)) { - goto errout; - } - } - - if (1) { - printf("Stopping encryption due to low battery"); - rc = 0; - goto errout; - } - - } - if (flush_outstanding_data(data)) { - goto errout; - } } - data->completed = 1; - rc = 0; - -errout: - log_progress(0, true); - free(data->buffer); - free(block_bitmap); - return rc; -} - -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) -{ - u32 i; - struct encryptGroupsData data; - int rc; // Can't initialize without causing warning -Wclobbered - - if (previously_encrypted_upto > *size_already_done) { - printf("Not fast encrypting since resuming part way through"); - return -1; - } - - memset(&data, 0, sizeof(data)); - data.real_blkdev = real_blkdev; - data.crypto_blkdev = crypto_blkdev; - - if ( (data.realfd = open(real_blkdev, O_RDWR)) < 0) { - printf("Error opening real_blkdev %s for inplace encrypt. err=%d(%s)\n", - real_blkdev, errno, strerror(errno)); - rc = -1; - goto errout; - } - - if ( (data.cryptofd = open(crypto_blkdev, O_WRONLY)) < 0) { - printf("Error opening crypto_blkdev %s for ext4 inplace encrypt. err=%d(%s)\n", - crypto_blkdev, errno, strerror(errno)); - rc = ENABLE_INPLACE_ERR_DEV; - goto errout; - } - - if (setjmp(setjmp_env)) { - printf("Reading ext4 extent caused an exception\n"); - rc = -1; - goto errout; - } - - if (read_ext(data.realfd, 0) != 0) { - printf("Failed to read ext4 extent\n"); - rc = -1; - goto errout; - } - - data.numblocks = size / CRYPT_SECTORS_PER_BUFSIZE; - data.tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE; - data.blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE; - - printf("Encrypting ext4 filesystem in place..."); - - data.tot_used_blocks = data.numblocks; - for (i = 0; i < aux_info.groups; ++i) { - data.tot_used_blocks -= aux_info.bg_desc[i].bg_free_blocks_count; - } - - data.one_pct = data.tot_used_blocks / 100; - data.cur_pct = 0; - - struct timespec time_started = {0}; - if (clock_gettime(CLOCK_MONOTONIC, &time_started)) { - printf("Error getting time at start"); - // Note - continue anyway - we'll run with 0 - } - data.time_started = time_started.tv_sec; - data.remaining_time = -1; - - rc = encrypt_groups(&data); - if (rc) { - printf("Error encrypting groups"); - goto errout; - } - - *size_already_done += data.completed ? size : data.last_written_sector; - rc = 0; - -errout: - close(data.realfd); - close(data.cryptofd); - - return rc; -} - -static void log_progress_f2fs(u64 block, bool completed) -{ - // Precondition - if completed data = 0 else data != 0 - - // Track progress so we can skip logging blocks - static u64 last_block = (u64)-1; - - // Need to close existing 'Encrypting from' log? - if (completed || (last_block != (u64)-1 && block != last_block + 1)) { - printf("Encrypted to block %" PRId64, last_block); - last_block = -1; - } - - // Need to start new 'Encrypting from' log? - if (!completed && (last_block == (u64)-1 || block != last_block + 1)) { - printf("Encrypting from block %" PRId64, block); - } - - // Update offset - if (!completed) { - last_block = block; - } -} - -static int encrypt_one_block_f2fs(u64 pos, void *data) -{ - struct encryptGroupsData *priv_dat = (struct encryptGroupsData *)data; - - priv_dat->blocks_already_done = pos - 1; - update_progress(priv_dat, 1); - - off64_t offset = pos * CRYPT_INPLACE_BUFSIZE; - - if (pread64(priv_dat->realfd, priv_dat->buffer, CRYPT_INPLACE_BUFSIZE, offset) <= 0) { - printf("Error reading real_blkdev %s for f2fs inplace encrypt", priv_dat->crypto_blkdev); - return -1; - } - - if (pwrite64(priv_dat->cryptofd, priv_dat->buffer, CRYPT_INPLACE_BUFSIZE, offset) <= 0) { - printf("Error writing crypto_blkdev %s for f2fs inplace encrypt", priv_dat->crypto_blkdev); - return -1; - } else { - log_progress_f2fs(pos, false); - } - - return 0; -} - -static int cryptfs_enable_inplace_f2fs(char *crypto_blkdev, - char *real_blkdev, - off64_t size, - off64_t *size_already_done, - off64_t tot_size, - off64_t previously_encrypted_upto) -{ - u32 i; - struct encryptGroupsData data; - struct f2fs_info *f2fs_info = NULL; - int rc = ENABLE_INPLACE_ERR_OTHER; - if (previously_encrypted_upto > *size_already_done) { - printf("Not fast encrypting since resuming part way through"); - return ENABLE_INPLACE_ERR_OTHER; - } - memset(&data, 0, sizeof(data)); - data.real_blkdev = real_blkdev; - data.crypto_blkdev = crypto_blkdev; - data.realfd = -1; - data.cryptofd = -1; - if ( (data.realfd = open64(real_blkdev, O_RDWR)) < 0) { - printf("Error opening real_blkdev %s for f2fs inplace encrypt\n", - real_blkdev); - goto errout; - } - if ( (data.cryptofd = open64(crypto_blkdev, O_WRONLY)) < 0) { - printf("Error opening crypto_blkdev %s for f2fs inplace encrypt. err=%d(%s)\n", - crypto_blkdev, errno, strerror(errno)); - rc = ENABLE_INPLACE_ERR_DEV; - goto errout; - } - - f2fs_info = generate_f2fs_info(data.realfd); - if (!f2fs_info) - goto errout; - - data.numblocks = size / CRYPT_SECTORS_PER_BUFSIZE; - data.tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE; - data.blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE; - - data.tot_used_blocks = get_num_blocks_used(f2fs_info); - - data.one_pct = data.tot_used_blocks / 100; - data.cur_pct = 0; - data.time_started = time(NULL); - data.remaining_time = -1; - - data.buffer = malloc(f2fs_info->block_size); - if (!data.buffer) { - printf("Failed to allocate crypto buffer"); - goto errout; - } - - data.count = 0; - - /* Currently, this either runs to completion, or hits a nonrecoverable error */ - rc = run_on_used_blocks(data.blocks_already_done, f2fs_info, &encrypt_one_block_f2fs, &data); - - if (rc) { - printf("Error in running over f2fs blocks"); - rc = ENABLE_INPLACE_ERR_OTHER; - goto errout; - } - - *size_already_done += size; - rc = 0; - -errout: - if (rc) - printf("Failed to encrypt f2fs filesystem on %s", real_blkdev); - - log_progress_f2fs(0, true); - free(f2fs_info); - free(data.buffer); - close(data.realfd); - close(data.cryptofd); - - return rc; -} - -static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev, - off64_t size, off64_t *size_already_done, - off64_t tot_size, - off64_t previously_encrypted_upto) -{ - int realfd, cryptofd; - char *buf[CRYPT_INPLACE_BUFSIZE]; - int rc = ENABLE_INPLACE_ERR_OTHER; - off64_t numblocks, i, remainder; - off64_t one_pct, cur_pct, new_pct; - off64_t blocks_already_done, tot_numblocks; - - if ( (realfd = open(real_blkdev, O_RDONLY)) < 0) { - printf("Error opening real_blkdev %s for inplace encrypt\n", real_blkdev); - return ENABLE_INPLACE_ERR_OTHER; - } - - if ( (cryptofd = open(crypto_blkdev, O_WRONLY)) < 0) { - printf("Error opening crypto_blkdev %s for inplace encrypt. err=%d(%s)\n", - crypto_blkdev, errno, strerror(errno)); - close(realfd); - return ENABLE_INPLACE_ERR_DEV; - } - - /* This is pretty much a simple loop of reading 4K, and writing 4K. - * The size passed in is the number of 512 byte sectors in the filesystem. - * So compute the number of whole 4K blocks we should read/write, - * and the remainder. - */ - numblocks = size / CRYPT_SECTORS_PER_BUFSIZE; - remainder = size % CRYPT_SECTORS_PER_BUFSIZE; - tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE; - blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE; - - printf("Encrypting filesystem in place..."); - - i = previously_encrypted_upto + 1 - *size_already_done; - - if (lseek64(realfd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) { - printf("Cannot seek to previously encrypted point on %s", real_blkdev); - goto errout; - } - - if (lseek64(cryptofd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) { - printf("Cannot seek to previously encrypted point on %s", crypto_blkdev); - goto errout; - } - - for (;i < size && i % CRYPT_SECTORS_PER_BUFSIZE != 0; ++i) { - if (unix_read(realfd, buf, CRYPT_SECTOR_SIZE) <= 0) { - printf("Error reading initial sectors from real_blkdev %s for " - "inplace encrypt\n", crypto_blkdev); - goto errout; - } - if (unix_write(cryptofd, buf, CRYPT_SECTOR_SIZE) <= 0) { - printf("Error writing initial sectors to crypto_blkdev %s for " - "inplace encrypt\n", crypto_blkdev); - goto errout; - } else { - printf("Encrypted 1 block at %" PRId64, i); - } - } - - one_pct = tot_numblocks / 100; - cur_pct = 0; - /* process the majority of the filesystem in blocks */ - for (i/=CRYPT_SECTORS_PER_BUFSIZE; i cur_pct) { - char buf[8]; - - cur_pct = new_pct; - snprintf(buf, sizeof(buf), "%" PRId64, cur_pct); - property_set("vold.encrypt_progress", buf); - } - if (unix_read(realfd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) { - printf("Error reading real_blkdev %s for inplace encrypt", crypto_blkdev); - goto errout; - } - if (unix_write(cryptofd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) { - printf("Error writing crypto_blkdev %s for inplace encrypt", crypto_blkdev); - goto errout; - } else { - printf("Encrypted %d block at %" PRId64, - CRYPT_SECTORS_PER_BUFSIZE, - i * CRYPT_SECTORS_PER_BUFSIZE); - } - - if (1) { - printf("Stopping encryption due to low battery"); - *size_already_done += (i + 1) * CRYPT_SECTORS_PER_BUFSIZE - 1; - rc = 0; - goto errout; - } - } - - /* Do any remaining sectors */ - for (i=0; iflags & (VOL_ENCRYPTABLE | VOL_NONREMOVABLE)) == - (VOL_ENCRYPTABLE | VOL_NONREMOVABLE); -} - -static int cryptfs_SHA256_fileblock(const char* filename, __le8* buf) -{ - int fd = open(filename, O_RDONLY); - if (fd == -1) { - printf("Error opening file %s", filename); - return -1; - } - - char block[CRYPT_INPLACE_BUFSIZE]; - memset(block, 0, sizeof(block)); - if (unix_read(fd, block, sizeof(block)) < 0) { - printf("Error reading file %s", filename); - close(fd); - return -1; - } - - close(fd); - - SHA256_CTX c; - SHA256_Init(&c); - SHA256_Update(&c, block, sizeof(block)); - SHA256_Final(buf, &c); - - return 0; -} - -static int get_fs_type(struct fstab_rec *rec) -{ - if (!strcmp(rec->fs_type, "ext4")) { - return EXT4_FS; - } else if (!strcmp(rec->fs_type, "f2fs")) { - return F2FS_FS; - } else { - return -1; - } -} - -static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr *crypt_ftr, int how, - char *crypto_blkdev, char *real_blkdev, - int previously_encrypted_upto) -{ - off64_t cur_encryption_done=0, tot_encryption_size=0; - int i, rc = -1; - - if (1) { - printf("Not starting encryption due to low battery"); - return 0; - } - - /* The size of the userdata partition, and add in the vold volumes below */ - tot_encryption_size = crypt_ftr->fs_size; - - if (how == CRYPTO_ENABLE_WIPE) { - struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT); - int fs_type = get_fs_type(rec); - if (fs_type < 0) { - printf("cryptfs_enable: unsupported fs type %s\n", rec->fs_type); - return -1; - } - rc = cryptfs_enable_wipe(crypto_blkdev, crypt_ftr->fs_size, fs_type); - } else if (how == CRYPTO_ENABLE_INPLACE) { - rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev, - crypt_ftr->fs_size, &cur_encryption_done, - tot_encryption_size, - previously_encrypted_upto); - - if (rc == ENABLE_INPLACE_ERR_DEV) { - /* Hack for b/17898962 */ - printf("cryptfs_enable: crypto block dev failure. Must reboot...\n"); - cryptfs_reboot(reboot); - } - - if (!rc) { - crypt_ftr->encrypted_upto = cur_encryption_done; - } - - if (!rc && crypt_ftr->encrypted_upto == crypt_ftr->fs_size) { - /* The inplace routine never actually sets the progress to 100% due - * to the round down nature of integer division, so set it here */ - property_set("vold.encrypt_progress", "100"); - } - } else { - /* Shouldn't happen */ - printf("cryptfs_enable: internal error, unknown option\n"); - rc = -1; - } - - return rc; -} - -int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd, - int allow_reboot) -{ - int how = 0; - char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN]; - unsigned long nr_sec; - unsigned char decrypted_master_key[KEY_LEN_BYTES]; - int rc=-1, fd, i, ret; - struct crypt_mnt_ftr crypt_ftr; - struct crypt_persist_data *pdata; - char encrypted_state[PROPERTY_VALUE_MAX]; - char lockid[32] = { 0 }; - char key_loc[PROPERTY_VALUE_MAX]; - char fuse_sdcard[PROPERTY_VALUE_MAX]; - char *sd_mnt_point; - int num_vols; - struct volume_info *vol_list = 0; - off64_t previously_encrypted_upto = 0; -printf("cryptfs_enable_internal disabled by TWRP\n"); -return -1; - if (!strcmp(howarg, "wipe")) { - how = CRYPTO_ENABLE_WIPE; - } else if (! strcmp(howarg, "inplace")) { - how = CRYPTO_ENABLE_INPLACE; - } else { - /* Shouldn't happen, as CommandListener vets the args */ - goto error_unencrypted; - } - - /* See if an encryption was underway and interrupted */ - 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; - - /* At this point, we are in an inconsistent state. Until we successfully - complete encryption, a reboot will leave us broken. So mark the - encryption failed in case that happens. - On successfully completing encryption, remove this flag */ - crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE; - - put_crypt_ftr_and_key(&crypt_ftr); - } - - property_get("ro.crypto.state", encrypted_state, ""); - if (!strcmp(encrypted_state, "encrypted") && !previously_encrypted_upto) { - printf("Device is already running encrypted, aborting"); - goto error_unencrypted; - } - - // TODO refactor fs_mgr_get_crypt_info to get both in one call - fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc)); - fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev)); - - /* Get the size of the real block device */ - fd = open(real_blkdev, O_RDONLY); - if ( (nr_sec = get_blkdev_size(fd)) == 0) { - printf("Cannot get size of block device %s\n", real_blkdev); - goto error_unencrypted; - } - close(fd); - - /* If doing inplace encryption, make sure the orig fs doesn't include the crypto footer */ - if ((how == CRYPTO_ENABLE_INPLACE) && (!strcmp(key_loc, KEY_IN_FOOTER))) { - unsigned int fs_size_sec, max_fs_size_sec; - fs_size_sec = get_fs_size(real_blkdev); - if (fs_size_sec == 0) - fs_size_sec = get_f2fs_filesystem_size_sec(real_blkdev); - - max_fs_size_sec = nr_sec - (CRYPT_FOOTER_OFFSET / CRYPT_SECTOR_SIZE); - - if (fs_size_sec > max_fs_size_sec) { - printf("Orig filesystem overlaps crypto footer region. Cannot encrypt in place."); - goto error_unencrypted; - } - } - - /* Get a wakelock as this may take a while, and we don't want the - * device to sleep on us. We'll grab a partial wakelock, and if the UI - * wants to keep the screen on, it can grab a full wakelock. - */ - snprintf(lockid, sizeof(lockid), "enablecrypto%d", (int) getpid()); - acquire_wake_lock(PARTIAL_WAKE_LOCK, lockid); - - /* Get the sdcard mount point */ - sd_mnt_point = getenv("EMULATED_STORAGE_SOURCE"); - if (!sd_mnt_point) { - sd_mnt_point = getenv("EXTERNAL_STORAGE"); - } - if (!sd_mnt_point) { - sd_mnt_point = "/mnt/sdcard"; - } - - /* TODO - * Currently do not have test devices with multiple encryptable volumes. - * When we acquire some, re-add support. - */ - num_vols=0/*vold_getNumDirectVolumes()*/; - vol_list = malloc(sizeof(struct volume_info) * num_vols); - //vold_getDirectVolumeList(vol_list); - - for (i=0; i= 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 { - printf("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; - } - - /* hrm, the encrypt step claims success, but the reboot failed. - * This should not happen. - * Set the property and return. Hope the framework can deal with it. - */ - property_set("vold.encrypt_progress", "error_reboot_failed"); - release_wake_lock(lockid); - return rc; - -error_unencrypted: - free(vol_list); - property_set("vold.encrypt_progress", "error_not_encrypted"); - if (lockid[0]) { - release_wake_lock(lockid); - } - return -1; - -error_shutting_down: - /* we failed, and have not encrypted anthing, so the users's data is still intact, - * but the framework is stopped and not restarted to show the error, so it's up to - * vold to restart the system. - */ - printf("Error enabling encryption after framework is shutdown, no data changed, restarting system"); - cryptfs_reboot(reboot); - - /* shouldn't get here */ - property_set("vold.encrypt_progress", "error_shutting_down"); - free(vol_list); - if (lockid[0]) { - release_wake_lock(lockid); - } - return -1; -} - -int cryptfs_enable(char *howarg, int type, char *passwd, int allow_reboot) -{ - char* adjusted_passwd = adjust_passwd(passwd); - if (adjusted_passwd) { - passwd = adjusted_passwd; - } - - int rc = cryptfs_enable_internal(howarg, type, passwd, allow_reboot); - - free(adjusted_passwd); - return rc; -} - -int cryptfs_enable_default(char *howarg, int allow_reboot) -{ - return cryptfs_enable_internal(howarg, CRYPT_TYPE_DEFAULT, - DEFAULT_PASSWORD, allow_reboot); -} - -int cryptfs_changepw(int crypt_type, const char *newpw) -{ - struct crypt_mnt_ftr crypt_ftr; - unsigned char decrypted_master_key[KEY_LEN_BYTES]; - - /* This is only allowed after we've successfully decrypted the master key */ - if (!master_key_saved) { - printf("Key not saved, aborting"); - return -1; - } - - if (crypt_type < 0 || crypt_type > CRYPT_TYPE_MAX_TYPE) { - printf("Invalid crypt_type %d", crypt_type); - return -1; - } - - /* get key */ - if (get_crypt_ftr_and_key(&crypt_ftr)) { - printf("Error getting crypt footer and key"); - return -1; - } - - crypt_ftr.crypt_type = crypt_type; - - char* adjusted_passwd = adjust_passwd(newpw); - if (adjusted_passwd) { - newpw = adjusted_passwd; - } - - encrypt_master_key(crypt_type == CRYPT_TYPE_DEFAULT ? DEFAULT_PASSWORD - : newpw, - crypt_ftr.salt, - saved_master_key, - crypt_ftr.master_key, - &crypt_ftr); - - /* save the key */ - put_crypt_ftr_and_key(&crypt_ftr); - - free(adjusted_passwd); - return 0; -} - -static int persist_get_key(char *fieldname, char *value) -{ - unsigned int i; - - if (persist_data == NULL) { - return -1; - } - for (i = 0; i < persist_data->persist_valid_entries; i++) { - if (!strncmp(persist_data->persist_entry[i].key, fieldname, PROPERTY_KEY_MAX)) { - /* We found it! */ - strlcpy(value, persist_data->persist_entry[i].val, PROPERTY_VALUE_MAX); - return 0; - } - } - - return -1; -} - -static int persist_set_key(char *fieldname, char *value, int encrypted) -{ - unsigned int i; - unsigned int num; - struct crypt_mnt_ftr crypt_ftr; - unsigned int max_persistent_entries; - unsigned int dsize; - - if (persist_data == NULL) { - return -1; - } - - /* If encrypted, use the values from the crypt_ftr, otherwise - * use the values for the current spec. - */ - if (encrypted) { - if(get_crypt_ftr_and_key(&crypt_ftr)) { - return -1; - } - dsize = crypt_ftr.persist_data_size; - } else { - dsize = CRYPT_PERSIST_DATA_SIZE; - } - max_persistent_entries = (dsize - sizeof(struct crypt_persist_data)) / - sizeof(struct crypt_persist_entry); - - num = persist_data->persist_valid_entries; - - for (i = 0; i < num; i++) { - if (!strncmp(persist_data->persist_entry[i].key, fieldname, PROPERTY_KEY_MAX)) { - /* We found an existing entry, update it! */ - memset(persist_data->persist_entry[i].val, 0, PROPERTY_VALUE_MAX); - strlcpy(persist_data->persist_entry[i].val, value, PROPERTY_VALUE_MAX); - return 0; - } - } - - /* We didn't find it, add it to the end, if there is room */ - if (persist_data->persist_valid_entries < max_persistent_entries) { - memset(&persist_data->persist_entry[num], 0, sizeof(struct crypt_persist_entry)); - strlcpy(persist_data->persist_entry[num].key, fieldname, PROPERTY_KEY_MAX); - strlcpy(persist_data->persist_entry[num].val, value, PROPERTY_VALUE_MAX); - persist_data->persist_valid_entries++; - return 0; - } - - return -1; -} - -/* Return the value of the specified field. */ -int cryptfs_getfield(char *fieldname, char *value, int len) -{ - char temp_value[PROPERTY_VALUE_MAX]; - char real_blkdev[MAXPATHLEN]; - /* 0 is success, 1 is not encrypted, - * -1 is value not set, -2 is any other error - */ - int rc = -2; - - if (persist_data == NULL) { - load_persistent_data(); - if (persist_data == NULL) { - printf("Getfield error, cannot load persistent data"); - goto out; - } - } - - if (!persist_get_key(fieldname, temp_value)) { - /* We found it, copy it to the caller's buffer and return */ - strlcpy(value, temp_value, len); - rc = 0; - } else { - /* Sadness, it's not there. Return the error */ - rc = -1; - } - -out: - return rc; -} - -/* Set the value of the specified field. */ -int cryptfs_setfield(char *fieldname, char *value) -{ - struct crypt_persist_data stored_pdata; - struct crypt_persist_data *pdata_p; - struct crypt_mnt_ftr crypt_ftr; - char encrypted_state[PROPERTY_VALUE_MAX]; - /* 0 is success, -1 is an error */ - int rc = -1; - int encrypted = 0; - - if (persist_data == NULL) { - load_persistent_data(); - if (persist_data == NULL) { - printf("Setfield error, cannot load persistent data"); - goto out; - } - } - - property_get("ro.crypto.state", encrypted_state, ""); - if (!strcmp(encrypted_state, "encrypted") ) { - encrypted = 1; - } - - if (persist_set_key(fieldname, value, encrypted)) { - goto out; - } - - /* If we are running encrypted, save the persistent data now */ - if (encrypted) { - if (save_persistent_data()) { - printf("Setfield error, cannot save persistent data"); - goto out; - } - } - - rc = 0; - -out: - return rc; -} - -/* Checks userdata. Attempt to mount the volume if default- - * encrypted. - * On success trigger next init phase and return 0. - * Currently do not handle failure - see TODO below. - */ -int cryptfs_mount_default_encrypted(void) -{ - char decrypt_state[PROPERTY_VALUE_MAX]; - property_get("vold.decrypt", decrypt_state, "0"); - if (!strcmp(decrypt_state, "0")) { - printf("Not encrypted - should not call here"); - } else { - int crypt_type = cryptfs_get_password_type(); - if (crypt_type < 0 || crypt_type > CRYPT_TYPE_MAX_TYPE) { - printf("Bad crypt type - error"); - } else if (crypt_type != CRYPT_TYPE_DEFAULT) { - printf("Password is not default - " - "starting min framework to prompt"); - property_set("vold.decrypt", "trigger_restart_min_framework"); - return 0; - } else if (cryptfs_check_passwd(DEFAULT_PASSWORD) == 0) { - printf("Password is default - restarting filesystem"); - cryptfs_restart_internal(0); - return 0; - } else { - printf("Encrypted, default crypt type but can't decrypt"); - } - } - - /** Corrupt. Allow us to boot into framework, which will detect bad - crypto when it calls do_crypto_complete, then do a factory reset - */ - property_set("vold.decrypt", "trigger_restart_min_framework"); - return 0; -} - -/* Returns type of the password, default, pattern, pin or password. - */ -int cryptfs_get_password_type(void) -{ - struct crypt_mnt_ftr crypt_ftr; - char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; - char propbuf[PROPERTY_VALUE_MAX]; - - property_get("ro.hardware", propbuf, ""); - snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); - - fstab = fs_mgr_read_fstab(fstab_filename); - if (!fstab) { - printf("failed to open %s\n", fstab_filename); - 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_INCONSISTENT_STATE) { + if (crypt_ftr.flags & CRYPT_INCONSISTENT_STATE) { return -1; } return crypt_ftr.crypt_type; } - -char* cryptfs_get_password() -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - if (now.tv_sec < password_expiry_time) { - return password; - } else { - cryptfs_clear_password(); - return 0; - } -} - -void cryptfs_clear_password() -{ - if (password) { - size_t len = strlen(password); - memset(password, 0, len); - free(password); - password = 0; - password_expiry_time = 0; - } -} diff --git a/crypto/lollipop/cryptfs.h b/crypto/lollipop/cryptfs.h index b95a290cf..8cb8a7a32 100644 --- a/crypto/lollipop/cryptfs.h +++ b/crypto/lollipop/cryptfs.h @@ -208,24 +208,11 @@ extern "C" { typedef int (*kdf_func)(const char *passwd, const unsigned char *salt, unsigned char *ikey, void *params); - int cryptfs_crypto_complete(void); - int cryptfs_check_footer(void); + void set_partition_data(const char* block_device, const char* key_location, const char* fs); + int cryptfs_check_footer(); int cryptfs_check_passwd(char *pw); int cryptfs_verify_passwd(char *newpw); - int cryptfs_restart(void); - int cryptfs_enable(char *flag, int type, char *passwd, int allow_reboot); - int cryptfs_changepw(int type, const char *newpw); - int cryptfs_enable_default(char *flag, int allow_reboot); - int cryptfs_setup_volume(const char *label, int major, int minor, - char *crypto_dev_path, unsigned int max_pathlen, - int *new_major, int *new_minor); - int cryptfs_revert_volume(const char *label); - int cryptfs_getfield(char *fieldname, char *value, int len); - int cryptfs_setfield(char *fieldname, char *value); - int cryptfs_mount_default_encrypted(void); int cryptfs_get_password_type(void); - char* cryptfs_get_password(void); - void cryptfs_clear_password(void); #ifdef __cplusplus } #endif -- cgit v1.2.3