Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 117 additions & 36 deletions Decrypt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <keyutils.h>
#include "cutils/properties.h"
Expand Down Expand Up @@ -296,18 +297,17 @@ bool Get_Spblob_Data(const std::string& spblob_path, const std::string& handle_s
} else
found_file = true;
} else {
// The Keystore alias uses the handle as-is, but the spblob files are
// named after it zero-padded to 16 digits.
printf("trying to read %s_file data with leading 0\n", tag.c_str());
std::vector<std::string> file_paths = {
spblob_path + "0" + handle_str + suffix,
spblob_path + "00" + handle_str + suffix
};
for (auto& file : file_paths) {
if (!android::base::ReadFileToString(file, data)) {
printf("Failed to read '%s'\n", file.c_str());
} else {
found_file = true;
break;
}
std::string padded = handle_str.size() < 16
? std::string(16 - handle_str.size(), '0') + handle_str
: handle_str;
file = spblob_path + padded + suffix;
if (!android::base::ReadFileToString(file, data)) {
printf("Failed to read '%s'\n", file.c_str());
} else {
found_file = true;
}
}
return found_file;
Expand Down Expand Up @@ -491,16 +491,57 @@ namespace keystore {
}
}

void copySqliteDb() {
std::string keystore_path = "/tmp/misc/keystore/";
std::string dst = keystore_path + "persistent.sqlite";
std::string src = "/data/misc/keystore/persistent.sqlite";
std::ifstream srcif(src.c_str(), std::ios::binary);
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();
static bool waitForServiceState(const char* service, const char* state) {
char current[PROPERTY_VALUE_MAX] = {};
std::string prop = std::string("init.svc.") + service;
for (int i = 0; i < 100; i++) {
property_get(prop.c_str(), current, "");
if (!strcmp(current, state)) return true;
usleep(100000);
}
printf("'%s' did not reach state '%s'\n", service, state);
return false;
}

/* keystore2 runs with its database on tmpfs so that nothing done here can
* reach the real one. It still has to see the installed system's keys, so
* seed it from /data before the first keystore2 call. */
bool syncKeystoreDb() {
static bool synced = false;
if (synced) return true;

const std::string src = "/data/misc/keystore/persistent.sqlite";
const std::string dst = "/tmp/misc/keystore/persistent.sqlite";
if (!android::vold::pathExists(src)) {
printf("no keystore database at '%s'\n", src.c_str());
return false;
}

// keystore2 holds the destination open, so stop it for a clean copy.
printf("stopping keystore2 to sync '%s'\n", src.c_str());
property_set("ctl.stop", "keystore2");
waitForServiceState("keystore2", "stopped");

Comment on lines +520 to +524
unlink("/tmp/misc/keystore/persistent.sqlite-wal");
unlink("/tmp/misc/keystore/persistent.sqlite-shm");
unlink(dst.c_str());

KeystoreInfo keystore_info;
bool copied = keystore_info.backupDatabase(src, dst);
if (copied) chmod(dst.c_str(), 0600);

property_set("ctl.start", "keystore2");
if (!waitForServiceState("keystore2", "running")) return false;
for (int i = 0; i < 100; i++) {
if (AServiceManager_checkService(
"android.system.keystore2.IKeystoreService/default") != nullptr) {
synced = copied;
return copied;
}
usleep(100000);
}
printf("keystore2 did not register after restart\n");
return false;
}

/* C++ replacement for function of the same name
Expand Down Expand Up @@ -591,6 +632,25 @@ namespace keystore {
printf("Begin Operation failed\n");
return disk_decryption_secret_key;
}
if (encOperationResponse.upgradedBlob) {
/* KeyMint rebound the synthetic password key because our OS
* version or patch levels do not match the installed system.
* The upgrade only lives in the tmpfs Keystore database, so the
* blob on /data stays usable, but keystore2 has marked the old
* one superseded and its garbage collector deletes superseded
* blobs from KeyMint itself. That collector is gated on
* sys.boot_completed, so it stays idle here unless something
* sets that property. */
printf("WARNING: KeyMint upgraded the synthetic password key\n");
printf("WARNING: the recovery environment does not match the installed system\n");
char boot_completed[PROPERTY_VALUE_MAX] = {};
property_get("sys.boot_completed", boot_completed, "");
if (!strcmp(boot_completed, "1")) {
printf("ERROR: sys.boot_completed is set, so keystore2 will garbage\n");
printf("ERROR: collect the original key blob. Do not set that property\n");
printf("ERROR: in recovery.\n");
}
}
std::optional<std::vector<uint8_t>> optPlaintext;

begin_rc = encOperationResponse.iOperation->finish(cipher_text_hidlvec, {}, &optPlaintext);
Expand Down Expand Up @@ -734,6 +794,12 @@ bool Decrypt_User_Synth_Pass(const userid_t user_id, const std::string& Password
// 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
KeystoreInfo keystore_info;
std::string handle_str = keystore_info.getHandle(user_id);
// The synthetic password key is looked up by alias, so keystore2 needs the
// installed system's database before any of the calls below.
if (!android::keystore::syncKeystoreDb()) {
printf("Failed to sync the keystore database\n");
return Free_Return(retval, weaver_key, &pwd);
}
// 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
// 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");
Expand All @@ -751,7 +817,6 @@ bool Decrypt_User_Synth_Pass(const userid_t user_id, const std::string& Password
return Free_Return(retval, weaver_key, &pwd);
}
} else {
android::keystore::copySqliteDb(); // early copy db for keystore
std::string defpassword = "default-password";
memcpy(password_token, defpassword.data(), defpassword.length());
}
Expand Down Expand Up @@ -1018,9 +1083,9 @@ extern "C" int Get_Password_Type(const userid_t user_id, std::string& filename)

extern "C" bool Decrypt_User(const userid_t user_id, const std::string& Password) {
printf("Attempting to decrypt user\n");
uint8_t *auth_token;
uint32_t auth_token_len;
int ret;
uint8_t *auth_token = NULL;
uint32_t auth_token_len = 0;
int ret = -1;

struct stat st;
if (user_id > 9999) {
Expand Down Expand Up @@ -1056,15 +1121,35 @@ extern "C" bool Decrypt_User(const userid_t user_id, const std::string& Password
}
bool should_reenroll;
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());

// Devices that only declare the AIDL GateKeeper have no HIDL service.
constexpr const char gatekeeperServiceName[] = "android.hardware.gatekeeper.IGatekeeper/default";
if (AServiceManager_isDeclared(gatekeeperServiceName)) {
::ndk::SpAIBinder gkBinder(AServiceManager_waitForService(gatekeeperServiceName));
auto aidl_gk_device = AidlIGatekeeper::fromBinder(gkBinder);
if (!aidl_gk_device) {
printf("failed to get gatekeeper service\n");
return false;
}
AidlGatekeeperVerifyResp rsp;
auto result = aidl_gk_device->verify(user_id, 0 /* challenge */, curPwdHandle, enteredPwd, &rsp);
if (!result.isOk() || rsp.statusCode < AidlIGatekeeper::STATUS_OK) {
printf("gatekeeper verification failed\n");
return false;
}
printf("GateKeeper status ok\n");
std::string secret = HashPassword(Password);
return Decrypt_CE_storage(user_id, secret);
}

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::Return<void> hwRet =
Expand All @@ -1089,16 +1174,12 @@ extern "C" bool Decrypt_User(const userid_t user_id, const std::string& Password
}
}
);
if (!hwRet.isOk()) {
delete[] auth_token;
if (!hwRet.isOk() || ret != 0) {
Comment on lines 1174 to +1178
printf("gatekeeper verification failed\n");
return false;
}

char token_hex[(auth_token_len*2)+1];
token_hex[(auth_token_len*2)] = 0;
uint32_t i;
for (i=0;i<auth_token_len;i++) {
sprintf(&token_hex[2*i], "%02X", auth_token[i]);
}
// The secret is "Android FBE credential hash" plus appended 0x00 to reach 128 bytes then append the user's password then feed that to sha512sum
std::string secret = HashPassword(Password);
if (!Decrypt_CE_storage(user_id, secret)) {
Expand Down
2 changes: 1 addition & 1 deletion Decrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static constexpr int NAMESPACE_LOCKSETTINGS = 103;

namespace android {
namespace keystore {
void copySqliteDb();
bool syncKeystoreDb();
int Get_Password_Type(const userid_t user_id, std::string& filename);
bool Decrypt_DE();
bool Decrypt_User(const userid_t user_id, const std::string& Password);
Expand Down
54 changes: 25 additions & 29 deletions FsCrypt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,17 +209,17 @@ static bool fixate_user_ce_key(const std::string& directory_path, const std::str
return true;
}

static bool read_and_fixate_user_ce_key(userid_t user_id,
const android::vold::KeyAuthentication& auth,
KeyBuffer* ce_key) {
// Unlike AOSP this does not fixate the key it found: dropping the sibling
// bindings is a Keystore deletion we cannot undo if the user was midway
// through a credential change.
static bool read_user_ce_key(userid_t user_id, const android::vold::KeyAuthentication& auth,
KeyBuffer* ce_key) {
auto const directory_path = get_ce_key_directory_path(user_id);
auto const paths = get_ce_key_paths(directory_path);
for (auto const ce_key_path : paths) {
LOG(INFO) << "Trying user CE key " << ce_key_path;
if (retrieveKey(ce_key_path, auth, ce_key)) {
LOG(INFO) << "Successfully retrieved key";
s_deferred_fixations.erase(directory_path);
fixate_user_ce_key(directory_path, ce_key_path, paths);
return true;
}
}
Expand Down Expand Up @@ -551,8 +551,10 @@ bool fscrypt_initialize_systemwide_keys() {

KeyBuffer device_key;
install:
// Never generate the device key here: a new one makes the existing /data
// permanently unreadable.
if (!retrieveOrGenerateKey(device_key_path, device_key_temp, kEmptyAuthentication,
makeGen(s_data_options), &device_key))
android::vold::neverGen(), &device_key))
return false;
Comment on lines +554 to 558

// This initializes s_device_policy, which is a global variable so that
Expand All @@ -568,28 +570,16 @@ bool fscrypt_initialize_systemwide_keys() {
return false;
}

std::string options_string;
if (!OptionsToString(s_device_policy.options, &options_string)) {
LOG(ERROR) << "Unable to serialize options";
return false;
}
std::string options_filename = std::string(DATA_MNT_POINT) + fscrypt_key_mode;
if (!android::vold::writeStringToFile(options_string, options_filename)) return false;

std::string ref_filename = std::string(DATA_MNT_POINT) + fscrypt_key_ref;
// AOSP writes /data/unencrypted/{mode,ref,per_boot_ref} here for init to
// pick up on the next boot. The installed system owns those files and
// rewrites them itself, so recovery only keeps the policy in memory.
de_key_raw_ref = s_device_policy.key_raw_ref;
if (!android::vold::writeStringToFile(s_device_policy.key_raw_ref, ref_filename)) return false;
LOG(INFO) << "Wrote system DE key reference to:" << ref_filename;

KeyBuffer per_boot_key;
if (!generateStorageKey(makeGen(s_data_options), &per_boot_key)) return false;
EncryptionPolicy per_boot_policy;
if (!install_storage_key(DATA_MNT_POINT, s_data_options, per_boot_key, &per_boot_policy))
return false;
std::string per_boot_ref_filename = std::string("/data") + fscrypt_key_per_boot_ref;
if (!android::vold::writeStringToFile(per_boot_policy.key_raw_ref, per_boot_ref_filename))
return false;
LOG(INFO) << "Wrote per boot key reference to:" << per_boot_ref_filename;

return true;
}
Expand Down Expand Up @@ -659,11 +649,17 @@ bool fscrypt_init_user0() {
if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return false;
if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return false;

// Create user 0's DE and CE keys if they don't already exist. Check
// each key independently, since if the first boot was interrupted it is
// possible that the DE key exists but the CE key does not.
if (!de_key_exists(0) && !create_de_key(0, false)) return false;
if (!ce_key_exists(0) && !create_ce_key(0, false)) return false;
// AOSP creates user 0's keys here when they are missing. That is right
// on a first boot, but in recovery a missing key means we failed to
// read it, and creating a new one throws the user's data away.
if (!de_key_exists(0)) {
LOG(ERROR) << "DE key for user 0 not found, refusing to create one";
return false;
}
Comment on lines +655 to +658
if (!ce_key_exists(0)) {
LOG(ERROR) << "CE key for user 0 not found, refusing to create one";
return false;
}

// TODO: switch to loading only DE_0 here once framework makes
// explicit calls to install DE keys for secondary users
Expand Down Expand Up @@ -846,10 +842,10 @@ bool fscrypt_set_ce_key_protection(userid_t user_id, const std::string& secret_h
// at upgrade time, when CE keys that were previously protected by
// kEmptyAuthentication are encrypted by the user's synthetic password.
LOG(INFO) << "CE key already exists on-disk; re-protecting it with the given secret";
if (!read_and_fixate_user_ce_key(user_id, kEmptyAuthentication, &ce_key)) {
if (!read_user_ce_key(user_id, kEmptyAuthentication, &ce_key)) {
// Before failing, also check whether the key is already protected
// with the given secret.
if (read_and_fixate_user_ce_key(user_id, *auth, &ce_key)) {
if (read_user_ce_key(user_id, *auth, &ce_key)) {
LOG(INFO) << "CE key is already protected by given secret. Nothing to do.";
LOG(INFO) << "Errors above are for the attempt with empty auth and can be ignored.";
return true;
Expand Down Expand Up @@ -930,7 +926,7 @@ bool fscrypt_unlock_ce_storage(userid_t user_id, const std::string& secret_hex)
auto auth = authentication_from_hex(secret_hex);
if (!auth) return false;
KeyBuffer ce_key;
if (!read_and_fixate_user_ce_key(user_id, *auth, &ce_key)) return false;
if (!read_user_ce_key(user_id, *auth, &ce_key)) return false;
EncryptionPolicy ce_policy;
if (!install_storage_key(DATA_MNT_POINT, s_data_options, ce_key, &ce_policy)) return false;
s_ce_policies[user_id].internal = ce_policy;
Expand Down
16 changes: 5 additions & 11 deletions KeyStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,12 +335,8 @@ static KeystoreOperation BeginKeystoreOp(Keystore& keystore, const std::string&

auto blob_file = dir + "/" + kFn_keymaster_key_blob;
LOG(INFO) << "reading blob_file: " << blob_file;
std::string blob_dir(kFn_keymaster_key_blob);
std::string temp_dir = "/tmp/" + blob_dir + "/";
if (TEMP_FAILURE_RETRY(mkdir(temp_dir.c_str(), 0700)) == -1) {
PLOG(ERROR) << "key mkdir " << temp_dir;
}
auto upgraded_blob_file = temp_dir + kFn_keymaster_key_blob;
// Never persist an upgraded blob: the installed system cannot open a blob
// rebound to a newer OS version or patch level.
// auto upgraded_blob_file = dir + "/" + kFn_keymaster_key_blob_upgraded;
std::lock_guard<std::mutex> lock(key_upgrade_lock);

Expand All @@ -360,17 +356,15 @@ static KeystoreOperation BeginKeystoreOp(Keystore& keystore, const std::string&
if (!opHandle) return opHandle;

// If key blob wasn't upgraded, nothing left to do.
// if (!opHandle.getUpgradedBlob()) return opHandle;
if (!opHandle.getUpgradedBlob()) return opHandle;

// if (already_upgraded) {
// LOG(ERROR) << "Unexpected case; already-upgraded key " << upgraded_blob_file
// << " still requires upgrade";
// return KeystoreOperation();
// }
LOG(INFO) << "Upgrading key: " << blob_file;

if (!writeStringToFile(*opHandle.getUpgradedBlob(), upgraded_blob_file))
return KeystoreOperation();
LOG(WARNING) << "KeyMint upgraded " << blob_file
<< " for this operation only; the on-disk blob is left unchanged";
// if (cp_needsCheckpoint()) {
// LOG(INFO) << "Wrote upgraded key to " << upgraded_blob_file
// << "; delaying commit due to checkpoint";
Expand Down
Loading