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