Snap for 4603395 from 291fec178925fe7cd724b3d345bfcfbb98d87f52 to pi-release

Change-Id: Id4ddbb350bb56880864d84766353ddee741d8ffa
diff --git a/cryptfs.cpp b/cryptfs.cpp
index f500a15..234899e 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -72,7 +72,6 @@
 #define DM_CRYPT_BUF_SIZE 4096
 
 #define HASH_COUNT 2000
-#define KEY_LEN_BYTES 16
 #define IV_LEN_BYTES 16
 
 #define KEY_IN_FOOTER  "footer"
@@ -101,11 +100,11 @@
 // EVP_DecryptUpdate() requires not just our key length, but up to
 // block length - 1 additional bytes for its work.  We provide a buffer
 // size that will work for all possible ciphers.
-#define DECRYPTED_MASTER_KEY_BUF_SIZE (KEY_LEN_BYTES + EVP_MAX_BLOCK_LENGTH - 1)
+#define DECRYPTED_MASTER_KEY_BUF_SIZE (MAX_KEY_LEN + EVP_MAX_BLOCK_LENGTH - 1)
 
 static int put_crypt_ftr_and_key(struct crypt_mnt_ftr* crypt_ftr);
 
-static unsigned char saved_master_key[KEY_LEN_BYTES];
+static unsigned char saved_master_key[MAX_KEY_LEN];
 static char *saved_mount_point;
 static int  master_key_saved = 0;
 static struct crypt_persist_data *persist_data = NULL;
@@ -260,6 +259,94 @@
     }
 }
 
+namespace {
+
+struct CryptType;
+
+// Use to get the CryptType in use on this device.
+const CryptType &get_crypt_type();
+
+struct CryptType {
+    const char * name;
+    __le32 keysize;
+
+    constexpr CryptType(const char *n, size_t size) : name(n), keysize(size) {}
+
+ private:
+    friend const CryptType &get_crypt_type();
+    static const CryptType &get_device_crypt_name();
+};
+
+// We only want to parse this read-only property once.  But we need to wait
+// until the system is initialized before we can read it.  So we use a static
+// scoped within this function to get it only once.
+const CryptType &get_crypt_type() {
+    static CryptType crypt_type = CryptType::get_device_crypt_name();
+    return crypt_type;
+}
+
+__le32 get_keysize() {
+    return get_crypt_type().keysize;
+}
+
+const char *get_crypt_name() {
+    return get_crypt_type().name;
+}
+
+
+
+constexpr CryptType default_crypt_type = CryptType("aes-cbc-essiv:sha256", 16);
+
+constexpr CryptType supported_crypt_types[] = {
+    default_crypt_type,
+    CryptType("speck128-xts-plain64", 32),
+    // Add new CryptTypes here.  Order is not important.
+};
+
+
+// ---------- START COMPILE-TIME SANITY CHECK BLOCK -------------------------
+// We confirm all supported_crypt_types have a small enough keysize.
+
+template <typename T, size_t N>
+constexpr size_t array_length(T (&)[N]) { return N; }
+
+constexpr bool indexOutOfBoundsForCryptTypes(size_t index) {
+    return (index >= array_length(supported_crypt_types));
+}
+
+// Note in C++11 that constexpr functions can only have a single line.
+// So our code is a bit convoluted (using recursion instead of a loop),
+// but it's asserting at compile time that all of our key lengths are valid.
+constexpr bool validateSupportedCryptTypes(size_t index) {
+    return indexOutOfBoundsForCryptTypes(index) ||
+        ((supported_crypt_types[index].keysize <= MAX_KEY_LEN) &&
+         validateSupportedCryptTypes(index + 1));
+}
+
+static_assert(validateSupportedCryptTypes(0),
+              "We have a CryptType with keysize > MAX_KEYSIZE");
+//  ---------- END COMPILE-TIME SANITY CHECK BLOCK -------------------------
+
+
+// Don't call this directly, use get_crypt_type(), which caches this result.
+const CryptType &CryptType::get_device_crypt_name() {
+    constexpr char CRYPT_TYPE_PROP[] = "ro.crypto.crypt_type_name";
+    char paramstr[PROPERTY_VALUE_MAX];
+
+    property_get(CRYPT_TYPE_PROP, paramstr, default_crypt_type.name);
+    for (auto const &ctype : supported_crypt_types) {
+        if (strcmp(paramstr, ctype.name) == 0) {
+            return ctype;
+        }
+    }
+    ALOGE("Invalid name (%s) for %s.  Defaulting to %s\n", paramstr,
+          CRYPT_TYPE_PROP, default_crypt_type.name);
+    return default_crypt_type;
+}
+
+}  // namespace
+
+
 /**
  * Gets the default device scrypt parameters for key derivation time tuning.
  * The parameters should lead to about one second derivation time for the
@@ -851,7 +938,7 @@
   struct dm_ioctl *io;
   struct dm_target_spec *tgt;
   char *crypt_params;
-  // We can't assume the key is only KEY_LEN_BYTES.  But we do know its limit
+  // We can't assume the key is only get_keysize().  But we do know its limit
   // due to the crypt_mnt_ftr struct.  We need two ASCII characters to represent
   // each byte, and need space for the '\0' terminator.
   char master_key_ascii[sizeof(crypt_ftr->master_key) * 2 + 1];
@@ -1048,7 +1135,7 @@
 
     /* Turn the password into a key and IV that can decrypt the master key */
     return PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), salt, SALT_LEN,
-                                  HASH_COUNT, KEY_LEN_BYTES + IV_LEN_BYTES,
+                                  HASH_COUNT, get_keysize() + IV_LEN_BYTES,
                                   ikey) != 1;
 }
 
@@ -1066,7 +1153,7 @@
     /* Turn the password into a key and IV that can decrypt the master key */
     crypto_scrypt((const uint8_t*)passwd, strlen(passwd),
                   salt, SALT_LEN, N, r, p, ikey,
-                  KEY_LEN_BYTES + IV_LEN_BYTES);
+                  get_keysize() + IV_LEN_BYTES);
 
    return 0;
 }
@@ -1087,21 +1174,21 @@
 
     rc = crypto_scrypt((const uint8_t*)passwd, strlen(passwd),
                        salt, SALT_LEN, N, r, p, ikey,
-                       KEY_LEN_BYTES + IV_LEN_BYTES);
+                       get_keysize() + IV_LEN_BYTES);
 
     if (rc) {
         SLOGE("scrypt failed");
         return -1;
     }
 
-    if (keymaster_sign_object(ftr, ikey, KEY_LEN_BYTES + IV_LEN_BYTES,
+    if (keymaster_sign_object(ftr, ikey, get_keysize() + IV_LEN_BYTES,
                               &signature, &signature_size)) {
         SLOGE("Signing failed");
         return -1;
     }
 
     rc = crypto_scrypt(signature, signature_size, salt, SALT_LEN,
-                       N, r, p, ikey, KEY_LEN_BYTES + IV_LEN_BYTES);
+                       N, r, p, ikey, get_keysize() + IV_LEN_BYTES);
     free(signature);
 
     if (rc) {
@@ -1117,7 +1204,7 @@
                               unsigned char *encrypted_master_key,
                               struct crypt_mnt_ftr *crypt_ftr)
 {
-    unsigned char ikey[KEY_LEN_BYTES+IV_LEN_BYTES] = { 0 };
+    unsigned char ikey[MAX_KEY_LEN+IV_LEN_BYTES] = { 0 };
     EVP_CIPHER_CTX e_ctx;
     int encrypted_len, final_len;
     int rc = 0;
@@ -1152,7 +1239,7 @@
 
     /* Initialize the decryption engine */
     EVP_CIPHER_CTX_init(&e_ctx);
-    if (! EVP_EncryptInit_ex(&e_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+KEY_LEN_BYTES)) {
+    if (! EVP_EncryptInit_ex(&e_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+get_keysize())) {
         SLOGE("EVP_EncryptInit failed\n");
         return -1;
     }
@@ -1160,7 +1247,7 @@
 
     /* Encrypt the master key */
     if (! EVP_EncryptUpdate(&e_ctx, encrypted_master_key, &encrypted_len,
-                            decrypted_master_key, KEY_LEN_BYTES)) {
+                            decrypted_master_key, get_keysize())) {
         SLOGE("EVP_EncryptUpdate failed\n");
         return -1;
     }
@@ -1169,7 +1256,7 @@
         return -1;
     }
 
-    if (encrypted_len + final_len != KEY_LEN_BYTES) {
+    if (encrypted_len + final_len != static_cast<int>(get_keysize())) {
         SLOGE("EVP_Encryption length check failed with %d, %d bytes\n", encrypted_len, final_len);
         return -1;
     }
@@ -1183,7 +1270,7 @@
     int r = 1 << crypt_ftr->r_factor;
     int p = 1 << crypt_ftr->p_factor;
 
-    rc = crypto_scrypt(ikey, KEY_LEN_BYTES,
+    rc = crypto_scrypt(ikey, get_keysize(),
                        crypt_ftr->salt, sizeof(crypt_ftr->salt), N, r, p,
                        crypt_ftr->scrypted_intermediate_key,
                        sizeof(crypt_ftr->scrypted_intermediate_key));
@@ -1204,7 +1291,7 @@
                                   unsigned char** intermediate_key,
                                   size_t* intermediate_key_size)
 {
-  unsigned char ikey[KEY_LEN_BYTES+IV_LEN_BYTES] = { 0 };
+  unsigned char ikey[MAX_KEY_LEN+IV_LEN_BYTES] = { 0 };
   EVP_CIPHER_CTX d_ctx;
   int decrypted_len, final_len;
 
@@ -1217,29 +1304,29 @@
 
   /* Initialize the decryption engine */
   EVP_CIPHER_CTX_init(&d_ctx);
-  if (! EVP_DecryptInit_ex(&d_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+KEY_LEN_BYTES)) {
+  if (! EVP_DecryptInit_ex(&d_ctx, EVP_aes_128_cbc(), NULL, ikey, ikey+get_keysize())) {
     return -1;
   }
   EVP_CIPHER_CTX_set_padding(&d_ctx, 0); /* Turn off padding as our data is block aligned */
   /* Decrypt the master key */
   if (! EVP_DecryptUpdate(&d_ctx, decrypted_master_key, &decrypted_len,
-                            encrypted_master_key, KEY_LEN_BYTES)) {
+                            encrypted_master_key, get_keysize())) {
     return -1;
   }
   if (! EVP_DecryptFinal_ex(&d_ctx, decrypted_master_key + decrypted_len, &final_len)) {
     return -1;
   }
 
-  if (decrypted_len + final_len != KEY_LEN_BYTES) {
+  if (decrypted_len + final_len != static_cast<int>(get_keysize())) {
     return -1;
   }
 
   /* Copy intermediate key if needed by params */
   if (intermediate_key && intermediate_key_size) {
-    *intermediate_key = (unsigned char*) malloc(KEY_LEN_BYTES);
+    *intermediate_key = (unsigned char*) malloc(get_keysize());
     if (*intermediate_key) {
-      memcpy(*intermediate_key, ikey, KEY_LEN_BYTES);
-      *intermediate_key_size = KEY_LEN_BYTES;
+      memcpy(*intermediate_key, ikey, get_keysize());
+      *intermediate_key_size = get_keysize();
     }
   }
 
@@ -1285,7 +1372,7 @@
 static int create_encrypted_random_key(const char *passwd, unsigned char *master_key, unsigned char *salt,
         struct crypt_mnt_ftr *crypt_ftr) {
     int fd;
-    unsigned char key_buf[KEY_LEN_BYTES];
+    unsigned char key_buf[MAX_KEY_LEN];
 
     /* Get some random bits for a key */
     fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC);
@@ -1683,7 +1770,7 @@
 
     /* 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);
+    memcpy(saved_master_key, decrypted_master_key, get_keysize());
     saved_mount_point = strdup(mount_point);
     master_key_saved = 1;
     SLOGD("%s(): Master key saved\n", __FUNCTION__);
@@ -1758,7 +1845,7 @@
     memset(&ext_crypt_ftr, 0, sizeof(ext_crypt_ftr));
     ext_crypt_ftr.fs_size = nr_sec;
     ext_crypt_ftr.keysize = keysize;
-    strlcpy((char*) ext_crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256",
+    strlcpy((char*) ext_crypt_ftr.crypto_type_name, get_crypt_name(),
             MAX_CRYPTO_TYPE_NAME_LEN);
 
     return create_crypto_blk_dev(
@@ -1901,7 +1988,7 @@
 }
 
 /* Initialize a crypt_mnt_ftr structure.  The keysize is
- * defaulted to 16 bytes, and the filesystem size to 0.
+ * defaulted to get_keysize(), 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.
  */
@@ -1914,7 +2001,7 @@
     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;
+    ftr->keysize = get_keysize();
 
     switch (keymaster_check_compatibility()) {
     case 1:
@@ -2166,7 +2253,7 @@
             crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE;
         }
         crypt_ftr.crypt_type = crypt_type;
-        strlcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", MAX_CRYPTO_TYPE_NAME_LEN);
+        strlcpy((char *)crypt_ftr.crypto_type_name, get_crypt_name(), MAX_CRYPTO_TYPE_NAME_LEN);
 
         /* Make an encrypted master key */
         if (create_encrypted_random_key(onlyCreateHeader ? DEFAULT_PASSWORD : passwd,
@@ -2177,8 +2264,8 @@
 
         /* Replace scrypted intermediate key if we are preparing for a reboot */
         if (onlyCreateHeader) {
-            unsigned char fake_master_key[KEY_LEN_BYTES];
-            unsigned char encrypted_fake_master_key[KEY_LEN_BYTES];
+            unsigned char fake_master_key[MAX_KEY_LEN];
+            unsigned char encrypted_fake_master_key[MAX_KEY_LEN];
             memset(fake_master_key, 0, sizeof(fake_master_key));
             encrypt_master_key(passwd, crypt_ftr.salt, fake_master_key,
                                encrypted_fake_master_key, &crypt_ftr);