am fc615041: Remove possibility of zero chars from passwords

* commit 'fc61504166d4377a1f83211c236ca11260da1261':
  Remove possibility of zero chars from passwords
diff --git a/cryptfs.c b/cryptfs.c
index e9c6da0..532c92c 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -1929,6 +1929,68 @@
     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) {
+        SLOGW("Password not correctly hex encoded.");
+        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;
+}
+
 int cryptfs_check_passwd(char *passwd)
 {
     struct crypt_mnt_ftr crypt_ftr;
@@ -1938,8 +2000,31 @@
     if (rc)
         return rc;
 
-    rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
-                                 DATA_MNT_POINT, "userdata");
+    char* adjusted_passwd = adjust_passwd(passwd);
+    if (adjusted_passwd) {
+        int failed_decrypt_count = crypt_ftr.failed_decrypt_count;
+        rc = test_mount_encrypted_fs(&crypt_ftr, adjusted_passwd,
+                                     DATA_MNT_POINT, "userdata");
+
+        // Maybe the original one still works?
+        if (rc) {
+            // Don't double count this failure
+            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
+                SLOGI("Updating pattern to new format");
+                cryptfs_changepw(CRYPT_TYPE_PATTERN, passwd);
+            }
+        }
+        free(adjusted_passwd);
+    } else {
+        rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
+                                     DATA_MNT_POINT, "userdata");
+    }
 
     if (rc == 0 && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) {
         cryptfs_clear_password();
@@ -1985,6 +2070,11 @@
         /* 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 */
@@ -1994,6 +2084,8 @@
             sleep(1);
             rc = 1;
         }
+
+        free(adjusted_passwd);
     }
 
     return rc;
@@ -3126,7 +3218,15 @@
 
 int cryptfs_enable(char *howarg, int type, char *passwd, int allow_reboot)
 {
-    return cryptfs_enable_internal(howarg, type, passwd, 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)
@@ -3159,6 +3259,11 @@
 
     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,
@@ -3169,6 +3274,7 @@
     /* save the key */
     put_crypt_ftr_and_key(&crypt_ftr);
 
+    free(adjusted_passwd);
     return 0;
 }