FBE for Pixel 2

Includes various minor fixes for building in Android 8 trees with r23+ tag

Update FBE extended header in libtar to version 2 and include the entire
ext4_encryption_policy structure now after translating the policy.

See this post for more details:
https://plus.google.com/u/1/+DeesTroy/posts/i33ygUi7tiu

Change-Id: I2af981e51f459b17fcd895fb8c2d3f6c8200e24b
diff --git a/adb_install.cpp b/adb_install.cpp
index 771994c..7b03882 100644
--- a/adb_install.cpp
+++ b/adb_install.cpp
@@ -64,9 +64,48 @@
     }
 }
 
+// On Android 8.0 for some reason init can't seem to completely stop adbd
+// so we have to kill it too if it doesn't die on its own.
+static void kill_adbd() {
+    DIR* dir = opendir("/proc");
+    if (dir) {
+        struct dirent* de = 0;
+
+        while ((de = readdir(dir)) != 0) {
+            if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+                continue;
+
+            int pid = -1;
+            int ret = sscanf(de->d_name, "%d", &pid);
+
+            if (ret == 1) {
+                char cmdpath[PATH_MAX];
+                sprintf(cmdpath, "/proc/%d/cmdline", pid);
+
+                FILE* file = fopen(cmdpath, "r");
+                size_t task_size = PATH_MAX;
+                char task[PATH_MAX];
+                char* p = task;
+                if (getline(&p, &task_size, file) > 0) {
+                    if (strstr(task, "adbd") != 0) {
+                        printf("adbd pid %d found, sending kill.\n", pid);
+                        kill(pid, SIGINT);
+                        usleep(5000);
+                        kill(pid, SIGKILL);
+                    }
+                }
+                fclose(file);
+            }
+        }
+        closedir(dir);
+    }
+}
+
 static void stop_adbd() {
     printf("Stopping adbd...\n");
     property_set("ctl.stop", "adbd");
+    usleep(5000);
+    kill_adbd();
     set_usb_driver(false);
 }
 
diff --git a/adbbu/libtwadbbu.cpp b/adbbu/libtwadbbu.cpp
index 0c7f355..64e688c 100644
--- a/adbbu/libtwadbbu.cpp
+++ b/adbbu/libtwadbbu.cpp
@@ -30,6 +30,7 @@
 #include <vector>
 #include <fstream>
 #include <sstream>
+#include <assert.h>
 
 #include "twadbstream.h"
 #include "libtwadbbu.hpp"
@@ -50,8 +51,8 @@
 	bytes = read(fd, &buf, sizeof(buf));
 	close(fd);
 
-	if (memcpy(&adbbuhdr, buf, sizeof(adbbuhdr)) < 0) {
-		printf("Unable to memcpy: %s.\n", fname.c_str(), strerror(errno));
+	if (memcpy(&adbbuhdr, buf, sizeof(adbbuhdr)) == NULL) {
+		printf("Unable to memcpy: %s (%s).\n", fname.c_str(), strerror(errno));
 		return false;
 	}
 	adbbuhdrcrc = adbbuhdr.crc;
@@ -77,7 +78,7 @@
 	while (1) {
 		std::string cmdstr;
 		int readbytes;
-		if (readbytes = read(fd, &buf, sizeof(buf)) > 0) {
+		if ((readbytes = read(fd, &buf, sizeof(buf))) > 0) {
 			memcpy(&structcmd, buf, sizeof(structcmd));
 			assert(structcmd.type == TWENDADB || structcmd.type == TWIMG || structcmd.type == TWFN);
 			cmdstr = structcmd.type;
diff --git a/crypto/ext4crypt/Android.mk b/crypto/ext4crypt/Android.mk
index 8b1dcd4..b32f384 100644
--- a/crypto/ext4crypt/Android.mk
+++ b/crypto/ext4crypt/Android.mk
@@ -5,7 +5,7 @@
 LOCAL_MODULE := libe4crypt
 LOCAL_MODULE_TAGS := eng optional
 LOCAL_CFLAGS :=
-LOCAL_SRC_FILES := Decrypt.cpp Ext4Crypt.cpp Keymaster.cpp KeyStorage.cpp ScryptParameters.cpp Utils.cpp HashPassword.cpp ext4_crypt.cpp
+LOCAL_SRC_FILES := Decrypt.cpp Ext4Crypt.cpp ScryptParameters.cpp Utils.cpp HashPassword.cpp ext4_crypt.cpp
 LOCAL_SHARED_LIBRARIES := libselinux libc libc++ libext4_utils libsoftkeymaster libbase libcrypto libcutils libkeymaster_messages libhardware libprotobuf-cpp-lite
 LOCAL_STATIC_LIBRARIES := libscrypt_static
 LOCAL_C_INCLUDES := system/extras/ext4_utils system/extras/ext4_utils/include/ext4_utils external/scrypt/lib/crypto system/security/keystore hardware/libhardware/include/hardware system/security/softkeymaster/include/keymaster system/keymaster/include
@@ -14,6 +14,16 @@
     LOCAL_CFLAGS += -DTW_CRYPTO_HAVE_KEYMASTERX
     LOCAL_C_INCLUDES +=  external/boringssl/src/include
 endif
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
+    LOCAL_CFLAGS += -DUSE_KEYSTORAGE_3 -DHAVE_LIBKEYUTILS -DHAVE_SYNTH_PWD_SUPPORT -DHAVE_GATEKEEPER1
+    LOCAL_SRC_FILES += Keymaster3.cpp KeyStorage3.cpp
+    LOCAL_SHARED_LIBRARIES += android.hardware.keymaster@3.0 libkeystore_binder libhidlbase libutils libkeyutils libbinder
+    LOCAL_SHARED_LIBRARIES += android.hardware.gatekeeper@1.0
+    LOCAL_SRC_FILES += Weaver1.cpp
+    LOCAL_SHARED_LIBRARIES += android.hardware.weaver@1.0
+else
+    LOCAL_SRC_FILES += Keymaster.cpp KeyStorage.cpp
+endif
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/crypto/ext4crypt/Decrypt.cpp b/crypto/ext4crypt/Decrypt.cpp
index 3b69d46..2dab166 100644
--- a/crypto/ext4crypt/Decrypt.cpp
+++ b/crypto/ext4crypt/Decrypt.cpp
@@ -26,10 +26,50 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include "ext4_crypt.h"
+#ifndef HAVE_LIBKEYUTILS
 #include "key_control.h"
+#else
+#include <keyutils.h>
+#endif
 
+#ifdef HAVE_SYNTH_PWD_SUPPORT
+#include "Weaver1.h"
+#include "cutils/properties.h"
+
+#include <openssl/sha.h>
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+#include <dirent.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fstream>
+
+#include <ext4_utils/ext4_crypt.h>
+
+#include <keystore/IKeystoreService.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <keystore/keystore.h>
+#include <keystore/authorization_set.h>
+
+#include <algorithm>
+extern "C" {
+#include "crypto_scrypt.h"
+}
+#else
+#include "ext4_crypt.h"
+#endif //ifdef HAVE_SYNTH_PWD_SUPPORT
+
+#ifdef HAVE_GATEKEEPER1
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+#else
 #include <hardware/gatekeeper.h>
+#endif
 #include "HashPassword.h"
 
 #include <android-base/file.h>
@@ -67,7 +107,7 @@
 
 extern "C" bool lookup_ref_tar(const char* policy_type, char* policy) {
     if (strncmp(policy_type, "1", 1) != 0) {
-        printf("Unexpected version %c\n", policy_type);
+        printf("Unexpected version %c\n", policy_type[0]);
         return false;
     }
     const char* ptr = policy_type + 1; // skip past the version number
@@ -94,6 +134,7 @@
     return true;
 }
 
+#ifndef HAVE_GATEKEEPER1
 int gatekeeper_device_initialize(gatekeeper_device_t **dev) {
 	int ret;
 	const hw_module_t *mod;
@@ -110,29 +151,7 @@
 		printf("failed to open gatekeeper\n");
 	return ret;
 }
-
-int Get_Password_Type(const userid_t user_id, std::string& filename) {
-	std::string path;
-    if (user_id == 0) {
-		path = "/data/system/";
-	} else {
-		char user_id_str[5];
-		sprintf(user_id_str, "%i", user_id);
-		path = "/data/system/users/";
-		path += user_id_str;
-		path += "/";
-	}
-	filename = path + "gatekeeper.password.key";
-	struct stat st;
-	if (stat(filename.c_str(), &st) == 0 && st.st_size > 0)
-		return 1;
-	filename = path + "gatekeeper.pattern.key";
-	if (stat(filename.c_str(), &st) == 0 && st.st_size > 0)
-		return 2;
-	printf("Unable to locate gatekeeper password file '%s'\n", filename.c_str());
-	filename = "";
-	return 0;
-}
+#endif //ifndef HAVE_GATEKEEPER1
 
 bool Decrypt_DE() {
 	if (!e4crypt_initialize_global_de()) { // this deals with the overarching device encryption
@@ -146,6 +165,692 @@
 	return true;
 }
 
+#ifdef HAVE_SYNTH_PWD_SUPPORT
+// Crappy functions for debugging, please ignore unless you need to debug
+/*void output_hex(const std::string& in) {
+	const char *buf = in.data();
+	char hex[in.size() * 2 + 1];
+	unsigned int index;
+	for (index = 0; index < in.size(); index++)
+		sprintf(&hex[2 * index], "%02X", buf[index]);
+	printf("%s", hex);
+}
+
+void output_hex(const char* buf, const int size) {
+	char hex[size * 2 + 1];
+	int index;
+	for (index = 0; index < size; index++)
+		sprintf(&hex[2 * index], "%02X", buf[index]);
+	printf("%s", hex);
+}
+
+void output_hex(const unsigned char* buf, const int size) {
+	char hex[size * 2 + 1];
+	int index;
+	for (index = 0; index < size; index++)
+		sprintf(&hex[2 * index], "%02X", buf[index]);
+	printf("%s", hex);
+}
+
+void output_hex(std::vector<uint8_t>* vec) {
+	char hex[3];
+	unsigned int index;
+	for (index = 0; index < vec->size(); index++) {
+		sprintf(&hex[0], "%02X", vec->at(index));
+		printf("%s", hex);
+	}
+}*/
+
+/* An alternative is to use:
+ * sqlite3 /data/system/locksettings.db "SELECT value FROM locksettings WHERE name='sp-handle' AND user=0;"
+ * but we really don't want to include the 1.1MB libsqlite in TWRP. We scan the spblob folder for the
+ * password data file (*.pwd) and get the handle from the filename instead. This is a replacement for
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/LockSettingsService.java#2017
+ * We never use this data as an actual long. We always use it as a string. */
+bool Find_Handle(const std::string& spblob_path, std::string& handle_str) {
+	DIR* dir = opendir(spblob_path.c_str());
+	if (!dir) {
+		printf("Error opening '%s'\n", spblob_path.c_str());
+		return false;
+	}
+
+	struct dirent* de = 0;
+
+	while ((de = readdir(dir)) != 0) {
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+		size_t len = strlen(de->d_name);
+		if (len <= 4)
+			continue;
+		char* p = de->d_name;
+		p += len - 4;
+		if (strncmp(p, ".pwd", 4) == 0) {
+			handle_str = de->d_name;
+			handle_str = handle_str.substr(0, len - 4);
+			//*handle = strtoull(handle_str.c_str(), 0 , 16);
+			closedir(dir);
+			return true;
+		}
+	}
+	closedir(dir);
+	return false;
+}
+
+// The password data is stored in big endian and has to be swapped on little endian ARM
+template <class T>
+void endianswap(T *objp) {
+	unsigned char *memp = reinterpret_cast<unsigned char*>(objp);
+	std::reverse(memp, memp + sizeof(T));
+}
+
+/* This is the structure of the data in the password data (*.pwd) file which the structure can be found
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#187 */
+struct password_data_struct {
+	int password_type;
+	unsigned char scryptN;
+	unsigned char scryptR;
+	unsigned char scryptP;
+	int salt_len;
+	void* salt;
+	int handle_len;
+	void* password_handle;
+};
+
+/* C++ replacement for
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#764 */
+bool Get_Password_Data(const std::string& spblob_path, const std::string& handle_str, password_data_struct *pwd) {
+	std::string pwd_file = spblob_path + handle_str + ".pwd";
+	std::string pwd_data;
+	if (!android::base::ReadFileToString(pwd_file, &pwd_data)) {
+		printf("Failed to read '%s'\n", pwd_file.c_str());
+		return false;
+	}
+	//output_hex(pwd_data.data(), pwd_data.size());printf("\n");
+	const int* intptr = (const int*)pwd_data.data();
+	pwd->password_type = *intptr;
+	endianswap(&pwd->password_type);
+	//printf("password type %i\n", pwd->password_type); // 2 was PIN, 1 for pattern, 2 also for password, -1 for default password
+	const unsigned char* byteptr = (const unsigned char*)pwd_data.data() + sizeof(int);
+	pwd->scryptN = *byteptr;
+	byteptr++;
+	pwd->scryptR = *byteptr;
+	byteptr++;
+	pwd->scryptP = *byteptr;
+	byteptr++;
+	intptr = (const int*)byteptr;
+	pwd->salt_len = *intptr;
+	endianswap(&pwd->salt_len);
+	if (pwd->salt_len != 0) {
+		pwd->salt = malloc(pwd->salt_len);
+		if (!pwd->salt) {
+			printf("Get_Password_Data malloc salt\n");
+			return false;
+		}
+		memcpy(pwd->salt, intptr + 1, pwd->salt_len);
+	} else {
+		printf("Get_Password_Data salt_len is 0\n");
+		return false;
+	}
+	return true;
+}
+
+/* C++ replacement for
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#765
+ * called here
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#1050 */
+bool Get_Password_Token(const password_data_struct *pwd, const std::string& Password, unsigned char* password_token) {
+	if (!password_token) {
+		printf("password_token is null\n");
+		return false;
+	}
+	unsigned int N = 1 << pwd->scryptN;
+	unsigned int r = 1 << pwd->scryptR;
+	unsigned int p = 1 << pwd->scryptP;
+	//printf("N %i r %i p %i\n", N, r, p);
+	int ret = crypto_scrypt(reinterpret_cast<const uint8_t*>(Password.data()), Password.size(),
+                          reinterpret_cast<const uint8_t*>(pwd->salt), pwd->salt_len,
+                          N, r, p,
+                          password_token, 32);
+	if (ret != 0) {
+		printf("scrypt error\n");
+		return false;
+	}
+	return true;
+}
+
+// Data structure for the *.weaver file, see Get_Weaver_Data below
+struct weaver_data_struct {
+	unsigned char version;
+	int slot;
+};
+
+/* C++ replacement for
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#501
+ * called here
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#768 */
+bool Get_Weaver_Data(const std::string& spblob_path, const std::string& handle_str, weaver_data_struct *wd) {
+	std::string weaver_file = spblob_path + handle_str + ".weaver";
+	std::string weaver_data;
+	if (!android::base::ReadFileToString(weaver_file, &weaver_data)) {
+		printf("Failed to read '%s'\n", weaver_file.c_str());
+		return false;
+	}
+	//output_hex(weaver_data.data(), weaver_data.size());printf("\n");
+	const unsigned char* byteptr = (const unsigned char*)weaver_data.data();
+	wd->version = *byteptr;
+	//printf("weaver version %i\n", wd->version);
+	const int* intptr = (const int*)weaver_data.data() + sizeof(unsigned char);
+	wd->slot = *intptr;
+	//endianswap(&wd->slot); not needed
+	//printf("weaver slot %i\n", wd->slot);
+	return true;
+}
+
+namespace android {
+
+// On Android 8.0 for some reason init can't seem to completely stop keystore
+// so we have to kill it too if it doesn't die on its own.
+static void kill_keystore() {
+    DIR* dir = opendir("/proc");
+    if (dir) {
+        struct dirent* de = 0;
+
+        while ((de = readdir(dir)) != 0) {
+            if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+                continue;
+
+            int pid = -1;
+            int ret = sscanf(de->d_name, "%d", &pid);
+
+            if (ret == 1) {
+                char cmdpath[PATH_MAX];
+                sprintf(cmdpath, "/proc/%d/cmdline", pid);
+
+                FILE* file = fopen(cmdpath, "r");
+                size_t task_size = PATH_MAX;
+                char task[PATH_MAX];
+                char* p = task;
+                if (getline(&p, &task_size, file) > 0) {
+                    if (strstr(task, "keystore") != 0) {
+                        printf("keystore pid %d found, sending kill.\n", pid);
+                        kill(pid, SIGINT);
+                        usleep(5000);
+                        kill(pid, SIGKILL);
+                    }
+                }
+                fclose(file);
+            }
+        }
+        closedir(dir);
+    }
+}
+
+// The keystore holds a file open on /data so we have to stop / kill it
+// if we want to be able to unmount /data for things like formatting.
+static void stop_keystore() {
+    printf("Stopping keystore...\n");
+    property_set("ctl.stop", "keystore");
+    usleep(5000);
+    kill_keystore();
+}
+
+/* These next 2 functions try to get the keystore service 50 times because
+ * the keystore is not always ready when TWRP boots */
+sp<IBinder> getKeystoreBinder() {
+	sp<IServiceManager> sm = defaultServiceManager();
+    return sm->getService(String16("android.security.keystore"));
+}
+
+sp<IBinder> getKeystoreBinderRetry() {
+	printf("Starting keystore...\n");
+    property_set("ctl.start", "keystore");
+	int retry_count = 50;
+	sp<IBinder> binder = getKeystoreBinder();
+	while (binder == NULL && retry_count) {
+		printf("Waiting for keystore service... %i\n", retry_count--);
+		sleep(1);
+		binder = getKeystoreBinder();
+	}
+	return binder;
+}
+
+namespace keystore {
+
+#define SYNTHETIC_PASSWORD_VERSION 1
+#define SYNTHETIC_PASSWORD_PASSWORD_BASED 0
+#define SYNTHETIC_PASSWORD_KEY_PREFIX "USRSKEY_synthetic_password_"
+
+/* The keystore alias subid is sometimes the same as the handle, but not always.
+ * In the case of handle 0c5303fd2010fe29, the alias subid used c5303fd2010fe29
+ * without the leading 0. We could try to parse the data from a previous
+ * keystore request, but I think this is an easier solution because there
+ * is little to no documentation on the format of data we get back from
+ * the keystore in this instance. We also want to copy everything to a temp
+ * folder so that any key upgrades that might take place do not actually
+ * upgrade the keys on the data partition. We rename all 1000 uid files to 0
+ * to pass the keystore permission checks. */
+bool Find_Keystore_Alias_SubID_And_Prep_Files(const userid_t user_id, std::string& keystoreid) {
+	char path_c[PATH_MAX];
+	sprintf(path_c, "/data/misc/keystore/user_%d", user_id);
+	char user_dir[PATH_MAX];
+	sprintf(user_dir, "user_%d", user_id);
+	std::string source_path = "/data/misc/keystore/";
+	source_path += user_dir;
+
+	mkdir("/tmp/misc", 0755);
+	mkdir("/tmp/misc/keystore", 0755);
+	std::string destination_path = "/tmp/misc/keystore/";
+	destination_path += user_dir;
+	if (mkdir(destination_path.c_str(), 0755) && errno != EEXIST) {
+		printf("failed to mkdir '%s' %s\n", destination_path.c_str(), strerror(errno));
+		return false;
+	}
+	destination_path += "/";
+
+	DIR* dir = opendir(source_path.c_str());
+	if (!dir) {
+		printf("Error opening '%s'\n", source_path.c_str());
+		return false;
+	}
+	source_path += "/";
+
+	struct dirent* de = 0;
+	size_t prefix_len = strlen(SYNTHETIC_PASSWORD_KEY_PREFIX);
+	bool found_subid = false;
+
+	while ((de = readdir(dir)) != 0) {
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+		if (!found_subid) {
+			size_t len = strlen(de->d_name);
+			if (len <= prefix_len)
+				continue;
+			if (!strstr(de->d_name, SYNTHETIC_PASSWORD_KEY_PREFIX))
+				continue;
+			std::string file = de->d_name;
+			std::size_t found = file.find_last_of("_");
+			if (found != std::string::npos) {
+				keystoreid = file.substr(found + 1);
+				printf("keystoreid: '%s'\n", keystoreid.c_str());
+				found_subid = true;
+			}
+		}
+		std::string src = source_path;
+		src += de->d_name;
+		std::ifstream srcif(src.c_str(), std::ios::binary);
+		std::string dst = destination_path;
+		dst += de->d_name;
+		std::size_t source_uid = dst.find("1000");
+		if (source_uid != std::string::npos)
+			dst.replace(source_uid, 4, "0");
+		std::ofstream dstof(dst.c_str(), std::ios::binary);
+		printf("copying '%s' to '%s'\n", src.c_str(), dst.c_str());
+		dstof << srcif.rdbuf();
+		srcif.close();
+		dstof.close();
+	}
+	closedir(dir);
+	return found_subid;
+}
+
+/* C++ replacement for function of the same name
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#867
+ * returning an empty string indicates an error */
+std::string unwrapSyntheticPasswordBlob(const std::string& spblob_path, const std::string& handle_str, const userid_t user_id, const void* application_id, const size_t application_id_size) {
+	std::string disk_decryption_secret_key = "";
+
+	std::string keystore_alias_subid;
+	if (!Find_Keystore_Alias_SubID_And_Prep_Files(user_id, keystore_alias_subid)) {
+		printf("failed to scan keystore alias subid and prep keystore files\n");
+		return disk_decryption_secret_key;
+	}
+
+	// First get the keystore service
+    sp<IBinder> binder = getKeystoreBinderRetry();
+	sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+	if (service == NULL) {
+		printf("error: could not connect to keystore service\n");
+		return disk_decryption_secret_key;
+	}
+
+	// Read the data from the .spblob file per: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#869
+	std::string spblob_file = spblob_path + handle_str + ".spblob";
+	std::string spblob_data;
+	if (!android::base::ReadFileToString(spblob_file, &spblob_data)) {
+		printf("Failed to read '%s'\n", spblob_file.c_str());
+		return disk_decryption_secret_key;
+	}
+	const unsigned char* byteptr = (const unsigned char*)spblob_data.data();
+	if (*byteptr != SYNTHETIC_PASSWORD_VERSION) {
+		printf("SYNTHETIC_PASSWORD_VERSION does not match\n");
+		return disk_decryption_secret_key;
+	}
+	byteptr++;
+	if (*byteptr != SYNTHETIC_PASSWORD_PASSWORD_BASED) {
+		printf("spblob data is not SYNTHETIC_PASSWORD_PASSWORD_BASED\n");
+		return disk_decryption_secret_key;
+	}
+	byteptr++; // Now we're pointing to the blob data itself
+	/* We're now going to handle decryptSPBlob: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java#115
+	 * Called from https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#879
+	 * This small function ends up being quite a headache. The call to get data from the keystore basically is not needed in TWRP at this time.
+	 * The keystore data seems to be the serialized data from an entire class in Java. Specifically I think it represents:
+	 * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+	 * or perhaps
+	 * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+	 * but the only things we "need" from this keystore are a user ID and the keyAlias which ends up being USRSKEY_synthetic_password_{handle_str}
+	 * the latter of which we already have. We may need to figure out how to get the user ID if we ever support decrypting mulitple users.
+	 * There are 2 calls to a Java decrypt funcion that is overloaded. These 2 calls go in completely different directions despite the seemingly
+	 * similar use of decrypt() and decrypt parameters. To figure out where things were going, I added logging to:
+	 * https://android.googlesource.com/platform/libcore/+/android-8.0.0_r23/ojluni/src/main/java/javax/crypto/Cipher.java#2575
+	 * Logger.global.severe("Cipher tryCombinations " + prov.getName() + " - " + prov.getInfo());
+	 * To make logging work in libcore, import java.util.logging.Logger; and either set a better logging level or modify the framework to log everything
+	 * regardless of logging level. This will give you some strings that you can grep for and find the actual crypto provider in use. In our case there were
+	 * 2 different providers in use. The first stage to get the intermediate key used:
+	 * https://android.googlesource.com/platform/external/conscrypt/+/android-8.0.0_r23/common/src/main/java/org/conscrypt/OpenSSLProvider.java
+	 * which is a pretty straight-forward OpenSSL implementation of AES/GCM/NoPadding. */
+	// First we personalize as seen https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java#102
+	void* personalized_application_id = PersonalizedHashBinary(PERSONALISATION_APPLICATION_ID, (const char*)application_id, application_id_size);
+	if (!personalized_application_id) {
+		printf("malloc personalized_application_id\n");
+		return disk_decryption_secret_key;
+	}
+	//printf("personalized application id: "); output_hex((unsigned char*)personalized_application_id, SHA512_DIGEST_LENGTH); printf("\n");
+	// Now we'll decrypt using openssl AES/GCM/NoPadding
+	OpenSSL_add_all_ciphers();
+	int actual_size=0, final_size=0;
+    EVP_CIPHER_CTX *d_ctx = EVP_CIPHER_CTX_new();
+    const unsigned char* iv = (const unsigned char*)byteptr; // The IV is the first 12 bytes of the spblob
+    //printf("iv: "); output_hex((const unsigned char*)iv, 12); printf("\n");
+    const unsigned char* cipher_text = (const unsigned char*)byteptr + 12; // The cipher text comes immediately after the IV
+    //printf("cipher_text: "); output_hex((const unsigned char*)cipher_text, spblob_data.size() - 2 - 12); printf("\n");
+    const unsigned char* key = (const unsigned char*)personalized_application_id; // The key is the now personalized copy of the application ID
+    //printf("key: "); output_hex((const unsigned char*)key, 32); printf("\n");
+    EVP_DecryptInit(d_ctx, EVP_aes_256_gcm(), key, iv);
+    std::vector<unsigned char> intermediate_key;
+    intermediate_key.resize(spblob_data.size() - 2 - 12, '\0');
+    EVP_DecryptUpdate(d_ctx, &intermediate_key[0], &actual_size, cipher_text, spblob_data.size() - 2 - 12);
+    unsigned char tag[AES_BLOCK_SIZE];
+    EVP_CIPHER_CTX_ctrl(d_ctx, EVP_CTRL_GCM_SET_TAG, 16, tag);
+    EVP_DecryptFinal_ex(d_ctx, &intermediate_key[actual_size], &final_size);
+    EVP_CIPHER_CTX_free(d_ctx);
+    free(personalized_application_id);
+    //printf("spblob_data size: %lu actual_size %i, final_size: %i\n", spblob_data.size(), actual_size, final_size);
+    intermediate_key.resize(actual_size + final_size - 16, '\0');// not sure why we have to trim the size by 16 as I don't see where this is done in Java side
+    //printf("intermediate key: "); output_hex((const unsigned char*)intermediate_key.data(), intermediate_key.size()); printf("\n");
+
+	int32_t ret;
+
+	/* We only need a keyAlias which is USRSKEY_synthetic_password_b6f71045af7bd042 which we find and a uid which is -1 or 1000, I forget which
+	 * as the key data will be read again by the begin function later via the keystore.
+	 * The data is in a hidl_vec format which consists of a type and a value. */
+	/*::keystore::hidl_vec<uint8_t> data;
+	std::string keystoreid = SYNTHETIC_PASSWORD_KEY_PREFIX;
+	keystoreid += handle_str;
+
+	ret = service->get(String16(keystoreid.c_str()), user_id, &data);
+	if (ret < 0) {
+		printf("Could not connect to keystore service %i\n", ret);
+		return disk_decryption_secret_key;
+	} else if (ret != 1 /*android::keystore::ResponseCode::NO_ERROR*//*) {
+		printf("keystore error: (%d)\n", /*responses[ret],*//* ret);
+		return disk_decryption_secret_key;
+	} else {
+		printf("keystore returned: "); output_hex(&data[0], data.size()); printf("\n");
+	}*/
+
+	// Now we'll break up the intermediate key into the IV (first 12 bytes) and the cipher text (the rest of it).
+	std::vector<unsigned char> nonce = intermediate_key;
+	nonce.resize(12);
+	intermediate_key.erase (intermediate_key.begin(),intermediate_key.begin()+12);
+	//printf("nonce: "); output_hex((const unsigned char*)nonce.data(), nonce.size()); printf("\n");
+	//printf("cipher text: "); output_hex((const unsigned char*)intermediate_key.data(), intermediate_key.size()); printf("\n");
+
+	/* Now we will begin the second decrypt call found in
+	 * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java#122
+	 * This time we will use https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+	 * and https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+	 * First we set some algorithm parameters as seen in two places:
+	 * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java#297
+	 * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java#216 */
+	size_t maclen = 128;
+	::keystore::AuthorizationSetBuilder begin_params;
+	begin_params.Authorization(::keystore::TAG_ALGORITHM, ::keystore::Algorithm::AES);
+	begin_params.Authorization(::keystore::TAG_BLOCK_MODE, ::keystore::BlockMode::GCM);
+    begin_params.Padding(::keystore::PaddingMode::NONE);
+    begin_params.Authorization(::keystore::TAG_NONCE, nonce);
+    begin_params.Authorization(::keystore::TAG_MAC_LENGTH, maclen);
+	//keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
+	//keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
+	//keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
+	//keymasterArgs.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, mTagLengthBits);
+	::keystore::hidl_vec<uint8_t> entropy; // No entropy is needed for decrypt
+	entropy.resize(0);
+	std::string keystore_alias = SYNTHETIC_PASSWORD_KEY_PREFIX;
+	keystore_alias += keystore_alias_subid;
+	String16 keystore_alias16(keystore_alias.c_str());
+	::keystore::KeyPurpose purpose = ::keystore::KeyPurpose::DECRYPT;
+	OperationResult begin_result;
+	// These parameters are mostly driven by the cipher.init call https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java#63
+	service->begin(binder, keystore_alias16, purpose, true, begin_params.hidl_data(), entropy, -1, &begin_result);
+	ret = begin_result.resultCode;
+	if (ret != 1 /*android::keystore::ResponseCode::NO_ERROR*/) {
+		printf("keystore begin error: (%d)\n", /*responses[ret],*/ ret);
+		return disk_decryption_secret_key;
+	} else {
+		//printf("keystore begin operation successful\n");
+	}
+	::keystore::hidl_vec<::keystore::KeyParameter> empty_params;
+	empty_params.resize(0);
+	OperationResult update_result;
+	// The cipher.doFinal call triggers an update to the keystore followed by a finish https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java#64
+	// See also https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java#208
+	service->update(begin_result.token, empty_params, intermediate_key, &update_result);
+	ret = update_result.resultCode;
+	if (ret != 1 /*android::keystore::ResponseCode::NO_ERROR*/) {
+		printf("keystore update error: (%d)\n", /*responses[ret],*/ ret);
+		return disk_decryption_secret_key;
+	} else {
+		//printf("keystore update operation successful\n");
+		//printf("keystore update returned: "); output_hex(&update_result.data[0], update_result.data.size()); printf("\n"); // this ends up being the synthetic password
+	}
+	// We must use the data in update_data.data before we call finish below or the data will be gone
+	// The payload data from the keystore update is further personalized at https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#153
+	// We now have the disk decryption key!
+	disk_decryption_secret_key = PersonalizedHash(PERSONALIZATION_FBE_KEY, (const char*)&update_result.data[0], update_result.data.size());
+	//printf("disk_decryption_secret_key: '%s'\n", disk_decryption_secret_key.c_str());
+	::keystore::hidl_vec<uint8_t> signature;
+	OperationResult finish_result;
+	service->finish(begin_result.token, empty_params, signature, entropy, &finish_result);
+	ret = finish_result.resultCode;
+	if (ret != 1 /*android::keystore::ResponseCode::NO_ERROR*/) {
+		printf("keystore finish error: (%d)\n", /*responses[ret],*/ ret);
+		return disk_decryption_secret_key;
+	} else {
+		//printf("keystore finish operation successful\n");
+	}
+	stop_keystore();
+	return disk_decryption_secret_key;
+}
+
+}}
+
+#define PASSWORD_TOKEN_SIZE 32
+
+bool Free_Return(bool retval, void* weaver_key, void* pwd_salt) {
+	if (weaver_key)
+		free(weaver_key);
+	if (pwd_salt)
+		free(pwd_salt);
+	return retval;
+}
+
+/* Decrypt_User_Synth_Pass is the TWRP C++ equivalent to spBasedDoVerifyCredential
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/LockSettingsService.java#1998 */
+bool Decrypt_User_Synth_Pass(const userid_t user_id, const std::string& Password) {
+	bool retval = false;
+	void* weaver_key = NULL;
+	password_data_struct pwd;
+	pwd.salt = NULL;
+
+	std::string secret; // this will be the disk decryption key that is sent to vold
+	std::string token = "!"; // there is no token used for this kind of decrypt, key escrow is handled by weaver
+	int flags = FLAG_STORAGE_DE;
+    if (user_id == 0)
+		flags = FLAG_STORAGE_DE;
+	else
+		flags = FLAG_STORAGE_CE;
+	char spblob_path_char[PATH_MAX];
+	sprintf(spblob_path_char, "/data/system_de/%d/spblob/", user_id);
+	std::string spblob_path = spblob_path_char;
+	long handle = 0;
+	std::string handle_str;
+	// Get the handle: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/LockSettingsService.java#2017
+	if (!Find_Handle(spblob_path, handle_str)) {
+		printf("Error getting handle\n");
+		return Free_Return(retval, weaver_key, pwd.salt);
+	}
+	printf("Handle is '%s'\n", handle_str.c_str());
+	// Now we begin driving unwrapPasswordBasedSyntheticPassword from: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#758
+	// First we read the password data which contains scrypt parameters
+	if (!Get_Password_Data(spblob_path, handle_str, &pwd)) {
+		printf("Failed to Get_Password_Data\n");
+		return Free_Return(retval, weaver_key, pwd.salt);
+	}
+	//printf("pwd N %i R %i P %i salt ", pwd.scryptN, pwd.scryptR, pwd.scryptP); output_hex((char*)pwd.salt, pwd.salt_len); printf("\n");
+	unsigned char password_token[PASSWORD_TOKEN_SIZE];
+	//printf("Password: '%s'\n", Password.c_str());
+	// The password token is the password scrypted with the parameters from the password data file
+	if (!Get_Password_Token(&pwd, Password, &password_token[0])) {
+		printf("Failed to Get_Password_Token\n");
+		return Free_Return(retval, weaver_key, pwd.salt);
+	}
+	//output_hex(&password_token[0], PASSWORD_TOKEN_SIZE);printf("\n");
+	// BEGIN PIXEL 2 WEAVER
+	// Get the weaver data from the .weaver file which tells us which slot to use when we ask weaver for the escrowed key
+	// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#768
+	weaver_data_struct wd;
+	if (!Get_Weaver_Data(spblob_path, handle_str, &wd)) {
+		printf("Failed to get weaver data\n");
+		// Fail over to gatekeeper path for Pixel 1???
+		return Free_Return(retval, weaver_key, pwd.salt);
+	}
+	// The weaver key is the the password token prefixed with "weaver-key" padded to 128 with nulls with the password token appended then SHA512
+	// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#1059
+	weaver_key = PersonalizedHashBinary(PERSONALISATION_WEAVER_KEY, (char*)&password_token[0], PASSWORD_TOKEN_SIZE);
+	if (!weaver_key) {
+		printf("malloc error getting weaver_key\n");
+		return Free_Return(retval, weaver_key, pwd.salt);
+	}
+	// Now we start driving weaverVerify: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#343
+	// Called from https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#776
+	android::vold::Weaver weaver;
+    if (!weaver) {
+		printf("Failed to get weaver service\n");
+		return Free_Return(retval, weaver_key, pwd.salt);
+	}
+	// Get the key size from weaver service
+	uint32_t weaver_key_size = 0;
+	if (!weaver.GetKeySize(&weaver_key_size)) {
+		printf("Failed to get weaver key size\n");
+		return Free_Return(retval, weaver_key, pwd.salt);
+	} else {
+		//printf("weaver key size is %u\n", weaver_key_size);
+	}
+	//printf("weaver key: "); output_hex((unsigned char*)weaver_key, weaver_key_size); printf("\n");
+	// Send the slot from the .weaver file, the computed weaver key, and get the escrowed key data
+	std::vector<uint8_t> weaver_payload;
+	// TODO: we should return more information about the status including time delays before the next retry
+	if (!weaver.WeaverVerify(wd.slot, weaver_key, &weaver_payload)) {
+		printf("failed to weaver verify\n");
+		return Free_Return(retval, weaver_key, pwd.salt);
+	}
+	//printf("weaver payload: "); output_hex(&weaver_payload); printf("\n");
+	// Done with weaverVerify
+	// Now we will compute the application ID
+	// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#964
+	// Called from https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#780
+	// The escrowed weaver key data is prefixed with "weaver-pwd" padded to 128 with nulls with the weaver payload appended then SHA512
+	void* weaver_secret = PersonalizedHashBinary(PERSONALISATION_WEAVER_PASSWORD, (const char*)weaver_payload.data(), weaver_payload.size());
+	//printf("weaver secret: "); output_hex((unsigned char*)weaver_secret, SHA512_DIGEST_LENGTH); printf("\n");
+	// The application ID is the password token and weaver secret appended to each other
+	char application_id[PASSWORD_TOKEN_SIZE + SHA512_DIGEST_LENGTH];
+	memcpy((void*)&application_id[0], (void*)&password_token[0], PASSWORD_TOKEN_SIZE);
+	memcpy((void*)&application_id[PASSWORD_TOKEN_SIZE], weaver_secret, SHA512_DIGEST_LENGTH);
+	//printf("application ID: "); output_hex((unsigned char*)application_id, PASSWORD_TOKEN_SIZE + SHA512_DIGEST_LENGTH); printf("\n");
+	// END PIXEL 2 WEAVER
+	// Now we will handle https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#816
+	// Plus we will include the last bit that computes the disk decrypt key found in:
+	// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#153
+	secret = android::keystore::unwrapSyntheticPasswordBlob(spblob_path, handle_str, user_id, (const void*)&application_id[0], PASSWORD_TOKEN_SIZE + SHA512_DIGEST_LENGTH);
+	if (!secret.size()) {
+		printf("failed to unwrapSyntheticPasswordBlob\n");
+		return Free_Return(retval, weaver_key, pwd.salt);
+	}
+	if (!e4crypt_unlock_user_key(user_id, 0, token.c_str(), secret.c_str())) {
+		printf("e4crypt_unlock_user_key returned fail\n");
+		return Free_Return(retval, weaver_key, pwd.salt);
+	}
+	if (!e4crypt_prepare_user_storage(nullptr, user_id, 0, flags)) {
+		printf("failed to e4crypt_prepare_user_storage\n");
+		return Free_Return(retval, weaver_key, pwd.salt);
+	}
+	printf("Decrypted Successfully!\n");
+	retval = true;
+	return Free_Return(retval, weaver_key, pwd.salt);
+}
+#endif //HAVE_SYNTH_PWD_SUPPORT
+
+int Get_Password_Type(const userid_t user_id, std::string& filename) {
+	struct stat st;
+	char spblob_path_char[PATH_MAX];
+	sprintf(spblob_path_char, "/data/system_de/%d/spblob/", user_id);
+	if (stat(spblob_path_char, &st) == 0) {
+#ifdef HAVE_SYNTH_PWD_SUPPORT
+		printf("Using synthetic password method\n");
+		std::string spblob_path = spblob_path_char;
+		std::string handle_str;
+		if (!Find_Handle(spblob_path, handle_str)) {
+			printf("Error getting handle\n");
+			return 0;
+		}
+		printf("Handle is '%s'\n", handle_str.c_str());
+		password_data_struct pwd;
+		if (!Get_Password_Data(spblob_path, handle_str, &pwd)) {
+			printf("Failed to Get_Password_Data\n");
+			return 0;
+		}
+		if (pwd.password_type == 1) // In Android this means pattern
+			return 2; // In TWRP this means pattern
+		else if (pwd.password_type == 2) // In Android this means PIN or password
+			return 1; // In TWRP this means PIN or password
+		return 0; // We'll try the default password
+#else
+		printf("Synthetic password support not present in TWRP\n");
+		return -1;
+#endif
+	}
+	std::string path;
+    if (user_id == 0) {
+		path = "/data/system/";
+	} else {
+		char user_id_str[5];
+		sprintf(user_id_str, "%i", user_id);
+		path = "/data/system/users/";
+		path += user_id_str;
+		path += "/";
+	}
+	filename = path + "gatekeeper.password.key";
+	if (stat(filename.c_str(), &st) == 0 && st.st_size > 0)
+		return 1;
+	filename = path + "gatekeeper.pattern.key";
+	if (stat(filename.c_str(), &st) == 0 && st.st_size > 0)
+		return 2;
+	printf("Unable to locate gatekeeper password file '%s'\n", filename.c_str());
+	filename = "";
+	return 0;
+}
+
 bool Decrypt_User(const userid_t user_id, const std::string& Password) {
     uint8_t *auth_token;
     uint32_t auth_token_len;
@@ -167,8 +872,6 @@
 		flags = FLAG_STORAGE_DE;
 	else
 		flags = FLAG_STORAGE_CE;
-	gatekeeper_device_t *device;
-	ret = gatekeeper_device_initialize(&device);
 	if (Default_Password) {
 		if (!e4crypt_unlock_user_key(user_id, 0, "!", "!")) {
 			printf("e4crypt_unlock_user_key returned fail\n");
@@ -181,8 +884,15 @@
 		printf("Decrypted Successfully!\n");
 		return true;
 	}
-    if (ret!=0)
+	if (stat("/data/system_de/0/spblob", &st) == 0) {
+#ifdef HAVE_SYNTH_PWD_SUPPORT
+		printf("Using synthetic password method\n");
+		return Decrypt_User_Synth_Pass(user_id, Password);
+#else
+		printf("Synthetic password support not present in TWRP\n");
 		return false;
+#endif
+	}
 	printf("password filename is '%s'\n", filename.c_str());
 	if (stat(filename.c_str(), &st) != 0) {
 		printf("error stat'ing key file: %s\n", strerror(errno));
@@ -194,13 +904,51 @@
 		return false;
 	}
     bool should_reenroll;
-    ret = device->verify(device, user_id, 0, (const uint8_t *)handle.c_str(), st.st_size,
+#ifdef HAVE_GATEKEEPER1
+	bool request_reenroll = false;
+	android::sp<android::hardware::gatekeeper::V1_0::IGatekeeper> gk_device;
+	gk_device = ::android::hardware::gatekeeper::V1_0::IGatekeeper::getService();
+	if (gk_device == nullptr)
+		return false;
+	android::hardware::hidl_vec<uint8_t> curPwdHandle;
+	curPwdHandle.setToExternal(const_cast<uint8_t *>((const uint8_t *)handle.c_str()), st.st_size);
+	android::hardware::hidl_vec<uint8_t> enteredPwd;
+	enteredPwd.setToExternal(const_cast<uint8_t *>((const uint8_t *)Password.c_str()), Password.size());
+
+	android::hardware::Return<void> hwRet =
+		gk_device->verify(user_id, 0 /* challange */,
+						  curPwdHandle,
+						  enteredPwd,
+						  [&ret, &request_reenroll, &auth_token, &auth_token_len]
+							(const android::hardware::gatekeeper::V1_0::GatekeeperResponse &rsp) {
+								ret = static_cast<int>(rsp.code); // propagate errors
+								if (rsp.code >= android::hardware::gatekeeper::V1_0::GatekeeperStatusCode::STATUS_OK) {
+									auth_token = new uint8_t[rsp.data.size()];
+									auth_token_len = rsp.data.size();
+									memcpy(auth_token, rsp.data.data(), auth_token_len);
+									request_reenroll = (rsp.code == android::hardware::gatekeeper::V1_0::GatekeeperStatusCode::STATUS_REENROLL);
+									ret = 0; // all success states are reported as 0
+								} else if (rsp.code == android::hardware::gatekeeper::V1_0::GatekeeperStatusCode::ERROR_RETRY_TIMEOUT && rsp.timeout > 0) {
+									ret = rsp.timeout;
+								}
+							}
+						 );
+	if (!hwRet.isOk()) {
+		return false;
+	}
+#else
+	gatekeeper_device_t *gk_device;
+	ret = gatekeeper_device_initialize(&gk_device);
+    if (ret!=0)
+		return false;
+    ret = gk_device->verify(gk_device, user_id, 0, (const uint8_t *)handle.c_str(), st.st_size,
                 (const uint8_t *)Password.c_str(), (uint32_t)Password.size(), &auth_token, &auth_token_len,
                 &should_reenroll);
     if (ret !=0) {
 		printf("failed to verify\n");
 		return false;
 	}
+#endif
 	char token_hex[(auth_token_len*2)+1];
 	token_hex[(auth_token_len*2)] = 0;
 	uint32_t i;
diff --git a/crypto/ext4crypt/Ext4Crypt.cpp b/crypto/ext4crypt/Ext4Crypt.cpp
index 8bc4199..ea5b1cf 100644
--- a/crypto/ext4crypt/Ext4Crypt.cpp
+++ b/crypto/ext4crypt/Ext4Crypt.cpp
@@ -41,8 +41,16 @@
 
 #include <private/android_filesystem_config.h>
 
+#ifdef HAVE_SYNTH_PWD_SUPPORT
+#include <ext4_utils/ext4_crypt.h>
+#else
 #include "ext4_crypt.h"
+#endif
+#ifndef HAVE_LIBKEYUTILS
 #include "key_control.h"
+#else
+#include <keyutils.h>
+#endif
 
 #include <hardware/gatekeeper.h>
 #include "HashPassword.h"
diff --git a/crypto/ext4crypt/HashPassword.cpp b/crypto/ext4crypt/HashPassword.cpp
index 86e067e..817c984 100644
--- a/crypto/ext4crypt/HashPassword.cpp
+++ b/crypto/ext4crypt/HashPassword.cpp
@@ -28,16 +28,37 @@
 #include <stdlib.h>
 #include <openssl/sha.h>
 
+#include "HashPassword.h"
+
 #define PASS_PADDING_SIZE 128
 #define SHA512_HEX_SIZE SHA512_DIGEST_LENGTH * 2
 
-std::string HashPassword(const std::string& Password) {
-	size_t size = PASS_PADDING_SIZE + Password.size();
+void* PersonalizedHashBinary(const char* prefix, const char* key, const size_t key_size) {
+	size_t size = PASS_PADDING_SIZE + key_size;
 	unsigned char* buffer = (unsigned char*)calloc(1, size);
-	const char* prefix = "Android FBE credential hash";
+	if (!buffer) return NULL; // failed to malloc
 	memcpy((void*)buffer, (void*)prefix, strlen(prefix));
 	unsigned char* ptr = buffer + PASS_PADDING_SIZE;
-	memcpy((void*)ptr, Password.c_str(), Password.size());
+	memcpy((void*)ptr, key, key_size);
+	unsigned char hash[SHA512_DIGEST_LENGTH];
+	SHA512_CTX sha512;
+	SHA512_Init(&sha512);
+	SHA512_Update(&sha512, buffer, size);
+	SHA512_Final(hash, &sha512);
+	free(buffer);
+	void* ret = malloc(SHA512_DIGEST_LENGTH);
+	if (!ret) return NULL; // failed to malloc
+	memcpy(ret, (void*)&hash[0], SHA512_DIGEST_LENGTH);
+	return ret;
+}
+
+std::string PersonalizedHash(const char* prefix, const char* key, const size_t key_size) {
+	size_t size = PASS_PADDING_SIZE + key_size;
+	unsigned char* buffer = (unsigned char*)calloc(1, size);
+	if (!buffer) return ""; // failed to malloc
+	memcpy((void*)buffer, (void*)prefix, strlen(prefix));
+	unsigned char* ptr = buffer + PASS_PADDING_SIZE;
+	memcpy((void*)ptr, key, key_size);
 	unsigned char hash[SHA512_DIGEST_LENGTH];
 	SHA512_CTX sha512;
 	SHA512_Init(&sha512);
@@ -49,5 +70,15 @@
 		sprintf(hex_hash + (index * 2), "%02X", hash[index]);
 	hex_hash[128] = 0;
 	std::string ret = hex_hash;
+	free(buffer);
 	return ret;
 }
+
+std::string PersonalizedHash(const char* prefix, const std::string& Password) {
+	return PersonalizedHash(prefix, Password.c_str(), Password.size());
+}
+
+std::string HashPassword(const std::string& Password) {
+	const char* prefix = FBE_PERSONALIZATION;
+	return PersonalizedHash(prefix, Password);
+}
diff --git a/crypto/ext4crypt/HashPassword.h b/crypto/ext4crypt/HashPassword.h
index d9b5ce5..8abd0de 100644
--- a/crypto/ext4crypt/HashPassword.h
+++ b/crypto/ext4crypt/HashPassword.h
@@ -19,6 +19,16 @@
 
 #include <string>
 
+#define FBE_PERSONALIZATION "Android FBE credential hash"
+#define PERSONALISATION_WEAVER_KEY "weaver-key"
+#define PERSONALISATION_WEAVER_PASSWORD "weaver-pwd"
+#define PERSONALISATION_APPLICATION_ID "application-id"
+#define PERSONALIZATION_FBE_KEY "fbe-key"
+
+void* PersonalizedHashBinary(const char* prefix, const char* key, const size_t key_size);
+
+std::string PersonalizedHash(const char* prefix, const char* key, const size_t key_size);
+std::string PersonalizedHash(const char* prefix, const std::string& Password);
 std::string HashPassword(const std::string& Password);
 
 #endif
diff --git a/crypto/ext4crypt/KeyStorage3.cpp b/crypto/ext4crypt/KeyStorage3.cpp
new file mode 100644
index 0000000..a07212d
--- /dev/null
+++ b/crypto/ext4crypt/KeyStorage3.cpp
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KeyStorage3.h"
+
+#include "Keymaster3.h"
+#include "ScryptParameters.h"
+#include "Utils.h"
+
+#include <vector>
+
+#include <errno.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+
+#include <android-base/file.h>
+//#include <android-base/logging.h>
+
+#include <cutils/properties.h>
+
+#include <hardware/hw_auth_token.h>
+
+#include <keystore/authorization_set.h>
+#include <keystore/keystore_hidl_support.h>
+
+extern "C" {
+
+#include "crypto_scrypt.h"
+}
+
+#include <iostream>
+#define ERROR 1
+#define LOG(x) std::cout
+#define PLOG(x) std::cout
+
+namespace android {
+namespace vold {
+using namespace keystore;
+
+const KeyAuthentication kEmptyAuthentication{"", ""};
+
+static constexpr size_t AES_KEY_BYTES = 32;
+static constexpr size_t GCM_NONCE_BYTES = 12;
+static constexpr size_t GCM_MAC_BYTES = 16;
+static constexpr size_t SALT_BYTES = 1 << 4;
+static constexpr size_t SECDISCARDABLE_BYTES = 1 << 14;
+static constexpr size_t STRETCHED_BYTES = 1 << 6;
+
+static constexpr uint32_t AUTH_TIMEOUT = 30; // Seconds
+
+static const char* kCurrentVersion = "1";
+static const char* kRmPath = "/system/bin/rm";
+static const char* kSecdiscardPath = "/system/bin/secdiscard";
+static const char* kStretch_none = "none";
+static const char* kStretch_nopassword = "nopassword";
+static const std::string kStretchPrefix_scrypt = "scrypt ";
+static const char* kHashPrefix_secdiscardable = "Android secdiscardable SHA512";
+static const char* kHashPrefix_keygen = "Android key wrapping key generation SHA512";
+static const char* kFn_encrypted_key = "encrypted_key";
+static const char* kFn_keymaster_key_blob = "keymaster_key_blob";
+static const char* kFn_keymaster_key_blob_upgraded = "keymaster_key_blob_upgraded";
+static const char* kFn_salt = "salt";
+static const char* kFn_secdiscardable = "secdiscardable";
+static const char* kFn_stretching = "stretching";
+static const char* kFn_version = "version";
+
+static bool checkSize(const std::string& kind, size_t actual, size_t expected) {
+    if (actual != expected) {
+        LOG(ERROR) << "Wrong number of bytes in " << kind << ", expected " << expected << " got "
+                   << actual;
+        return false;
+    }
+    return true;
+}
+
+static std::string hashWithPrefix(char const* prefix, const std::string& tohash) {
+    SHA512_CTX c;
+
+    SHA512_Init(&c);
+    // Personalise the hashing by introducing a fixed prefix.
+    // Hashing applications should use personalization except when there is a
+    // specific reason not to; see section 4.11 of https://www.schneier.com/skein1.3.pdf
+    std::string hashingPrefix = prefix;
+    hashingPrefix.resize(SHA512_CBLOCK);
+    SHA512_Update(&c, hashingPrefix.data(), hashingPrefix.size());
+    SHA512_Update(&c, tohash.data(), tohash.size());
+    std::string res(SHA512_DIGEST_LENGTH, '\0');
+    SHA512_Final(reinterpret_cast<uint8_t*>(&res[0]), &c);
+    return res;
+}
+
+/*static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& auth,
+                                 const std::string& appId, std::string* key) {
+    auto paramBuilder = AuthorizationSetBuilder()
+                            .AesEncryptionKey(AES_KEY_BYTES * 8)
+                            .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                            .Authorization(TAG_MIN_MAC_LENGTH, GCM_MAC_BYTES * 8)
+                            .Authorization(TAG_PADDING, PaddingMode::NONE)
+                            .Authorization(TAG_APPLICATION_ID, blob2hidlVec(appId));
+    if (auth.token.empty()) {
+        LOG(DEBUG) << "Creating key that doesn't need auth token";
+        paramBuilder.Authorization(TAG_NO_AUTH_REQUIRED);
+    } else {
+        LOG(DEBUG) << "Auth token required for key";
+        if (auth.token.size() != sizeof(hw_auth_token_t)) {
+            LOG(ERROR) << "Auth token should be " << sizeof(hw_auth_token_t) << " bytes, was "
+                       << auth.token.size() << " bytes";
+            return false;
+        }
+        const hw_auth_token_t* at = reinterpret_cast<const hw_auth_token_t*>(auth.token.data());
+        paramBuilder.Authorization(TAG_USER_SECURE_ID, at->user_id);
+        paramBuilder.Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD);
+        paramBuilder.Authorization(TAG_AUTH_TIMEOUT, AUTH_TIMEOUT);
+    }
+    return keymaster.generateKey(paramBuilder, key);
+}*/
+
+static AuthorizationSet beginParams(const KeyAuthentication& auth,
+                                               const std::string& appId) {
+    auto paramBuilder = AuthorizationSetBuilder()
+                            .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                            .Authorization(TAG_MAC_LENGTH, GCM_MAC_BYTES * 8)
+                            .Authorization(TAG_PADDING, PaddingMode::NONE)
+                            .Authorization(TAG_APPLICATION_ID, blob2hidlVec(appId));
+    if (!auth.token.empty()) {
+        LOG(DEBUG) << "Supplying auth token to Keymaster";
+        paramBuilder.Authorization(TAG_AUTH_TOKEN, blob2hidlVec(auth.token));
+    }
+    return paramBuilder;
+}
+
+static bool readFileToString(const std::string& filename, std::string* result) {
+    if (!android::base::ReadFileToString(filename, result)) {
+        PLOG(ERROR) << "Failed to read from " << filename;
+        return false;
+    }
+    return true;
+}
+
+static bool writeStringToFile(const std::string& payload, const std::string& filename) {
+    if (!android::base::WriteStringToFile(payload, filename)) {
+        PLOG(ERROR) << "Failed to write to " << filename;
+        return false;
+    }
+    return true;
+}
+
+static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir,
+                                KeyPurpose purpose,
+                                const AuthorizationSet &keyParams,
+                                const AuthorizationSet &opParams,
+                                AuthorizationSet* outParams) {
+    auto kmKeyPath = dir + "/" + kFn_keymaster_key_blob;
+    std::string kmKey;
+    if (!readFileToString(kmKeyPath, &kmKey)) return KeymasterOperation();
+    AuthorizationSet inParams(keyParams);
+    inParams.append(opParams.begin(), opParams.end());
+    for (;;) {
+        auto opHandle = keymaster.begin(purpose, kmKey, inParams, outParams);
+        if (opHandle) {
+            return opHandle;
+        }
+        if (opHandle.errorCode() != ErrorCode::KEY_REQUIRES_UPGRADE) return opHandle;
+        LOG(DEBUG) << "Upgrading key: " << dir;
+        std::string newKey;
+        if (!keymaster.upgradeKey(kmKey, keyParams, &newKey)) return KeymasterOperation();
+        // Upgrade the key in memory but do not replace the key in storage
+        /*auto newKeyPath = dir + "/" + kFn_keymaster_key_blob_upgraded;
+        if (!writeStringToFile(newKey, newKeyPath)) return KeymasterOperation();
+        if (rename(newKeyPath.c_str(), kmKeyPath.c_str()) != 0) {
+            PLOG(ERROR) << "Unable to move upgraded key to location: " << kmKeyPath;
+            return KeymasterOperation();
+        }
+        if (!keymaster.deleteKey(kmKey)) {
+            LOG(ERROR) << "Key deletion failed during upgrade, continuing anyway: " << dir;
+        }*/
+        kmKey = newKey;
+        LOG(INFO) << "Key upgraded: " << dir;
+    }
+}
+
+/*static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
+                                    const AuthorizationSet &keyParams,
+                                    const std::string& message, std::string* ciphertext) {
+    AuthorizationSet opParams;
+    AuthorizationSet outParams;
+    auto opHandle = begin(keymaster, dir, KeyPurpose::ENCRYPT, keyParams, opParams, &outParams);
+    if (!opHandle) return false;
+    auto nonceBlob = outParams.GetTagValue(TAG_NONCE);
+    if (!nonceBlob.isOk()) {
+        LOG(ERROR) << "GCM encryption but no nonce generated";
+        return false;
+    }
+    // nonceBlob here is just a pointer into existing data, must not be freed
+    std::string nonce(reinterpret_cast<const char*>(&nonceBlob.value()[0]), nonceBlob.value().size());
+    if (!checkSize("nonce", nonce.size(), GCM_NONCE_BYTES)) return false;
+    std::string body;
+    if (!opHandle.updateCompletely(message, &body)) return false;
+
+    std::string mac;
+    if (!opHandle.finish(&mac)) return false;
+    if (!checkSize("mac", mac.size(), GCM_MAC_BYTES)) return false;
+    *ciphertext = nonce + body + mac;
+    return true;
+}*/
+
+static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
+                                    const AuthorizationSet &keyParams,
+                                    const std::string& ciphertext, std::string* message) {
+    auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES);
+    auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES);
+    auto opParams = AuthorizationSetBuilder()
+            .Authorization(TAG_NONCE, blob2hidlVec(nonce));
+    auto opHandle = begin(keymaster, dir, KeyPurpose::DECRYPT, keyParams, opParams, nullptr);
+    if (!opHandle) return false;
+    if (!opHandle.updateCompletely(bodyAndMac, message)) return false;
+    if (!opHandle.finish(nullptr)) return false;
+    return true;
+}
+
+static std::string getStretching(const KeyAuthentication& auth) {
+    if (!auth.usesKeymaster()) {
+        return kStretch_none;
+    } else if (auth.secret.empty()) {
+        return kStretch_nopassword;
+    } else {
+        char paramstr[PROPERTY_VALUE_MAX];
+
+        property_get(SCRYPT_PROP, paramstr, SCRYPT_DEFAULTS);
+        return std::string() + kStretchPrefix_scrypt + paramstr;
+    }
+}
+
+static bool stretchingNeedsSalt(const std::string& stretching) {
+    return stretching != kStretch_nopassword && stretching != kStretch_none;
+}
+
+static bool stretchSecret(const std::string& stretching, const std::string& secret,
+                          const std::string& salt, std::string* stretched) {
+    if (stretching == kStretch_nopassword) {
+        if (!secret.empty()) {
+            LOG(WARNING) << "Password present but stretching is nopassword";
+            // Continue anyway
+        }
+        stretched->clear();
+    } else if (stretching == kStretch_none) {
+        *stretched = secret;
+    } else if (std::equal(kStretchPrefix_scrypt.begin(), kStretchPrefix_scrypt.end(),
+                          stretching.begin())) {
+        int Nf, rf, pf;
+        if (!parse_scrypt_parameters(stretching.substr(kStretchPrefix_scrypt.size()).c_str(), &Nf,
+                                     &rf, &pf)) {
+            LOG(ERROR) << "Unable to parse scrypt params in stretching: " << stretching;
+            return false;
+        }
+        stretched->assign(STRETCHED_BYTES, '\0');
+        if (crypto_scrypt(reinterpret_cast<const uint8_t*>(secret.data()), secret.size(),
+                          reinterpret_cast<const uint8_t*>(salt.data()), salt.size(),
+                          1 << Nf, 1 << rf, 1 << pf,
+                          reinterpret_cast<uint8_t*>(&(*stretched)[0]), stretched->size()) != 0) {
+            LOG(ERROR) << "scrypt failed with params: " << stretching;
+            return false;
+        }
+    } else {
+        LOG(ERROR) << "Unknown stretching type: " << stretching;
+        return false;
+    }
+    return true;
+}
+
+static bool generateAppId(const KeyAuthentication& auth, const std::string& stretching,
+                          const std::string& salt, const std::string& secdiscardable,
+                          std::string* appId) {
+    std::string stretched;
+    if (!stretchSecret(stretching, auth.secret, salt, &stretched)) return false;
+    *appId = hashWithPrefix(kHashPrefix_secdiscardable, secdiscardable) + stretched;
+    return true;
+}
+
+static bool readRandomBytesOrLog(size_t count, std::string* out) {
+    auto status = ReadRandomBytes(count, *out);
+    if (status != OK) {
+        LOG(ERROR) << "Random read failed with status: " << status;
+        return false;
+    }
+    return true;
+}
+
+static void logOpensslError() {
+    LOG(ERROR) << "Openssl error: " << ERR_get_error();
+}
+
+static bool encryptWithoutKeymaster(const std::string& preKey,
+                                    const std::string& plaintext, std::string* ciphertext) {
+    auto key = hashWithPrefix(kHashPrefix_keygen, preKey);
+    key.resize(AES_KEY_BYTES);
+    if (!readRandomBytesOrLog(GCM_NONCE_BYTES, ciphertext)) return false;
+    auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>(
+        EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
+    if (!ctx) {
+        logOpensslError();
+        return false;
+    }
+    if (1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL,
+            reinterpret_cast<const uint8_t*>(key.data()),
+            reinterpret_cast<const uint8_t*>(ciphertext->data()))) {
+        logOpensslError();
+        return false;
+    }
+    ciphertext->resize(GCM_NONCE_BYTES + plaintext.size() + GCM_MAC_BYTES);
+    int outlen;
+    if (1 != EVP_EncryptUpdate(ctx.get(),
+        reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES), &outlen,
+        reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size())) {
+        logOpensslError();
+        return false;
+    }
+    if (outlen != static_cast<int>(plaintext.size())) {
+        LOG(ERROR) << "GCM ciphertext length should be " << plaintext.size() << " was " << outlen;
+        return false;
+    }
+    if (1 != EVP_EncryptFinal_ex(ctx.get(),
+        reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES + plaintext.size()), &outlen)) {
+        logOpensslError();
+        return false;
+    }
+    if (outlen != 0) {
+        LOG(ERROR) << "GCM EncryptFinal should be 0, was " << outlen;
+        return false;
+    }
+    if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, GCM_MAC_BYTES,
+        reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES + plaintext.size()))) {
+        logOpensslError();
+        return false;
+    }
+    return true;
+}
+
+static bool decryptWithoutKeymaster(const std::string& preKey,
+                                    const std::string& ciphertext, std::string* plaintext) {
+    if (ciphertext.size() < GCM_NONCE_BYTES + GCM_MAC_BYTES) {
+        LOG(ERROR) << "GCM ciphertext too small: " << ciphertext.size();
+        return false;
+    }
+    auto key = hashWithPrefix(kHashPrefix_keygen, preKey);
+    key.resize(AES_KEY_BYTES);
+    auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>(
+        EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
+    if (!ctx) {
+        logOpensslError();
+        return false;
+    }
+    if (1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL,
+            reinterpret_cast<const uint8_t*>(key.data()),
+            reinterpret_cast<const uint8_t*>(ciphertext.data()))) {
+        logOpensslError();
+        return false;
+    }
+    plaintext->resize(ciphertext.size() - GCM_NONCE_BYTES - GCM_MAC_BYTES);
+    int outlen;
+    if (1 != EVP_DecryptUpdate(ctx.get(),
+        reinterpret_cast<uint8_t*>(&(*plaintext)[0]), &outlen,
+        reinterpret_cast<const uint8_t*>(ciphertext.data() + GCM_NONCE_BYTES), plaintext->size())) {
+        logOpensslError();
+        return false;
+    }
+    if (outlen != static_cast<int>(plaintext->size())) {
+        LOG(ERROR) << "GCM plaintext length should be " << plaintext->size() << " was " << outlen;
+        return false;
+    }
+    if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, GCM_MAC_BYTES,
+        const_cast<void *>(
+            reinterpret_cast<const void*>(ciphertext.data() + GCM_NONCE_BYTES + plaintext->size())))) {
+        logOpensslError();
+        return false;
+    }
+    if (1 != EVP_DecryptFinal_ex(ctx.get(),
+        reinterpret_cast<uint8_t*>(&(*plaintext)[0] + plaintext->size()), &outlen)) {
+        logOpensslError();
+        return false;
+    }
+    if (outlen != 0) {
+        LOG(ERROR) << "GCM EncryptFinal should be 0, was " << outlen;
+        return false;
+    }
+    return true;
+}
+
+/*bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::string& key) {
+    if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), 0700)) == -1) {
+        PLOG(ERROR) << "key mkdir " << dir;
+        return false;
+    }
+    if (!writeStringToFile(kCurrentVersion, dir + "/" + kFn_version)) return false;
+    std::string secdiscardable;
+    if (!readRandomBytesOrLog(SECDISCARDABLE_BYTES, &secdiscardable)) return false;
+    if (!writeStringToFile(secdiscardable, dir + "/" + kFn_secdiscardable)) return false;
+    std::string stretching = getStretching(auth);
+    if (!writeStringToFile(stretching, dir + "/" + kFn_stretching)) return false;
+    std::string salt;
+    if (stretchingNeedsSalt(stretching)) {
+        if (ReadRandomBytes(SALT_BYTES, salt) != OK) {
+            LOG(ERROR) << "Random read failed";
+            return false;
+        }
+        if (!writeStringToFile(salt, dir + "/" + kFn_salt)) return false;
+    }
+    std::string appId;
+    if (!generateAppId(auth, stretching, salt, secdiscardable, &appId)) return false;
+    std::string encryptedKey;
+    if (auth.usesKeymaster()) {
+        Keymaster keymaster;
+        if (!keymaster) return false;
+        std::string kmKey;
+        if (!generateKeymasterKey(keymaster, auth, appId, &kmKey)) return false;
+        if (!writeStringToFile(kmKey, dir + "/" + kFn_keymaster_key_blob)) return false;
+        auto keyParams = beginParams(auth, appId);
+        if (!encryptWithKeymasterKey(keymaster, dir, keyParams, key, &encryptedKey)) return false;
+    } else {
+        if (!encryptWithoutKeymaster(appId, key, &encryptedKey)) return false;
+    }
+    if (!writeStringToFile(encryptedKey, dir + "/" + kFn_encrypted_key)) return false;
+    return true;
+}*/
+
+bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, std::string* key) {
+    std::string version;
+    if (!readFileToString(dir + "/" + kFn_version, &version)) return false;
+    if (version != kCurrentVersion) {
+        LOG(ERROR) << "Version mismatch, expected " << kCurrentVersion << " got " << version;
+        return false;
+    }
+    std::string secdiscardable;
+    if (!readFileToString(dir + "/" + kFn_secdiscardable, &secdiscardable)) return false;
+    std::string stretching;
+    if (!readFileToString(dir + "/" + kFn_stretching, &stretching)) return false;
+    std::string salt;
+    if (stretchingNeedsSalt(stretching)) {
+        if (!readFileToString(dir + "/" + kFn_salt, &salt)) return false;
+    }
+    std::string appId;
+    if (!generateAppId(auth, stretching, salt, secdiscardable, &appId)) return false;
+    std::string encryptedMessage;
+    if (!readFileToString(dir + "/" + kFn_encrypted_key, &encryptedMessage)) return false;
+    if (auth.usesKeymaster()) {
+        Keymaster keymaster;
+        if (!keymaster) return false;
+        auto keyParams = beginParams(auth, appId);
+        if (!decryptWithKeymasterKey(keymaster, dir, keyParams, encryptedMessage, key)) return false;
+    } else {
+        if (!decryptWithoutKeymaster(appId, encryptedMessage, key)) return false;
+    }
+    return true;
+}
+
+static bool deleteKey(const std::string& dir) {
+    std::string kmKey;
+    if (!readFileToString(dir + "/" + kFn_keymaster_key_blob, &kmKey)) return false;
+    Keymaster keymaster;
+    if (!keymaster) return false;
+    if (!keymaster.deleteKey(kmKey)) return false;
+    return true;
+}
+
+static bool runSecdiscard(const std::string& dir) {
+    if (ForkExecvp(
+            std::vector<std::string>{kSecdiscardPath, "--",
+                dir + "/" + kFn_encrypted_key,
+                dir + "/" + kFn_keymaster_key_blob,
+                dir + "/" + kFn_secdiscardable,
+                }) != 0) {
+        LOG(ERROR) << "secdiscard failed";
+        return false;
+    }
+    return true;
+}
+
+bool runSecdiscardSingle(const std::string& file) {
+    if (ForkExecvp(
+            std::vector<std::string>{kSecdiscardPath, "--",
+                file}) != 0) {
+        LOG(ERROR) << "secdiscard failed";
+        return false;
+    }
+    return true;
+}
+
+static bool recursiveDeleteKey(const std::string& dir) {
+    if (ForkExecvp(std::vector<std::string>{kRmPath, "-rf", dir}) != 0) {
+        LOG(ERROR) << "recursive delete failed";
+        return false;
+    }
+    return true;
+}
+
+bool destroyKey(const std::string& dir) {
+    bool success = true;
+    // Try each thing, even if previous things failed.
+    success &= deleteKey(dir);
+    success &= runSecdiscard(dir);
+    success &= recursiveDeleteKey(dir);
+    return success;
+}
+
+}  // namespace vold
+}  // namespace android
diff --git a/crypto/ext4crypt/KeyStorage3.h b/crypto/ext4crypt/KeyStorage3.h
new file mode 100644
index 0000000..bce6a99
--- /dev/null
+++ b/crypto/ext4crypt/KeyStorage3.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VOLD_KEYSTORAGE_H
+#define ANDROID_VOLD_KEYSTORAGE_H
+
+#include <string>
+
+namespace android {
+namespace vold {
+
+// Represents the information needed to decrypt a disk encryption key.
+// If "token" is nonempty, it is passed in as a required Gatekeeper auth token.
+// If "token" and "secret" are nonempty, "secret" is appended to the application-specific
+// binary needed to unlock.
+// If only "secret" is nonempty, it is used to decrypt in a non-Keymaster process.
+class KeyAuthentication {
+  public:
+    KeyAuthentication(std::string t, std::string s) : token{t}, secret{s} {};
+
+    bool usesKeymaster() const { return !token.empty() || secret.empty(); };
+
+    const std::string token;
+    const std::string secret;
+};
+
+extern const KeyAuthentication kEmptyAuthentication;
+
+// Create a directory at the named path, and store "key" in it,
+// in such a way that it can only be retrieved via Keymaster and
+// can be securely deleted.
+// It's safe to move/rename the directory after creation.
+bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::string& key);
+
+// Retrieve the key from the named directory.
+bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, std::string* key);
+
+// Securely destroy the key stored in the named directory and delete the directory.
+bool destroyKey(const std::string& dir);
+
+bool runSecdiscardSingle(const std::string& file);
+}  // namespace vold
+}  // namespace android
+
+#endif
diff --git a/crypto/ext4crypt/Keymaster3.cpp b/crypto/ext4crypt/Keymaster3.cpp
new file mode 100644
index 0000000..c72ddd0
--- /dev/null
+++ b/crypto/ext4crypt/Keymaster3.cpp
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Keymaster3.h"
+
+//#include <android-base/logging.h>
+#include <keystore/keymaster_tags.h>
+#include <keystore/authorization_set.h>
+#include <keystore/keystore_hidl_support.h>
+
+#include <iostream>
+#define ERROR 1
+#define LOG(x) std::cout
+
+using namespace ::keystore;
+using android::hardware::hidl_string;
+
+namespace android {
+namespace vold {
+
+KeymasterOperation::~KeymasterOperation() {
+    if (mDevice.get()) mDevice->abort(mOpHandle);
+}
+
+bool KeymasterOperation::updateCompletely(const std::string& input, std::string* output) {
+    if (output)
+        output->clear();
+    auto it = input.begin();
+    uint32_t inputConsumed;
+
+    ErrorCode km_error;
+    auto hidlCB = [&] (ErrorCode ret, uint32_t _inputConsumed,
+            const hidl_vec<KeyParameter>& /*ignored*/, const hidl_vec<uint8_t>& _output) {
+        km_error = ret;
+        if (km_error != ErrorCode::OK) return;
+        inputConsumed = _inputConsumed;
+        if (output)
+            output->append(reinterpret_cast<const char*>(&_output[0]), _output.size());
+    };
+
+    while (it != input.end()) {
+        size_t toRead = static_cast<size_t>(input.end() - it);
+        auto inputBlob = blob2hidlVec(reinterpret_cast<const uint8_t*>(&*it), toRead);
+        auto error = mDevice->update(mOpHandle, hidl_vec<KeyParameter>(), inputBlob, hidlCB);
+        if (!error.isOk()) {
+            LOG(ERROR) << "update failed: " << error.description();
+            mDevice = nullptr;
+            return false;
+        }
+        if (km_error != ErrorCode::OK) {
+            LOG(ERROR) << "update failed, code " << int32_t(km_error);
+            mDevice = nullptr;
+            return false;
+        }
+        if (inputConsumed > toRead) {
+            LOG(ERROR) << "update reported too much input consumed";
+            mDevice = nullptr;
+            return false;
+        }
+        it += inputConsumed;
+    }
+    return true;
+}
+
+bool KeymasterOperation::finish(std::string* output) {
+    ErrorCode km_error;
+    auto hidlCb = [&] (ErrorCode ret, const hidl_vec<KeyParameter>& /*ignored*/,
+            const hidl_vec<uint8_t>& _output) {
+        km_error = ret;
+        if (km_error != ErrorCode::OK) return;
+        if (output)
+            output->assign(reinterpret_cast<const char*>(&_output[0]), _output.size());
+    };
+    auto error = mDevice->finish(mOpHandle, hidl_vec<KeyParameter>(), hidl_vec<uint8_t>(),
+            hidl_vec<uint8_t>(), hidlCb);
+    mDevice = nullptr;
+    if (!error.isOk()) {
+        LOG(ERROR) << "finish failed: " << error.description();
+        return false;
+    }
+    if (km_error != ErrorCode::OK) {
+        LOG(ERROR) << "finish failed, code " << int32_t(km_error);
+        return false;
+    }
+    return true;
+}
+
+Keymaster::Keymaster() {
+    mDevice = ::android::hardware::keymaster::V3_0::IKeymasterDevice::getService();
+}
+
+/*bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key) {
+    ErrorCode km_error;
+    auto hidlCb = [&] (ErrorCode ret, const hidl_vec<uint8_t>& keyBlob,
+            const KeyCharacteristics& /*ignored* /) {
+        km_error = ret;
+        if (km_error != ErrorCode::OK) return;
+        if (key)
+            key->assign(reinterpret_cast<const char*>(&keyBlob[0]), keyBlob.size());
+    };
+
+    auto error = mDevice->generateKey(inParams.hidl_data(), hidlCb);
+    if (!error.isOk()) {
+        LOG(ERROR) << "generate_key failed: " << error.description();
+        return false;
+    }
+    if (km_error != ErrorCode::OK) {
+        LOG(ERROR) << "generate_key failed, code " << int32_t(km_error);
+        return false;
+    }
+    return true;
+}*/
+
+bool Keymaster::deleteKey(const std::string& key) {
+	LOG(ERROR) << "NOT deleting key in TWRP";
+	return false;
+    /*auto keyBlob = blob2hidlVec(key);
+    auto error = mDevice->deleteKey(keyBlob);
+    if (!error.isOk()) {
+        LOG(ERROR) << "delete_key failed: " << error.description();
+        return false;
+    }
+    if (ErrorCode(error) != ErrorCode::OK) {
+        LOG(ERROR) << "delete_key failed, code " << uint32_t(ErrorCode(error));
+        return false;
+    }
+    return true;*/
+}
+
+bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& inParams,
+                           std::string* newKey) {
+    auto oldKeyBlob = blob2hidlVec(oldKey);
+    ErrorCode km_error;
+    auto hidlCb = [&] (ErrorCode ret, const hidl_vec<uint8_t>& upgradedKeyBlob) {
+        km_error = ret;
+        if (km_error != ErrorCode::OK) return;
+        if (newKey)
+            newKey->assign(reinterpret_cast<const char*>(&upgradedKeyBlob[0]),
+                    upgradedKeyBlob.size());
+    };
+    auto error = mDevice->upgradeKey(oldKeyBlob, inParams.hidl_data(), hidlCb);
+    if (!error.isOk()) {
+        LOG(ERROR) << "upgrade_key failed: " << error.description();
+        return false;
+    }
+    if (km_error != ErrorCode::OK) {
+        LOG(ERROR) << "upgrade_key failed, code " << int32_t(km_error);
+        return false;
+    }
+    return true;
+}
+
+KeymasterOperation Keymaster::begin(KeyPurpose purpose, const std::string& key,
+                                    const AuthorizationSet& inParams,
+                                    AuthorizationSet* outParams) {
+    auto keyBlob = blob2hidlVec(key);
+    uint64_t mOpHandle;
+    ErrorCode km_error;
+
+    auto hidlCb = [&] (ErrorCode ret, const hidl_vec<KeyParameter>& _outParams,
+            uint64_t operationHandle) {
+        km_error = ret;
+        if (km_error != ErrorCode::OK) return;
+        if (outParams)
+            *outParams = _outParams;
+        mOpHandle = operationHandle;
+    };
+
+    auto error = mDevice->begin(purpose, keyBlob, inParams.hidl_data(), hidlCb);
+    if (!error.isOk()) {
+        LOG(ERROR) << "begin failed: " << error.description();
+        return KeymasterOperation(ErrorCode::UNKNOWN_ERROR);
+    }
+    if (km_error != ErrorCode::OK) {
+        LOG(ERROR) << "begin failed, code " << int32_t(km_error);
+        return KeymasterOperation(km_error);
+    }
+    return KeymasterOperation(mDevice, mOpHandle);
+}
+bool Keymaster::isSecure() {
+    bool _isSecure = false;
+    auto rc = mDevice->getHardwareFeatures(
+            [&] (bool isSecure, bool, bool, bool, bool, const hidl_string&, const hidl_string&) {
+                _isSecure = isSecure; });
+    return rc.isOk() && _isSecure;
+}
+
+}  // namespace vold
+}  // namespace android
+
+using namespace ::android::vold;
+
+int keymaster_compatibility_cryptfs_scrypt() {
+    Keymaster dev;
+    if (!dev) {
+        LOG(ERROR) << "Failed to initiate keymaster session";
+        return -1;
+    }
+    return dev.isSecure();
+}
+
+/*int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size,
+                                            uint64_t rsa_exponent,
+                                            uint32_t ratelimit,
+                                            uint8_t* key_buffer,
+                                            uint32_t key_buffer_size,
+                                            uint32_t* key_out_size)
+{
+    Keymaster dev;
+    std::string key;
+    if (!dev) {
+        LOG(ERROR) << "Failed to initiate keymaster session";
+        return -1;
+    }
+    if (!key_buffer || !key_out_size) {
+        LOG(ERROR) << __FILE__ << ":" << __LINE__ << ":Invalid argument";
+        return -1;
+    }
+    if (key_out_size) {
+        *key_out_size = 0;
+    }
+
+    auto paramBuilder = AuthorizationSetBuilder()
+                            .Authorization(TAG_ALGORITHM, Algorithm::RSA)
+                            .Authorization(TAG_KEY_SIZE, rsa_key_size)
+                            .Authorization(TAG_RSA_PUBLIC_EXPONENT, rsa_exponent)
+                            .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+                            .Authorization(TAG_PADDING, PaddingMode::NONE)
+                            .Authorization(TAG_DIGEST, Digest::NONE)
+                            .Authorization(TAG_BLOB_USAGE_REQUIREMENTS,
+                                    KeyBlobUsageRequirements::STANDALONE)
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, ratelimit);
+
+    if (!dev.generateKey(paramBuilder, &key)) {
+        return -1;
+    }
+
+    if (key_out_size) {
+        *key_out_size = key.size();
+    }
+
+    if (key_buffer_size < key.size()) {
+        return -1;
+    }
+
+    std::copy(key.data(), key.data() + key.size(), key_buffer);
+    return 0;
+}
+
+int keymaster_sign_object_for_cryptfs_scrypt(const uint8_t* key_blob,
+                                             size_t key_blob_size,
+                                             uint32_t ratelimit,
+                                             const uint8_t* object,
+                                             const size_t object_size,
+                                             uint8_t** signature_buffer,
+                                             size_t* signature_buffer_size)
+{
+    Keymaster dev;
+    if (!dev) {
+        LOG(ERROR) << "Failed to initiate keymaster session";
+        return -1;
+    }
+    if (!key_blob || !object || !signature_buffer || !signature_buffer_size) {
+        LOG(ERROR) << __FILE__ << ":" << __LINE__ << ":Invalid argument";
+        return -1;
+    }
+
+    AuthorizationSet outParams;
+    std::string key(reinterpret_cast<const char*>(key_blob), key_blob_size);
+    std::string input(reinterpret_cast<const char*>(object), object_size);
+    std::string output;
+    KeymasterOperation op;
+
+    auto paramBuilder = AuthorizationSetBuilder()
+                            .Authorization(TAG_PADDING, PaddingMode::NONE)
+                            .Authorization(TAG_DIGEST, Digest::NONE);
+
+    while (true) {
+        op = dev.begin(KeyPurpose::SIGN, key, paramBuilder, &outParams);
+        if (op.errorCode() == ErrorCode::KEY_RATE_LIMIT_EXCEEDED) {
+            sleep(ratelimit);
+            continue;
+        } else break;
+    }
+
+    if (op.errorCode() != ErrorCode::OK) {
+        LOG(ERROR) << "Error starting keymaster signature transaction: " << int32_t(op.errorCode());
+        return -1;
+    }
+
+    if (!op.updateCompletely(input, &output)) {
+        LOG(ERROR) << "Error sending data to keymaster signature transaction: "
+                   << uint32_t(op.errorCode());
+        return -1;
+    }
+
+    if (!op.finish(&output)) {
+        LOG(ERROR) << "Error finalizing keymaster signature transaction: " << int32_t(op.errorCode());
+        return -1;
+    }
+
+    *signature_buffer = reinterpret_cast<uint8_t*>(malloc(output.size()));
+    if (*signature_buffer == nullptr) {
+        LOG(ERROR) << "Error allocation buffer for keymaster signature";
+        return -1;
+    }
+    *signature_buffer_size = output.size();
+    std::copy(output.data(), output.data() + output.size(), *signature_buffer);
+    return 0;
+}*/
diff --git a/crypto/ext4crypt/Keymaster3.h b/crypto/ext4crypt/Keymaster3.h
new file mode 100644
index 0000000..4db8551
--- /dev/null
+++ b/crypto/ext4crypt/Keymaster3.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VOLD_KEYMASTER_H
+#define ANDROID_VOLD_KEYMASTER_H
+
+#ifdef __cplusplus
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+#include <keystore/authorization_set.h>
+#include "Utils.h"
+
+namespace android {
+namespace vold {
+using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
+using ::keystore::ErrorCode;
+using ::keystore::KeyPurpose;
+using ::keystore::AuthorizationSet;
+
+// C++ wrappers to the Keymaster hidl interface.
+// This is tailored to the needs of KeyStorage, but could be extended to be
+// a more general interface.
+
+// Wrapper for a Keymaster operation handle representing an
+// ongoing Keymaster operation.  Aborts the operation
+// in the destructor if it is unfinished. Methods log failures
+// to LOG(ERROR).
+class KeymasterOperation {
+  public:
+    ~KeymasterOperation();
+    // Is this instance valid? This is false if creation fails, and becomes
+    // false on finish or if an update fails.
+    explicit operator bool() { return mError == ErrorCode::OK; }
+    ErrorCode errorCode() { return mError; }
+    // Call "update" repeatedly until all of the input is consumed, and
+    // concatenate the output. Return true on success.
+    bool updateCompletely(const std::string& input, std::string* output);
+    // Finish and write the output to this string, unless pointer is null.
+    bool finish(std::string* output);
+    // Move constructor
+    KeymasterOperation(KeymasterOperation&& rhs) {
+        mDevice = std::move(rhs.mDevice);
+        mOpHandle = std::move(rhs.mOpHandle);
+        mError = std::move(rhs.mError);
+    }
+    // Construct an object in an error state for error returns
+    KeymasterOperation()
+        : mDevice{nullptr}, mOpHandle{0},
+          mError {ErrorCode::UNKNOWN_ERROR} {}
+    // Move Assignment
+    KeymasterOperation& operator= (KeymasterOperation&& rhs) {
+        mDevice = std::move(rhs.mDevice);
+        mOpHandle = std::move(rhs.mOpHandle);
+        mError = std::move(rhs.mError);
+        rhs.mError = ErrorCode::UNKNOWN_ERROR;
+        rhs.mOpHandle = 0;
+        return *this;
+    }
+
+  private:
+    KeymasterOperation(const sp<IKeymasterDevice>& d, uint64_t h)
+        : mDevice{d}, mOpHandle{h}, mError {ErrorCode::OK} {}
+    KeymasterOperation(ErrorCode error)
+        : mDevice{nullptr}, mOpHandle{0},
+          mError {error} {}
+    sp<IKeymasterDevice> mDevice;
+    uint64_t mOpHandle;
+    ErrorCode mError;
+    DISALLOW_COPY_AND_ASSIGN(KeymasterOperation);
+    friend class Keymaster;
+};
+
+// Wrapper for a Keymaster device for methods that start a KeymasterOperation or are not
+// part of one.
+class Keymaster {
+  public:
+    Keymaster();
+    // false if we failed to open the keymaster device.
+    explicit operator bool() { return mDevice.get() != nullptr; }
+    // Generate a key in the keymaster from the given params.
+    //bool generateKey(const AuthorizationSet& inParams, std::string* key);
+    // If the keymaster supports it, permanently delete a key.
+    bool deleteKey(const std::string& key);
+    // Replace stored key blob in response to KM_ERROR_KEY_REQUIRES_UPGRADE.
+    bool upgradeKey(const std::string& oldKey, const AuthorizationSet& inParams,
+                    std::string* newKey);
+    // Begin a new cryptographic operation, collecting output parameters if pointer is non-null
+    KeymasterOperation begin(KeyPurpose purpose, const std::string& key,
+                             const AuthorizationSet& inParams, AuthorizationSet* outParams);
+    bool isSecure();
+
+  private:
+    sp<hardware::keymaster::V3_0::IKeymasterDevice> mDevice;
+    DISALLOW_COPY_AND_ASSIGN(Keymaster);
+};
+
+}  // namespace vold
+}  // namespace android
+
+#endif // __cplusplus
+
+
+/*
+ * The following functions provide C bindings to keymaster services
+ * needed by cryptfs scrypt. The compatibility check checks whether
+ * the keymaster implementation is considered secure, i.e., TEE backed.
+ * The create_key function generates an RSA key for signing.
+ * The sign_object function signes an object with the given keymaster
+ * key.
+ */
+__BEGIN_DECLS
+
+int keymaster_compatibility_cryptfs_scrypt();
+/*int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size,
+                                            uint64_t rsa_exponent,
+                                            uint32_t ratelimit,
+                                            uint8_t* key_buffer,
+                                            uint32_t key_buffer_size,
+                                            uint32_t* key_out_size);
+
+int keymaster_sign_object_for_cryptfs_scrypt(const uint8_t* key_blob,
+                                             size_t key_blob_size,
+                                             uint32_t ratelimit,
+                                             const uint8_t* object,
+                                             const size_t object_size,
+                                             uint8_t** signature_buffer,
+                                             size_t* signature_buffer_size);*/
+
+__END_DECLS
+
+#endif
diff --git a/crypto/ext4crypt/Utils.h b/crypto/ext4crypt/Utils.h
index 8d0445d..aede203 100644
--- a/crypto/ext4crypt/Utils.h
+++ b/crypto/ext4crypt/Utils.h
@@ -24,6 +24,14 @@
 #include <vector>
 #include <string>
 
+// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions. It goes in the private:
+// declarations in a class.
+#if !defined(DISALLOW_COPY_AND_ASSIGN)
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+    TypeName(const TypeName&) = delete;  \
+    void operator=(const TypeName&) = delete
+#endif
+
 namespace android {
 namespace vold {
 
diff --git a/crypto/ext4crypt/Weaver1.cpp b/crypto/ext4crypt/Weaver1.cpp
new file mode 100644
index 0000000..6d09ec9
--- /dev/null
+++ b/crypto/ext4crypt/Weaver1.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2017 Team Win Recovery Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* To the best of my knowledge there is no native implementation for
+ * Weaver so I made this by looking at the IWeaver.h file that gets
+ * compiled by the build system. I took the information from this header
+ * file and looked at keymaster source to get an idea of the proper way
+ * to write the functions.
+ */
+
+#include "Weaver1.h"
+
+//#include <android-base/logging.h>
+#include <keystore/keymaster_tags.h>
+#include <keystore/authorization_set.h>
+#include <keystore/keystore_hidl_support.h>
+
+#include <android/hardware/weaver/1.0/IWeaver.h>
+
+#include <iostream>
+#define ERROR 1
+#define LOG(x) std::cout
+
+using namespace android::hardware::weaver;
+using android::hardware::hidl_string;
+using ::android::hardware::weaver::V1_0::IWeaver;
+using ::android::hardware::weaver::V1_0::WeaverConfig;
+using ::android::hardware::weaver::V1_0::WeaverReadStatus;
+using ::android::hardware::weaver::V1_0::WeaverReadResponse;
+using ::android::hardware::weaver::V1_0::WeaverStatus;
+using ::android::hardware::Return;
+using ::android::sp;
+
+namespace android {
+namespace vold {
+
+Weaver::Weaver() {
+	mDevice = ::android::hardware::weaver::V1_0::IWeaver::getService();
+	GottenConfig = false;
+}
+
+bool Weaver::GetConfig() {
+	if (GottenConfig)
+		return true;
+
+	WeaverStatus status;
+	WeaverConfig cfg;
+
+	bool callbackCalled = false;
+	auto ret = mDevice->getConfig([&](WeaverStatus s, WeaverConfig c) {
+		callbackCalled = true;
+		status = s;
+		cfg = c;
+	});
+	if (ret.isOk() && callbackCalled && status == WeaverStatus::OK) {
+		config = cfg;
+		GottenConfig = true;
+		return true;
+	}
+	return false;
+}
+
+bool Weaver::GetSlots(uint32_t* slots) {
+	if (!GetConfig())
+		return false;
+	*slots = config.slots;
+	return true;
+}
+
+bool Weaver::GetKeySize(uint32_t* keySize) {
+	if (!GetConfig())
+		return false;
+	*keySize = config.keySize;
+	return true;
+}
+
+bool Weaver::GetValueSize(uint32_t* valueSize) {
+	if (!GetConfig())
+		return false;
+	*valueSize = config.valueSize;
+	return true;
+}
+
+// TODO: we should return more information about the status including time delays before the next retry
+bool Weaver::WeaverVerify(const uint32_t slot, const void* weaver_key, std::vector<uint8_t>* payload) {
+	bool callbackCalled = false;
+	WeaverReadStatus status;
+	std::vector<uint8_t> readValue;
+	uint32_t timeout;
+	uint32_t keySize;
+	if (!GetKeySize(&keySize))
+		return false;
+	std::vector<uint8_t> key;
+	key.resize(keySize);
+	uint32_t index = 0;
+	unsigned char* ptr = (unsigned char*)weaver_key;
+	for (index = 0; index < keySize; index++) {
+		key[index] = *ptr;
+		ptr++;
+	}
+	const auto readRet = mDevice->read(slot, key, [&](WeaverReadStatus s, WeaverReadResponse r) {
+		callbackCalled = true;
+		status = s;
+		readValue = r.value;
+		timeout = r.timeout;
+	});
+	if (readRet.isOk() && callbackCalled && status == WeaverReadStatus::OK && timeout == 0) {
+		*payload = readValue;
+		return true;
+	}
+	return false;
+}
+
+}  // namespace vold
+}  // namespace android
diff --git a/crypto/ext4crypt/Weaver1.h b/crypto/ext4crypt/Weaver1.h
new file mode 100644
index 0000000..22f401e
--- /dev/null
+++ b/crypto/ext4crypt/Weaver1.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 Team Win Recovery Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* To the best of my knowledge there is no native implementation for
+ * Weaver so I made this by looking at the IWeaver.h file that gets
+ * compiled by the build system. I took the information from this header
+ * file and looked at keymaster source to get an idea of the proper way
+ * to write the functions.
+ */
+
+#ifndef TWRP_WEAVER_H
+#define TWRP_WEAVER_H
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <android/hardware/weaver/1.0/IWeaver.h>
+#include "Utils.h"
+
+namespace android {
+namespace vold {
+using ::android::hardware::weaver::V1_0::IWeaver;
+
+// Wrapper for a Weaver device
+class Weaver {
+	public:
+		Weaver();
+		// false if we failed to open the weaver device.
+		explicit operator bool() { return mDevice.get() != nullptr; }
+
+		bool GetSlots(uint32_t* slots);
+		bool GetKeySize(uint32_t* keySize);
+		bool GetValueSize(uint32_t* valueSize);
+		// TODO: we should return more information about the status including time delays before the next retry
+		bool WeaverVerify(const uint32_t slot, const void* weaver_key, std::vector<uint8_t>* payload);
+
+	private:
+		sp<hardware::weaver::V1_0::IWeaver> mDevice;
+		hardware::weaver::V1_0::WeaverConfig config;
+		bool GottenConfig;
+
+		bool GetConfig();
+
+		DISALLOW_COPY_AND_ASSIGN(Weaver);
+};
+
+}  // namespace vold
+}  // namespace android
+
+#endif
diff --git a/crypto/ext4crypt/e4policyget.cpp b/crypto/ext4crypt/e4policyget.cpp
index d217f18..05de86f 100644
--- a/crypto/ext4crypt/e4policyget.cpp
+++ b/crypto/ext4crypt/e4policyget.cpp
@@ -28,13 +28,10 @@
 		printf("Must specify a path\n");
 		return -1;
 	} else  {
-		char e4crypt_policy[EXT4_KEY_DESCRIPTOR_SIZE];
-		if (e4crypt_policy_get(argv[1], e4crypt_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
-		{
-			char* ptr = tar_policy;
-			memset(tar_policy, 0, sizeof(tar_policy));
+		ext4_encryption_policy eep;
+		if (e4crypt_policy_get_struct(argv[1], &eep, sizeof(eep))) {
 			char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
-			policy_to_hex(e4crypt_policy, policy_hex);
+			policy_to_hex(eep.master_key_descriptor, policy_hex);
 			printf("%s\n", policy_hex);
 		} else {
 			printf("No policy set\n");
diff --git a/crypto/ext4crypt/ext4_crypt.cpp b/crypto/ext4crypt/ext4_crypt.cpp
index 029db75..5a3b4b2 100644
--- a/crypto/ext4crypt/ext4_crypt.cpp
+++ b/crypto/ext4crypt/ext4_crypt.cpp
@@ -22,6 +22,7 @@
  */
 
 #include "ext4_crypt.h"
+#include "ext4crypt_tar.h"
 
 #include <dirent.h>
 #include <errno.h>
@@ -41,29 +42,13 @@
 #define XATTR_NAME_ENCRYPTION_POLICY "encryption.policy"
 #define EXT4_KEYREF_DELIMITER ((char)'.')
 
-// ext4enc:TODO Include structure from somewhere sensible
-// MUST be in sync with ext4_crypto.c in kernel
-#define EXT4_KEY_DESCRIPTOR_SIZE 8
-#define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17
-
-struct ext4_encryption_policy {
-    char version;
-    char contents_encryption_mode;
-    char filenames_encryption_mode;
-    char flags;
-    char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
-} __attribute__((__packed__));
-
 #define EXT4_ENCRYPTION_MODE_AES_256_XTS    1
 #define EXT4_ENCRYPTION_MODE_AES_256_CTS    4
+#define EXT4_ENCRYPTION_MODE_AES_256_HEH    126
 #define EXT4_ENCRYPTION_MODE_PRIVATE        127
 
 static int encryption_mode = EXT4_ENCRYPTION_MODE_PRIVATE;
 
-// ext4enc:TODO Get value from somewhere sensible
-#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy)
-#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy)
-
 #define HEX_LOOKUP "0123456789abcdef"
 
 extern "C" void policy_to_hex(const char* policy, char* hex) {
@@ -146,6 +131,48 @@
     return true;
 }
 
+extern "C" void e4crypt_policy_fill_default_struct(ext4_encryption_policy *eep) {
+	eep->version = 0;
+    eep->contents_encryption_mode = encryption_mode;
+    eep->filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
+    eep->flags = 0;
+    memset((void*)&eep->master_key_descriptor[0], 0, EXT4_KEY_DESCRIPTOR_SIZE);
+}
+
+extern "C" bool e4crypt_policy_set_struct(const char *directory, const ext4_encryption_policy *eep) {
+    int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+    if (fd == -1) {
+		printf("failed to open %s\n", directory);
+        PLOG(ERROR) << "Failed to open directory " << directory;
+        return false;
+    }
+    if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, eep)) {
+		printf("failed to set policy for '%s'\n", directory);
+        PLOG(ERROR) << "Failed to set encryption policy for " << directory;
+        close(fd);
+        return false;
+    }
+    close(fd);
+    return true;
+}
+
+extern "C" bool e4crypt_policy_get_struct(const char *directory, ext4_encryption_policy *eep) {
+    int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+    if (fd == -1) {
+        printf("Failed to open '%s'\n", directory);
+        PLOG(ERROR) << "Failed to open directory " << directory;
+        return false;
+    }
+    memset(eep, 0, sizeof(ext4_encryption_policy));
+    if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, eep) != 0) {
+        PLOG(ERROR) << "Failed to get encryption policy for " << directory;
+        close(fd);
+        return false;
+    }
+    close(fd);
+    return true;
+}
+
 extern "C" bool e4crypt_set_mode() {
     const char* mode_file = "/data/unencrypted/mode";
     struct stat st;
diff --git a/crypto/ext4crypt/ext4crypt_tar.h b/crypto/ext4crypt/ext4crypt_tar.h
index 1c9cef0..c35d115 100644
--- a/crypto/ext4crypt/ext4crypt_tar.h
+++ b/crypto/ext4crypt/ext4crypt_tar.h
@@ -21,8 +21,25 @@
 #include <stdbool.h>
 #include <cutils/multiuser.h>
 
+// ext4enc:TODO Include structure from somewhere sensible
+// MUST be in sync with ext4_crypto.c in kernel
+#define EXT4_KEY_DESCRIPTOR_SIZE 8
+#define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17
+
+// ext4enc:TODO Get value from somewhere sensible
+#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy)
+#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy)
+
 __BEGIN_DECLS
 
+struct ext4_encryption_policy {
+    char version;
+    char contents_encryption_mode;
+    char filenames_encryption_mode;
+    char flags;
+    char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
+} __attribute__((__packed__));
+
 bool lookup_ref_key(const char* policy, char* policy_type);
 bool lookup_ref_tar(const char* policy_type, char* policy);
 
@@ -31,6 +48,9 @@
                                size_t policy_length, int contents_encryption_mode);
 bool e4crypt_policy_get(const char *directory, char *policy,
                                size_t policy_length, int contents_encryption_mode);
+void e4crypt_policy_fill_default_struct(struct ext4_encryption_policy *eep);
+bool e4crypt_policy_set_struct(const char *directory, const struct ext4_encryption_policy *eep);
+bool e4crypt_policy_get_struct(const char *directory, struct ext4_encryption_policy *eep);
 
 bool e4crypt_set_mode();
 __END_DECLS
diff --git a/libblkid/lib/sysfs.c b/libblkid/lib/sysfs.c
index 8070750..71cf1b4 100644
--- a/libblkid/lib/sysfs.c
+++ b/libblkid/lib/sysfs.c
@@ -7,6 +7,7 @@
 #include <ctype.h>
 #include <string.h>
 #include <libgen.h>
+#include <sys/sysmacros.h>
 
 #include "c.h"
 #include "at.h"
diff --git a/libblkid/src/devname.c b/libblkid/src/devname.c
index fdbb5c9..d98af04 100644
--- a/libblkid/src/devname.c
+++ b/libblkid/src/devname.c
@@ -33,6 +33,7 @@
 #include <errno.h>
 #endif
 #include <time.h>
+#include <sys/sysmacros.h>
 
 #include "blkidP.h"
 
diff --git a/libblkid/src/evaluate.c b/libblkid/src/evaluate.c
index ffbe097..3d9a76b 100644
--- a/libblkid/src/evaluate.c
+++ b/libblkid/src/evaluate.c
@@ -12,6 +12,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <ctype.h>
+#include <sys/sysmacros.h>
 #include <sys/types.h>
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c
index 4853f97..25f1828 100644
--- a/libblkid/src/partitions/partitions.c
+++ b/libblkid/src/partitions/partitions.c
@@ -15,6 +15,7 @@
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <errno.h>
 #include <stdint.h>
 #include <inttypes.h>
diff --git a/libblkid/src/topology/dm.c b/libblkid/src/topology/dm.c
index e061632..6add2f7 100644
--- a/libblkid/src/topology/dm.c
+++ b/libblkid/src/topology/dm.c
@@ -16,6 +16,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <unistd.h>
 
diff --git a/libblkid/src/topology/evms.c b/libblkid/src/topology/evms.c
index 7a4fd55..1fce25a 100644
--- a/libblkid/src/topology/evms.c
+++ b/libblkid/src/topology/evms.c
@@ -17,6 +17,7 @@
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <unistd.h>
 
diff --git a/libblkid/src/topology/lvm.c b/libblkid/src/topology/lvm.c
index bd079d4..20a66b4 100644
--- a/libblkid/src/topology/lvm.c
+++ b/libblkid/src/topology/lvm.c
@@ -16,6 +16,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <unistd.h>
 
diff --git a/libblkid/src/topology/md.c b/libblkid/src/topology/md.c
index 5eba947..c232197 100644
--- a/libblkid/src/topology/md.c
+++ b/libblkid/src/topology/md.c
@@ -17,6 +17,7 @@
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <unistd.h>
 
diff --git a/libtar/append.c b/libtar/append.c
index 8896764..66e3aa1 100644
--- a/libtar/append.c
+++ b/libtar/append.c
@@ -131,27 +131,39 @@
 #ifdef HAVE_EXT4_CRYPT
 	if (TH_ISDIR(t) && t->options & TAR_STORE_EXT4_POL)
 	{
-		if (t->th_buf.e4crypt_policy != NULL)
+		if (t->th_buf.eep != NULL)
 		{
-			free(t->th_buf.e4crypt_policy);
-			t->th_buf.e4crypt_policy = NULL;
+			free(t->th_buf.eep);
+			t->th_buf.eep = NULL;
 		}
 
-		char e4crypt_policy[EXT4_KEY_DESCRIPTOR_SIZE];
-		if (e4crypt_policy_get(realname, e4crypt_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
+		t->th_buf.eep = (struct ext4_encryption_policy*)malloc(sizeof(struct ext4_encryption_policy));
+		if (!t->th_buf.eep) {
+			printf("malloc ext4_encryption_policy\n");
+			return -1;
+		}
+		if (e4crypt_policy_get_struct(realname, t->th_buf.eep))
 		{
 			char tar_policy[EXT4_KEY_DESCRIPTOR_SIZE];
 			memset(tar_policy, 0, sizeof(tar_policy));
-			char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
-			policy_to_hex(e4crypt_policy, policy_hex);
-			if (lookup_ref_key(e4crypt_policy, &tar_policy)) {
+			char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
+			policy_to_hex(t->th_buf.eep->master_key_descriptor, policy_hex);
+			if (lookup_ref_key(t->th_buf.eep->master_key_descriptor, &tar_policy[0])) {
 				printf("found policy '%s' - '%s' - '%s'\n", realname, tar_policy, policy_hex);
-				t->th_buf.e4crypt_policy = strdup(tar_policy);
+				memcpy(t->th_buf.eep->master_key_descriptor, tar_policy, EXT4_KEY_DESCRIPTOR_SIZE);
 			} else {
 				printf("failed to lookup tar policy for '%s' - '%s'\n", realname, policy_hex);
+				free(t->th_buf.eep);
+				t->th_buf.eep = NULL;
 				return -1;
 			}
-		} // else no policy found, but this is not an error as not all dirs will have a policy
+		}
+		else
+		{
+			// no policy found, but this is not an error as not all dirs will have a policy
+			free(t->th_buf.eep);
+			t->th_buf.eep = NULL;
+		}
 	}
 #endif
 
diff --git a/libtar/block.c b/libtar/block.c
index 8b22059..d0adb2b 100644
--- a/libtar/block.c
+++ b/libtar/block.c
@@ -18,6 +18,10 @@
 # include <stdlib.h>
 #endif
 
+#ifdef HAVE_EXT4_CRYPT
+# include "ext4crypt_tar.h"
+#endif
+
 #define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
 
 // Used to identify selinux_context in extended ('x')
@@ -138,9 +142,8 @@
 	if (t->th_buf.selinux_context != NULL)
 		free(t->th_buf.selinux_context);
 #ifdef HAVE_EXT4_CRYPT
-	if (t->th_buf.e4crypt_policy != NULL) {
-		free(t->th_buf.e4crypt_policy);
-	}
+	if (t->th_buf.eep != NULL)
+		free(t->th_buf.eep);
 #endif
 	if (t->th_buf.has_cap_data)
 	{
@@ -345,17 +348,41 @@
 			start = strstr(buf, E4CRYPT_TAG);
 			if (start && start+E4CRYPT_TAG_LEN < buf+len)
 			{
+				t->th_buf.eep = (struct ext4_encryption_policy*)malloc(sizeof(struct ext4_encryption_policy));
+				if (!t->th_buf.eep) {
+					printf("malloc ext4_encryption_policy\n");
+					return -1;
+				}
 				start += E4CRYPT_TAG_LEN;
-				char *end = strchr(start, '\n');
-				if(!end)
-					end = strchr(start, '\0');
-				if(end)
+				if (*start == '2')
 				{
-					t->th_buf.e4crypt_policy = strndup(start, end-start);
+					start++;
+					if (start + sizeof(struct ext4_encryption_policy) != '\n')
+						printf("did not find newline char in expected location, continuing anyway...\n");
+					memcpy(t->th_buf.eep, start, sizeof(struct ext4_encryption_policy));
 #ifdef DEBUG
-					printf("    th_read(): E4Crypt policy detected: %s\n", t->th_buf.e4crypt_policy);
+					printf("    th_read(): E4Crypt policy v2 detected: %i %i %i %i %s\n",
+						(int)t->th_buf.eep->version,
+						(int)t->th_buf.eep->contents_encryption_mode,
+						(int)t->th_buf.eep->filenames_encryption_mode,
+						(int)t->th_buf.eep->flags,
+						t->th_buf.eep->master_key_descriptor);
 #endif
 				}
+				else
+				{
+					e4crypt_policy_fill_default_struct(t->th_buf.eep);
+					char *end = strchr(start, '\n');
+					if(!end)
+						end = strchr(start, '\0');
+					if(end)
+					{
+						strncpy(t->th_buf.eep->master_key_descriptor, start, end-start);
+#ifdef DEBUG
+						printf("    th_read(): E4Crypt policy v1 detected: %s\n", t->th_buf.eep->master_key_descriptor);
+#endif
+					}
+				}
 			}
 #endif // HAVE_EXT4_CRYPT
 		}
@@ -557,22 +584,22 @@
 	}
 
 #ifdef HAVE_EXT4_CRYPT
-	if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.e4crypt_policy != NULL)
+	if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.eep != NULL)
 	{
 #ifdef DEBUG
 		printf("th_write(): using e4crypt_policy %s\n",
-		       t->th_buf.e4crypt_policy);
+		       t->th_buf.eep->master_key_descriptor);
 #endif
-		/* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
+		/* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *version code* *content* *newline* */
 		//                                                       size   newline
-		sz = E4CRYPT_TAG_LEN + strlen(t->th_buf.e4crypt_policy) + 3  +    1;
+		sz = E4CRYPT_TAG_LEN + sizeof(struct ext4_encryption_policy) + 1 + 3  +    1;
 
 		if(sz >= 100) // another ascci digit for size
 			++sz;
 
 		if (total_sz + sz >= T_BLOCKSIZE)
 		{
-			if (th_write_extended(t, &buf, total_sz))
+			if (th_write_extended(t, &buf[0], total_sz))
 				return -1;
 			ptr = buf;
 			total_sz = sz;
@@ -580,7 +607,8 @@
 		else
 			total_sz += sz;
 
-		snprintf(ptr, T_BLOCKSIZE, "%d "E4CRYPT_TAG"%s", (int)sz, t->th_buf.e4crypt_policy);
+		snprintf(ptr, T_BLOCKSIZE, "%d "E4CRYPT_TAG"2", (int)sz);
+		memcpy(ptr + sz - sizeof(struct ext4_encryption_policy) - 1, t->th_buf.eep, sizeof(struct ext4_encryption_policy));
 		char *nlptr = ptr + sz - 1;
 		*nlptr = '\n';
 		ptr += sz;
@@ -599,7 +627,7 @@
 
 		if (total_sz + sz >= T_BLOCKSIZE)
 		{
-			if (th_write_extended(t, &buf, total_sz))
+			if (th_write_extended(t, &buf[0], total_sz))
 				return -1;
 			ptr = buf;
 			total_sz = sz;
@@ -623,7 +651,7 @@
 
 			if (total_sz + sz >= T_BLOCKSIZE)
 			{
-				if (th_write_extended(t, &buf, total_sz))
+				if (th_write_extended(t, &buf[0], total_sz))
 					return -1;
 				ptr = buf;
 				total_sz = sz;
@@ -644,7 +672,7 @@
 
 			if (total_sz + sz >= T_BLOCKSIZE)
 			{
-				if (th_write_extended(t, &buf, total_sz))
+				if (th_write_extended(t, &buf[0], total_sz))
 					return -1;
 				ptr = buf;
 				total_sz = sz;
@@ -665,7 +693,7 @@
 
 			if (total_sz + sz >= T_BLOCKSIZE)
 			{
-				if (th_write_extended(t, &buf, total_sz))
+				if (th_write_extended(t, &buf[0], total_sz))
 					return -1;
 				ptr = buf;
 				total_sz = sz;
@@ -679,7 +707,7 @@
 			ptr += sz;
 		}
 	}
-	if (total_sz > 0 && th_write_extended(t, &buf, total_sz)) // write any outstanding tar extended header
+	if (total_sz > 0 && th_write_extended(t, &buf[0], total_sz)) // write any outstanding tar extended header
 		return -1;
 
 	th_finish(t);
diff --git a/libtar/compat.h b/libtar/compat.h
index 70ac2f4..16b3c3b 100644
--- a/libtar/compat.h
+++ b/libtar/compat.h
@@ -4,6 +4,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 
 #include <stdarg.h>
 #include <stddef.h>
diff --git a/libtar/encode.c b/libtar/encode.c
index c937152..1e679d8 100644
--- a/libtar/encode.c
+++ b/libtar/encode.c
@@ -16,6 +16,7 @@
 #include <pwd.h>
 #include <grp.h>
 #include <sys/types.h>
+#include <sys/sysmacros.h>
 
 #ifdef STDC_HEADERS
 # include <string.h>
diff --git a/libtar/extract.c b/libtar/extract.c
index 82ed766..fcd403a 100644
--- a/libtar/extract.c
+++ b/libtar/extract.c
@@ -549,22 +549,23 @@
 	}
 
 #ifdef HAVE_EXT4_CRYPT
-	if(t->th_buf.e4crypt_policy != NULL)
+	if(t->th_buf.eep != NULL)
 	{
 #ifdef DEBUG
-		printf("tar_extract_file(): restoring EXT4 crypt policy %s to dir %s\n", t->th_buf.e4crypt_policy, realname);
+		printf("tar_extract_file(): restoring EXT4 crypt policy %s to dir %s\n", t->th_buf.eep->master_key_descriptor, realname);
 #endif
 		char binary_policy[EXT4_KEY_DESCRIPTOR_SIZE];
-		if (!lookup_ref_tar(t->th_buf.e4crypt_policy, &binary_policy)) {
-			printf("error looking up proper e4crypt policy for '%s' - %s\n", realname, t->th_buf.e4crypt_policy);
+		if (!lookup_ref_tar(t->th_buf.eep->master_key_descriptor, &binary_policy[0])) {
+			printf("error looking up proper e4crypt policy for '%s' - %s\n", realname, t->th_buf.eep->master_key_descriptor);
 			return -1;
 		}
-		char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
+		char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
 		policy_to_hex(binary_policy, policy_hex);
-		printf("restoring policy %s > '%s' to '%s'\n", t->th_buf.e4crypt_policy, policy_hex, realname);
-		if (!e4crypt_policy_set(realname, binary_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
+		printf("restoring policy %s > '%s' to '%s'\n", t->th_buf.eep->master_key_descriptor, policy_hex, realname);
+		memcpy(&t->th_buf.eep->master_key_descriptor, binary_policy, EXT4_KEY_DESCRIPTOR_SIZE);
+		if (!e4crypt_policy_set_struct(realname, t->th_buf.eep))
 		{
-			printf("tar_extract_file(): failed to restore EXT4 crypt policy %s to dir '%s' '%s'!!!\n", t->th_buf.e4crypt_policy, realname, policy_hex);
+			printf("tar_extract_file(): failed to restore EXT4 crypt policy to dir '%s' '%s'!!!\n", realname, policy_hex);
 			//return -1; // This may not be an error in some cases, so log and ignore
 		}
 	}
diff --git a/libtar/libtar.h b/libtar/libtar.h
index 2d0a3d3..aa637b1 100644
--- a/libtar/libtar.h
+++ b/libtar/libtar.h
@@ -21,8 +21,7 @@
 #include "libtar_listhash.h"
 
 #ifdef HAVE_EXT4_CRYPT
-#define EXT4_KEY_DESCRIPTOR_SIZE 8
-#define EXT4_KEY_DESCRIPTOR_HEX 17
+# include "ext4crypt_tar.h"
 #endif
 
 #ifdef __cplusplus
@@ -70,7 +69,7 @@
 	char *gnu_longlink;
 	char *selinux_context;
 #ifdef HAVE_EXT4_CRYPT
-	char *e4crypt_policy;
+	struct ext4_encryption_policy *eep;
 #endif
 	int has_cap_data;
 	struct vfs_cap_data cap_data;
diff --git a/libtar/output.c b/libtar/output.c
index d2bf8bb..f5431b6 100644
--- a/libtar/output.c
+++ b/libtar/output.c
@@ -24,6 +24,10 @@
 # include <string.h>
 #endif
 
+#ifdef HAVE_EXT4_CRYPT
+# include "ext4crypt_tar.h"
+#endif
+
 
 #ifndef _POSIX_LOGIN_NAME_MAX
 # define _POSIX_LOGIN_NAME_MAX	9
@@ -45,8 +49,8 @@
 	printf("  linkname = \"%.100s\"\n", t->th_buf.linkname);
 	printf("  magic    = \"%.6s\"\n", t->th_buf.magic);
 	/*printf("  version  = \"%.2s\"\n", t->th_buf.version); */
-	printf("  version[0] = \'%c\',version[1] = \'%c\'\n",
-	       t->th_buf.version[0], t->th_buf.version[1]);
+	/*printf("  version[0] = \'%c\',version[1] = \'%c\'\n",
+	       t->th_buf.version[0], t->th_buf.version[1]);*/
 	printf("  uname    = \"%.32s\"\n", t->th_buf.uname);
 	printf("  gname    = \"%.32s\"\n", t->th_buf.gname);
 	printf("  devmajor = \"%.8s\"\n", t->th_buf.devmajor);
@@ -57,6 +61,10 @@
 	       (t->th_buf.gnu_longname ? t->th_buf.gnu_longname : "[NULL]"));
 	printf("  gnu_longlink = \"%s\"\n",
 	       (t->th_buf.gnu_longlink ? t->th_buf.gnu_longlink : "[NULL]"));
+#ifdef HAVE_EXT4_CRYPT
+	printf("  eep = \"%s\"\n",
+	       (t->th_buf.eep ? t->th_buf.eep->master_key_descriptor : "[NULL]"));
+#endif
 }
 
 
diff --git a/minadbd/minadbd_services.cpp b/minadbd/minadbd_services.cpp
index e558f97..40f2cea 100644
--- a/minadbd/minadbd_services.cpp
+++ b/minadbd/minadbd_services.cpp
@@ -21,6 +21,9 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <string>
+#include <thread>
+
 #include "adb.h"
 #include "fdevent.h"
 #include "fuse_adb_provider.h"
@@ -40,15 +43,26 @@
     free(sti);
 }
 
+#if PLATFORM_SDK_VERSION < 26
 static void sideload_host_service(int sfd, void* data) {
     char* args = reinterpret_cast<char*>(data);
+#else
+static void sideload_host_service(int sfd, const std::string& args) {
+#endif
     int file_size;
     int block_size;
+#if PLATFORM_SDK_VERSION < 26
     if (sscanf(args, "%d:%d", &file_size, &block_size) != 2) {
         printf("bad sideload-host arguments: %s\n", args);
+#else
+    if (sscanf(args.c_str(), "%d:%d", &file_size, &block_size) != 2) {
+        printf("bad sideload-host arguments: %s\n", args.c_str());
+#endif
         exit(1);
     }
+#if PLATFORM_SDK_VERSION < 26
     free(args);
+#endif
 
     printf("sideload-host file size %d block size %d\n", file_size, block_size);
 
@@ -59,6 +73,7 @@
     exit(result == 0 ? 0 : 1);
 }
 
+#if PLATFORM_SDK_VERSION < 26
 static int create_service_thread(void (*func)(int, void *), void *cookie) {
     int s[2];
     if (adb_socketpair(s)) {
@@ -88,6 +103,20 @@
     //VLOG(SERVICES) << "service thread started, " << s[0] << ":" << s[1];
     return s[0];
 }
+#else
+static int create_service_thread(void (*func)(int, const std::string&), const std::string& args) {
+    int s[2];
+    if (adb_socketpair(s)) {
+        printf("cannot create service socket pair\n");
+        return -1;
+    }
+
+    std::thread([s, func, args]() { func(s[1], args); }).detach();
+
+    //VLOG(SERVICES) << "service thread started, " << s[0] << ":" << s[1];
+    return s[0];
+}
+#endif
 
 int service_to_fd(const char* name, const atransport* transport) {
     int ret = -1;
@@ -98,7 +127,11 @@
         // sideload-host).
         exit(3);
     } else if (!strncmp(name, "sideload-host:", 14)) {
+#if PLATFORM_SDK_VERSION < 26
         char* arg = strdup(name + 14);
+#else
+        std::string arg(name + 14);
+#endif
         ret = create_service_thread(sideload_host_service, arg);
     }
     if (ret >= 0) {
diff --git a/partition.cpp b/partition.cpp
index 8b73f64..3957c65 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -656,7 +656,9 @@
 			//ExcludeAll(Mount_Point + "/user_de");
 			//ExcludeAll(Mount_Point + "/misc/profiles/cur/0"); // might be important later
 			ExcludeAll(Mount_Point + "/misc/gatekeeper");
+			ExcludeAll(Mount_Point + "/misc/keystore");
 			ExcludeAll(Mount_Point + "/drm/kek.dat");
+			ExcludeAll(Mount_Point + "/system_de/0/spblob"); // contains data needed to decrypt pixel 2
 			int retry_count = 3;
 			while (!Decrypt_DE() && --retry_count)
 				usleep(2000);
@@ -668,7 +670,12 @@
 				DataManager::SetValue(TW_IS_FBE, 1);
 				DataManager::SetValue(TW_IS_ENCRYPTED, 1);
 				string filename;
-				DataManager::SetValue(TW_CRYPTO_PWTYPE, Get_Password_Type(0, filename));
+				int pwd_type = Get_Password_Type(0, filename);
+				if (pwd_type < 0) {
+					LOGERR("This TWRP does not have synthetic password decrypt support\n");
+					pwd_type = 0; // default password
+				}
+				DataManager::SetValue(TW_CRYPTO_PWTYPE, pwd_type);
 				DataManager::SetValue(TW_CRYPTO_PASSWORD, "");
 				DataManager::SetValue("tw_crypto_display", "");
 			}
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 0486c7a..54ce691 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -91,9 +91,11 @@
 	stop_backup.set_value(0);
 #ifdef AB_OTA_UPDATER
 	char slot_suffix[PROPERTY_VALUE_MAX];
-	property_get("ro.boot.slot_suffix", slot_suffix, "_a");
+	property_get("ro.boot.slot_suffix", slot_suffix, "error");
+	if (strcmp(slot_suffix, "error") == 0)
+		property_get("ro.boot.slot", slot_suffix, "error");
 	Active_Slot_Display = "";
-	if (strcmp(slot_suffix, "_a") == 0)
+	if (strcmp(slot_suffix, "_a") == 0 || strcmp(slot_suffix, "a") == 0)
 		Set_Active_Slot("A");
 	else
 		Set_Active_Slot("B");
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index aff20d5..4e18010 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -63,10 +63,10 @@
 ifneq ($(wildcard external/e2fsprogs/lib/quota/Android.mk),)
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_quota.so
 endif
-ifneq ($(wildcard external/e2fsprogs/lib/ext2fs/Android.mk),)
+ifneq ($(wildcard external/e2fsprogs/lib/ext2fs/Android.*),)
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2fs.so
 endif
-ifneq ($(wildcard external/e2fsprogs/lib/blkid/Android.mk),)
+ifneq ($(wildcard external/e2fsprogs/lib/blkid/Android.*),)
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_blkid.so
 endif
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libpng.so
@@ -186,7 +186,23 @@
         RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbinder.so
         RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libprotobuf-cpp-lite.so
         RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libsoftkeymasterdevice.so
-        RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libkeymaster1.so
+        ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 25; echo $$?),0)
+            RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/android.hardware.gatekeeper@1.0.so
+            RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/hwservicemanager
+            RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/avbctl
+            RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/hwservicemanager
+            RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/keystore
+            RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/keystore_cli
+            RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/servicemanager
+            RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/android.system.wifi.keystore@1.0.so
+            RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libkeymaster_portable.so
+            RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libkeymaster_staging.so
+            RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libwifikeystorehal.so
+            RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/android.hardware.weaver@1.0.so
+            RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libhardware_legacy.so
+        else
+            RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libkeymaster1.so
+        endif
     endif
 endif
 ifeq ($(AB_OTA_UPDATER), true)
@@ -198,7 +214,7 @@
 ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
     RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/make_ext4fs
 endif
-ifneq ($(wildcard system/core/libsparse/Android.mk),)
+ifneq ($(wildcard system/core/libsparse/Android.*),)
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libsparse.so
 endif
 ifneq ($(TW_EXCLUDE_ENCRYPTED_BACKUPS), true)
@@ -223,7 +239,7 @@
     endif
     RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/fsck.f2fs
 endif
-ifneq ($(wildcard system/core/reboot/Android.mk),)
+ifneq ($(wildcard system/core/reboot/Android.*),)
     RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/reboot
 endif
 ifneq ($(TW_DISABLE_TTF), true)
@@ -275,10 +291,16 @@
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libhidlbase.so
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libhidltransport.so
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/android.hardware.keymaster@3.0.so
-    RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/android.hidl.base@1.0.so
+    #RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/android.hidl.base@1.0.so
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libziparchive.so
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_blkid.so
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_quota.so
+
+    RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libhidl-gen-utils.so
+    RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libvintf.so
+    RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libtinyxml2.so
+    RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/android.hidl.token@1.0.so
+    RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libkeyutils.so
 endif
 
 TWRP_AUTOGEN := $(intermediates)/teamwin