Change cryptfs changepw to only require a new password.

The master key is now stored unhashed in memory. This
is needed because certain operation like remote reseting
of passwords the old password is not avaliable.
The changepw interface has been changed to only take
the new password as the only argument. When this is
called we reencrypt the master key with the new password
and old salt.

Bug: 3382129
Change-Id: I9a596b89013194605d6d7790067691aa0dc75e72
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 4459981..daee95d 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -543,12 +543,12 @@
         dumpArgs(argc, argv, 3);
         rc = cryptfs_enable(argv[2], argv[3]);
     } else if (!strcmp(argv[1], "changepw")) {
-        if (argc != 4) {
-            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs changepw <oldpasswd> <newpasswd>", false);
+        if (argc != 3) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs changepw <newpasswd>", false);
             return 0;
         } 
-        SLOGD("cryptfs changepw {} {}");
-        rc = cryptfs_changepw(argv[2], argv[3]);
+        SLOGD("cryptfs changepw {}");
+        rc = cryptfs_changepw(argv[2]);
     } else {
         dumpArgs(argc, argv, -1);
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
diff --git a/cryptfs.c b/cryptfs.c
index f8df447..e3312fb 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -44,10 +44,14 @@
 #define DM_CRYPT_BUF_SIZE 4096
 #define DATA_MNT_POINT "/data"
 
+#define HASH_COUNT 2000
+#define KEY_LEN_BYTES 16
+#define IV_LEN_BYTES 16
+
 char *me = "cryptfs";
 
-static unsigned char saved_key_sha1[20] = { '\0' };
-static int  key_sha1_saved = 0;
+static unsigned char saved_master_key[KEY_LEN_BYTES];
+static int  master_key_saved = 0;
 
 static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
 {
@@ -112,7 +116,7 @@
   }
 
   if (key) {
-    if (crypt_ftr->keysize != 16) {
+    if (crypt_ftr->keysize != KEY_LEN_BYTES) {
       SLOGE("Keysize of %d bits not supported for real block device %s\n",
             crypt_ftr->keysize * 8, real_blk_name);
       goto errout; 
@@ -210,7 +214,7 @@
     }
   }
 
-  if (crypt_ftr->keysize != 16) {
+  if (crypt_ftr->keysize != KEY_LEN_BYTES) {
     SLOGE("Keysize of %d bits not supported for real block device %s\n",
           crypt_ftr->keysize * 8, real_blk_name);
     goto errout;
@@ -368,10 +372,6 @@
 
 }
 
-#define HASH_COUNT 2000
-#define KEY_LEN_BYTES 16
-#define IV_LEN_BYTES 16
-
 static void pbkdf2(char *passwd, unsigned char *salt, unsigned char *ikey)
 {
     /* Turn the password into a key and IV that can decrypt the master key */
@@ -554,7 +554,7 @@
     static int restart_successful = 0;
 
     /* Validate that it's OK to call this routine */
-    if (! key_sha1_saved) {
+    if (! master_key_saved) {
         SLOGE("Encrypted filesystem not validated, aborting");
         return -1;
     }
@@ -639,7 +639,7 @@
   int rc;
 
   property_get("ro.crypto.state", encrypted_state, "");
-  if ( key_sha1_saved || strcmp(encrypted_state, "encrypted") ) {
+  if ( master_key_saved || strcmp(encrypted_state, "encrypted") ) {
     SLOGE("encrypted fs already validated or not running with encryption, aborting");
     return -1;
   }
@@ -700,12 +700,12 @@
      * so we can mount it when restarting the framework.
      */
     property_set("ro.crypto.fs_crypto_blkdev", crypto_blkdev);
-    /* Also save a SHA1 of the master key so we can know if we
-     * successfully decrypted the key when we want to change the
-     * password on it.
+
+    /* Also save a the master key so we can reencrypted the key
+     * the key when we want to change the password on it.
      */
-    SHA1(decrypted_master_key, KEY_LEN_BYTES, saved_key_sha1);
-    key_sha1_saved = 1;
+    memcpy(saved_master_key, decrypted_master_key, KEY_LEN_BYTES);
+    master_key_saved = 1;
     rc = 0;
   }
 
@@ -733,7 +733,7 @@
     ftr->minor_version = 0;
     ftr->ftr_size = sizeof(struct crypt_mnt_ftr);
     ftr->flags = 0;
-    ftr->keysize = 16;
+    ftr->keysize = KEY_LEN_BYTES;
     ftr->spare1 = 0;
     ftr->fs_size = 0;
     ftr->failed_decrypt_count = 0;
@@ -859,7 +859,7 @@
     char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN];
     char fs_type[32], fs_options[256], mount_point[32];
     unsigned long mnt_flags, nr_sec;
-    unsigned char master_key[16], decrypted_master_key[16];
+    unsigned char master_key[KEY_LEN_BYTES], decrypted_master_key[KEY_LEN_BYTES];
     unsigned char salt[SALT_LEN];
     int rc=-1, fd, i;
     struct crypt_mnt_ftr crypt_ftr;
@@ -978,16 +978,15 @@
     return rc;
 }
 
-int cryptfs_changepw(char *oldpw, char *newpw)
+int cryptfs_changepw(char *newpw)
 {
     struct crypt_mnt_ftr crypt_ftr;
-    unsigned char encrypted_master_key[32], decrypted_master_key[32];
+    unsigned char encrypted_master_key[KEY_LEN_BYTES], decrypted_master_key[KEY_LEN_BYTES];
     unsigned char salt[SALT_LEN];
-    unsigned char new_key_sha1[20];
     char real_blkdev[MAXPATHLEN];
 
     /* This is only allowed after we've successfully decrypted the master key */
-    if (! key_sha1_saved) {
+    if (! master_key_saved) {
         SLOGE("Key not saved, aborting");
         return -1;
     }
@@ -1004,24 +1003,10 @@
       return -1;
     }
 
-    /* decrypt key with old passwd */
-    decrypt_master_key(oldpw, salt, encrypted_master_key, decrypted_master_key);
+    encrypt_master_key(newpw, salt, saved_master_key, encrypted_master_key);
 
-    /* compute sha1 of decrypted key */
-    SHA1(decrypted_master_key, KEY_LEN_BYTES, new_key_sha1);
-
-    /* If computed sha1 and saved sha1 match, encrypt key with new passwd */
-    if (! memcmp(saved_key_sha1, new_key_sha1, sizeof(saved_key_sha1))) {
-        /* they match, it's safe to re-encrypt the key */
-        encrypt_master_key(newpw, salt, decrypted_master_key, encrypted_master_key);
-
-        /* save the key */
-        put_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, 0);
-    } else {
-        SLOGE("SHA1 mismatch");
-        return -1;
-    }
+    /* save the key */
+    put_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt);
 
     return 0;
 }
-
diff --git a/cryptfs.h b/cryptfs.h
index 432450c..ca3cc95 100644
--- a/cryptfs.h
+++ b/cryptfs.h
@@ -62,7 +62,7 @@
   int cryptfs_check_passwd(char *pw);
   int cryptfs_restart(void);
   int cryptfs_enable(char *flag, char *passwd);
-  int cryptfs_changepw(char *oldpw, char *newpw);
+  int cryptfs_changepw(char *newpw);
 #ifdef __cplusplus
 }
 #endif