Support Qualcomm hardware decrypt

Change-Id: I121ef0f5da209be48f6d87559d539c7fc6d85336
diff --git a/crypto/lollipop/cryptfs.c b/crypto/lollipop/cryptfs.c
index 496b960..697593f 100644
--- a/crypto/lollipop/cryptfs.c
+++ b/crypto/lollipop/cryptfs.c
@@ -21,6 +21,7 @@
  */
 
 #include <sys/types.h>
+#include <linux/types.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <ctype.h>
@@ -52,6 +53,10 @@
 
 #define UNUSED __attribute__((unused))
 
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+#include "cryptfs_hw.h"
+#endif
+
 #define DM_CRYPT_BUF_SIZE 4096
 
 #define HASH_COUNT 2000
@@ -592,12 +597,26 @@
   tgt->status = 0;
   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);
+ }
+#else
   strcpy(tgt->target_type, "crypt");
+#endif
 
   crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
   convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
   sprintf(crypt_params, "%s %s 0 %s 0 %s", crypt_ftr->crypto_type_name,
           master_key_ascii, real_blk_name, extra_params);
+
+  printf("%s: target_type = %s\n", __func__, tgt->target_type);
+  printf("%s: real_blk_name = %s, extra_params = %s\n", __func__, real_blk_name, extra_params);
+
   crypt_params += strlen(crypt_params) + 1;
   crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
   tgt->next = crypt_params - buffer;
@@ -623,6 +642,7 @@
     char buffer[DM_CRYPT_BUF_SIZE];
     struct dm_ioctl *io;
     struct dm_target_versions *v;
+    int flag;
     int i;
 
     io = (struct dm_ioctl *) buffer;
@@ -638,7 +658,17 @@
      */
     v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)];
     while (v->next) {
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+        if (is_hw_fde_enabled()) {
+            flag = (!strcmp(v->name, "crypt") || !strcmp(v->name, "req-crypt"));
+        } else {
+            flag = (!strcmp(v->name, "crypt"));
+        }
+        printf("get_dm_crypt_version flag: %i, name: '%s'\n", flag, v->name);
+        if (flag) {
+#else
         if (! strcmp(v->name, "crypt")) {
+#endif
             /* We found the crypt driver, return the version, and get out */
             version[0] = v->version[0];
             version[1] = v->version[1];
@@ -660,12 +690,16 @@
   struct dm_ioctl *io;
   struct dm_target_spec *tgt;
   unsigned int minor;
-  int fd;
+  int fd=0;
   int i;
   int retval = -1;
   int version[3];
   char *extra_params;
   int load_count;
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+  char encrypted_state[PROPERTY_VALUE_MAX] = {0};
+  char progress[PROPERTY_VALUE_MAX] = {0};
+#endif
 
   if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) {
     printf("Cannot open device-mapper\n");
@@ -689,6 +723,31 @@
   minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
   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");
+      }
+  } 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");
+          }
+      }
+  }
+#else
   extra_params = "";
   if (! get_dm_crypt_version(fd, name, version)) {
       /* Support for allow_discards was added in version 1.11.0 */
@@ -698,6 +757,7 @@
           printf("Enabling support for allow_discards in dmcrypt.\n");
       }
   }
+#endif
 
   load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name,
                                          fd, extra_params);
@@ -1020,7 +1080,7 @@
   char crypto_blkdev[MAXPATHLEN];
   char tmp_mount_point[64];
   unsigned int orig_failed_decrypt_count;
-  int rc;
+  int rc = 0;
   kdf_func kdf;
   void *kdf_params;
   int use_keymaster = 0;
@@ -1040,6 +1100,18 @@
     }
   }
 
+#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;
+      }
+    }
+  }
+#endif
+
   // Create crypto block device - all (non fatal) code paths
   // need it
   if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key,
@@ -1207,7 +1279,7 @@
     // an even length, since each character encodes to two characters.
     length = strlen(passwd);
     if (length % 2) {
-        printf("Password not correctly hex encoded.");
+        printf("Password not correctly hex encoded.\n");
         return 0;
     }
 
@@ -1241,10 +1313,10 @@
  * regular character codes to their hexadecimal representation to make
  * decrypt work properly with Android 5.0 lollipop decryption.
  */
-char* hexadj_passwd(const char* passwd)
+char* hexadj_passwd(const char* passwd, int has_hw_crypto)
 {
     size_t index, length;
-    char* ptr = passwd;
+    const char* ptr = passwd;
 
     if (!passwd) {
         return 0;
@@ -1261,7 +1333,15 @@
         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;
 }
 
@@ -1279,22 +1359,36 @@
 {
     struct crypt_mnt_ftr crypt_ftr;
     int rc;
+    int has_hw_crypto = 0;
 
     rc = check_unmounted_and_get_ftr(&crypt_ftr);
     if (rc)
         return rc;
 
-    char* adjusted_passwd = adjust_passwd(passwd);
-    char* hex_passwd = hexadj_passwd(passwd);
+#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
 
-    if (adjusted_passwd) {
+    //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;
-        rc = test_mount_encrypted_fs(&crypt_ftr, adjusted_passwd,
+        //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");
@@ -1305,16 +1399,23 @@
                 printf("TWRP NOT Updating pattern to new format");
                 //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 {
-        rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
-                                     DATA_MNT_POINT, "userdata");
-        if (rc && hex_passwd) {
+        if (hex_passwd) {
+            //printf("2trying hex_passwd '%s'\n", hex_passwd);
             rc = test_mount_encrypted_fs(&crypt_ftr, hex_passwd,
+                                         DATA_MNT_POINT, "userdata");
+        } else {
+            rc = 1;
+        }
+        if (rc && passwd) {
+            //printf("2trying passwd '%s'\n", passwd);
+            rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
                                      DATA_MNT_POINT, "userdata");
         }
     }
@@ -1323,7 +1424,7 @@
         free(hex_passwd);
 
     /*if (rc == 0 && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) {
-		printf("cryptfs_check_passwd update expiry time?\n");
+        printf("cryptfs_check_passwd update expiry time?\n");
         cryptfs_clear_password();
         password = strdup(passwd);
         struct timespec now;