Skip to content
This repository was archived by the owner on Nov 23, 2022. It is now read-only.

Commit

Permalink
Decrypt FBE on 9.0 (backwards compatible)
Browse files Browse the repository at this point in the history
Building in 9.0 may require you to add a flag to your twrp fstab
with the fileencryption details like:
fileencryption=ice:aes-256-heh

Verify this against your device's stock fstab of course.

Change-Id: If9286f5d5787280814daca9fbc8f5191ff26a839
  • Loading branch information
Dees-Troy committed Aug 31, 2018
1 parent 58f2132 commit e9afc3d
Show file tree
Hide file tree
Showing 46 changed files with 2,643 additions and 47 deletions.
41 changes: 32 additions & 9 deletions crypto/ext4crypt/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := libe4crypt
LOCAL_MODULE_TAGS := eng optional
LOCAL_CFLAGS :=
LOCAL_SRC_FILES := Decrypt.cpp Ext4Crypt.cpp ScryptParameters.cpp Utils.cpp HashPassword.cpp ext4_crypt.cpp
LOCAL_SRC_FILES := Decrypt.cpp ScryptParameters.cpp Utils.cpp HashPassword.cpp ext4_crypt.cpp
LOCAL_SHARED_LIBRARIES := libselinux libc libc++ libext4_utils 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
Expand All @@ -15,22 +15,40 @@ ifneq ($(wildcard hardware/libhardware/include/hardware/keymaster0.h),)
LOCAL_C_INCLUDES += external/boringssl/src/include
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
LOCAL_CFLAGS += -DUSE_KEYSTORAGE_3 -DHAVE_GATEKEEPER1
LOCAL_SRC_FILES += Keymaster3.cpp KeyStorage3.cpp
LOCAL_SHARED_LIBRARIES += [email protected] libkeystore_binder libhidlbase libutils libbinder
LOCAL_SHARED_LIBRARIES += [email protected]
ifneq ($(wildcard hardware/interfaces/weaver/Android.bp),)
#8.0 or higher
LOCAL_CFLAGS += -DHAVE_GATEKEEPER1
LOCAL_SHARED_LIBRARIES += [email protected] libkeystore_binder libhidlbase libutils libbinder [email protected]
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 28; echo $$?),0)
#9.0 rules
LOCAL_CFLAGS += -DUSE_KEYSTORAGE_4 -Wno-unused-variable -Wno-sign-compare -Wno-unused-parameter -Wno-comment
LOCAL_SRC_FILES += Ext4CryptPie.cpp Keymaster4.cpp KeyStorage4.cpp KeyUtil.cpp
LOCAL_SHARED_LIBRARIES += [email protected] libkeymaster4support
LOCAL_SHARED_LIBRARIES += [email protected] libkeystore_parcelables libkeystore_aidl
LOCAL_CFLAGS += -DHAVE_SYNTH_PWD_SUPPORT
LOCAL_SRC_FILES += Weaver1.cpp
LOCAL_SHARED_LIBRARIES += [email protected]
endif
ifneq ($(wildcard system/core/libkeyutils/Android.bp),)
LOCAL_CFLAGS += -DHAVE_LIBKEYUTILS
LOCAL_SHARED_LIBRARIES += libkeyutils
else
#8.0 rules
LOCAL_CFLAGS += -DUSE_KEYSTORAGE_3
LOCAL_SRC_FILES += Ext4Crypt.cpp Keymaster3.cpp KeyStorage3.cpp
ifneq ($(wildcard hardware/interfaces/weaver/Android.bp),)
#only present in some 8.0 trees and should be in all 8.1 trees
LOCAL_CFLAGS += -DHAVE_SYNTH_PWD_SUPPORT
LOCAL_SRC_FILES += Weaver1.cpp
LOCAL_SHARED_LIBRARIES += [email protected]
endif
ifneq ($(wildcard system/core/libkeyutils/Android.bp),)
#only present in some 8.0 trees and should be in all 8.1 trees
LOCAL_CFLAGS += -DHAVE_LIBKEYUTILS
LOCAL_SHARED_LIBRARIES += libkeyutils
endif
endif
LOCAL_REQUIRED_MODULES := keystore_auth
else
LOCAL_SRC_FILES += Keymaster.cpp KeyStorage.cpp
#7.x rules
LOCAL_SRC_FILES += Ext4Crypt.cpp Keymaster.cpp KeyStorage.cpp
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 28; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libsoftkeymaster
Expand Down Expand Up @@ -69,6 +87,11 @@ LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
LOCAL_SRC_FILES := keystore_auth.cpp
LOCAL_SHARED_LIBRARIES := libc libkeystore_binder libutils libbinder liblog
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 28; echo $$?),0)
#9.0
LOCAL_CFLAGS += -DUSE_SECURITY_NAMESPACE
LOCAL_SHARED_LIBRARIES += libkeystore_aidl
endif
LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64

include $(BUILD_EXECUTABLE)
Expand Down
101 changes: 82 additions & 19 deletions crypto/ext4crypt/Decrypt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
*/

#include "Decrypt.h"
#ifdef USE_KEYSTORAGE_4
#include "Ext4CryptPie.h"
#else
#include "Ext4Crypt.h"
#endif

#include <map>
#include <string>
Expand Down Expand Up @@ -50,12 +54,16 @@

#include <ext4_utils/ext4_crypt.h>

#ifdef USE_KEYSTORAGE_4
#include <android/security/IKeystoreService.h>
#else
#include <keystore/IKeystoreService.h>
#include <keystore/authorization_set.h>
#endif
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>

#include <keystore/keystore.h>
#include <keystore/authorization_set.h>

#include <algorithm>
extern "C" {
Expand Down Expand Up @@ -437,6 +445,9 @@ namespace keystore {
#define SYNTHETIC_PASSWORD_VERSION 2
#define SYNTHETIC_PASSWORD_PASSWORD_BASED 0
#define SYNTHETIC_PASSWORD_KEY_PREFIX "USRSKEY_synthetic_password_"
#define USR_PRIVATE_KEY_PREFIX "USRPKEY_synthetic_password_"

static std::string mKey_Prefix;

/* 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
Expand All @@ -447,13 +458,19 @@ namespace keystore {
* 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) {
bool Find_Keystore_Alias_SubID_And_Prep_Files(const userid_t user_id, std::string& keystoreid, const std::string& handle_str) {
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;
std::string handle_sub = handle_str;
while (handle_sub.substr(0,1) == "0") {
std::string temp = handle_sub.substr(1);
handle_sub = temp;
}
mKey_Prefix = "";

mkdir("/tmp/misc", 0755);
mkdir("/tmp/misc/keystore", 0755);
Expand All @@ -475,6 +492,7 @@ bool Find_Keystore_Alias_SubID_And_Prep_Files(const userid_t user_id, std::strin
struct dirent* de = 0;
size_t prefix_len = strlen(SYNTHETIC_PASSWORD_KEY_PREFIX);
bool found_subid = false;
bool has_pkey = false; // PKEY has priority over SKEY

while ((de = readdir(dir)) != 0) {
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
Expand All @@ -483,14 +501,25 @@ bool Find_Keystore_Alias_SubID_And_Prep_Files(const userid_t user_id, std::strin
size_t len = strlen(de->d_name);
if (len <= prefix_len)
continue;
if (!strstr(de->d_name, SYNTHETIC_PASSWORD_KEY_PREFIX))
if (strstr(de->d_name, SYNTHETIC_PASSWORD_KEY_PREFIX) && !has_pkey)
mKey_Prefix = SYNTHETIC_PASSWORD_KEY_PREFIX;
else if (strstr(de->d_name, USR_PRIVATE_KEY_PREFIX)) {
mKey_Prefix = USR_PRIVATE_KEY_PREFIX;
has_pkey = true;
} else
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());
if (strstr(de->d_name, handle_sub.c_str())) {
keystoreid = handle_sub;
printf("keystoreid matched handle_sub: '%s'\n", keystoreid.c_str());
found_subid = true;
} else {
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("possible keystoreid: '%s'\n", keystoreid.c_str());
//found_subid = true; // we'll keep going in hopes that we find a pkey or a match to the handle_sub
}
}
}
std::string src = source_path;
Expand All @@ -508,6 +537,8 @@ bool Find_Keystore_Alias_SubID_And_Prep_Files(const userid_t user_id, std::strin
dstof.close();
}
closedir(dir);
if (!found_subid && !mKey_Prefix.empty() && !keystoreid.empty())
found_subid = true;
return found_subid;
}

Expand All @@ -518,14 +549,18 @@ std::string unwrapSyntheticPasswordBlob(const std::string& spblob_path, const st
std::string disk_decryption_secret_key = "";

std::string keystore_alias_subid;
if (!Find_Keystore_Alias_SubID_And_Prep_Files(user_id, keystore_alias_subid)) {
if (!Find_Keystore_Alias_SubID_And_Prep_Files(user_id, keystore_alias_subid, handle_str)) {
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();
#ifdef USE_KEYSTORAGE_4
sp<security::IKeystoreService> service = interface_cast<security::IKeystoreService>(binder);
#else
sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
#endif
if (service == NULL) {
printf("error: could not connect to keystore service\n");
return disk_decryption_secret_key;
Expand Down Expand Up @@ -682,23 +717,34 @@ std::string unwrapSyntheticPasswordBlob(const std::string& spblob_path, const st
//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;
std::string keystore_alias = mKey_Prefix;
keystore_alias += keystore_alias_subid;
String16 keystore_alias16(keystore_alias.c_str());
#ifdef USE_KEYSTORAGE_4
android::hardware::keymaster::V4_0::KeyPurpose purpose = android::hardware::keymaster::V4_0::KeyPurpose::DECRYPT;
security::keymaster::OperationResult begin_result;
security::keymaster::OperationResult update_result;
security::keymaster::OperationResult finish_result;
::android::security::keymaster::KeymasterArguments empty_params;
// 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, (int32_t)purpose, true, android::security::keymaster::KeymasterArguments(begin_params.hidl_data()), entropy, -1, &begin_result);
#else
::keystore::KeyPurpose purpose = ::keystore::KeyPurpose::DECRYPT;
OperationResult begin_result;
OperationResult update_result;
OperationResult finish_result;
::keystore::hidl_vec<::keystore::KeyParameter> empty_params;
empty_params.resize(0);
// 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);
#endif
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);
Expand All @@ -716,7 +762,6 @@ std::string unwrapSyntheticPasswordBlob(const std::string& spblob_path, const st
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*/) {
Expand Down Expand Up @@ -785,23 +830,34 @@ std::string unwrapSyntheticPasswordBlob(const std::string& spblob_path, const st
begin_params.Authorization(::keystore::TAG_MAC_LENGTH, maclen);
::keystore::hidl_vec<uint8_t> entropy; // No entropy is needed for decrypt
entropy.resize(0);
std::string keystore_alias = SYNTHETIC_PASSWORD_KEY_PREFIX;
std::string keystore_alias = mKey_Prefix;
keystore_alias += keystore_alias_subid;
String16 keystore_alias16(keystore_alias.c_str());
#ifdef USE_KEYSTORAGE_4
android::hardware::keymaster::V4_0::KeyPurpose purpose = android::hardware::keymaster::V4_0::KeyPurpose::DECRYPT;
security::keymaster::OperationResult begin_result;
security::keymaster::OperationResult update_result;
security::keymaster::OperationResult finish_result;
::android::security::keymaster::KeymasterArguments empty_params;
// 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, (int32_t)purpose, true, android::security::keymaster::KeymasterArguments(begin_params.hidl_data()), entropy, -1, &begin_result);
#else
::keystore::KeyPurpose purpose = ::keystore::KeyPurpose::DECRYPT;
OperationResult begin_result;
OperationResult update_result;
OperationResult finish_result;
::keystore::hidl_vec<::keystore::KeyParameter> empty_params;
empty_params.resize(0);
// 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);
#endif
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, cipher_text_hidlvec, &update_result);
Expand All @@ -824,7 +880,6 @@ std::string unwrapSyntheticPasswordBlob(const std::string& spblob_path, const st
memcpy(keystore_result, &update_result.data[0], update_result.data.size());
//printf("keystore_result data: "); output_hex(keystore_result, keystore_result_size); printf("\n");
::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*/) {
Expand Down Expand Up @@ -1103,7 +1158,11 @@ bool Decrypt_User_Synth_Pass(const userid_t user_id, const std::string& Password
printf("e4crypt_unlock_user_key returned fail\n");
return Free_Return(retval, weaver_key, &pwd);
}
#ifdef USE_KEYSTORAGE_4
if (!e4crypt_prepare_user_storage("", user_id, 0, flags)) {
#else
if (!e4crypt_prepare_user_storage(nullptr, user_id, 0, flags)) {
#endif
printf("failed to e4crypt_prepare_user_storage\n");
return Free_Return(retval, weaver_key, &pwd);
}
Expand Down Expand Up @@ -1189,7 +1248,11 @@ bool Decrypt_User(const userid_t user_id, const std::string& Password) {
printf("e4crypt_unlock_user_key returned fail\n");
return false;
}
#ifdef USE_KEYSTORAGE_4
if (!e4crypt_prepare_user_storage("", user_id, 0, flags)) {
#else
if (!e4crypt_prepare_user_storage(nullptr, user_id, 0, flags)) {
#endif
printf("failed to e4crypt_prepare_user_storage\n");
return false;
}
Expand Down
4 changes: 4 additions & 0 deletions crypto/ext4crypt/Decrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ __BEGIN_DECLS
// NOTE: keep in sync with StorageManager
static constexpr int FLAG_STORAGE_DE = 1 << 0;
static constexpr int FLAG_STORAGE_CE = 1 << 1;
// For 9.0 Ext4CryptPie.cpp
static constexpr int STORAGE_FLAG_DE = 1 << 0;
static constexpr int STORAGE_FLAG_CE = 1 << 1;


int Get_Password_Type(const userid_t user_id, std::string& filename);
bool Decrypt_DE();
Expand Down
4 changes: 4 additions & 0 deletions crypto/ext4crypt/Ext4Crypt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
#include "Ext4Crypt.h"
#include "Decrypt.h"

#ifdef USE_KEYSTORAGE_3
#include "KeyStorage3.h"
#else
#include "KeyStorage.h"
#endif
#include "Utils.h"

#include <algorithm>
Expand Down
Loading

0 comments on commit e9afc3d

Please sign in to comment.