FsCrypt update: support fscrypt policies v1 and v2
This patchset introduces support decryption for Android 11. In this update we deprecate ext4crypt. To specify the policy version to use, use TW_USE_FSCRYPT_POLICY := 1 or TW_USE_FSCRYPT_POLICY := 2. By default policy version will be set to 2 if this variable is omitted. Change-Id: I62a29c1bef36c259ec4b11259f71be613d20a112
This commit is contained in:
+53
-53
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "Decrypt.h"
|
||||
#include "FsCrypt.h"
|
||||
#include <fscrypt/fscrypt.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -72,39 +73,37 @@
|
||||
#include <keystore/OperationResult.h>
|
||||
#include "keystore_client.pb.h"
|
||||
|
||||
#include <keymasterV4_0/authorization_set.h>
|
||||
#include <keymasterV4_0/keymaster_utils.h>
|
||||
#include <keymasterV4_1/authorization_set.h>
|
||||
#include <keymasterV4_1/keymaster_utils.h>
|
||||
|
||||
extern "C" {
|
||||
#include "crypto_scrypt.h"
|
||||
}
|
||||
|
||||
#include "fscrypt_policy.h"
|
||||
#include "fscrypt-common.h"
|
||||
#include "HashPassword.h"
|
||||
#include "KeyStorage.h"
|
||||
#include "android/os/IVold.h"
|
||||
|
||||
using android::security::keystore::IKeystoreService;
|
||||
using keystore::KeystoreResponsePromise;
|
||||
using keystore::OperationResultPromise;
|
||||
using android::security::keymaster::OperationResult;
|
||||
using android::hardware::keymaster::V4_0::support::blob2hidlVec;
|
||||
using android::hardware::keymaster::V4_1::support::blob2hidlVec;
|
||||
|
||||
// Store main DE raw ref / policy
|
||||
extern std::string de_raw_ref;
|
||||
extern std::map<userid_t, std::string> s_de_key_raw_refs;
|
||||
extern std::map<userid_t, std::string> s_ce_key_raw_refs;
|
||||
|
||||
inline std::string hidlVec2String(const ::keystore::hidl_vec<uint8_t>& value) {
|
||||
return std::string(reinterpret_cast<const std::string::value_type*>(&value[0]), value.size());
|
||||
}
|
||||
|
||||
static bool lookup_ref_key_internal(std::map<userid_t, std::string>& key_map, const uint8_t* policy, userid_t* user_id) {
|
||||
char policy_string_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
|
||||
char key_map_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
|
||||
policy_to_hex(policy, policy_string_hex);
|
||||
static bool lookup_ref_key_internal(std::map<userid_t, android::fscrypt::EncryptionPolicy> key_map, const uint8_t* policy, userid_t* user_id) {
|
||||
char policy_string_hex[FSCRYPT_KEY_IDENTIFIER_HEX_SIZE];
|
||||
char key_map_hex[FSCRYPT_KEY_IDENTIFIER_HEX_SIZE];
|
||||
bytes_to_hex(policy, FSCRYPT_KEY_IDENTIFIER_SIZE, policy_string_hex);
|
||||
|
||||
for (std::map<userid_t, std::string>::iterator it=key_map.begin(); it!=key_map.end(); ++it) {
|
||||
policy_to_hex(reinterpret_cast<const uint8_t*>(&it->second[0]), key_map_hex);
|
||||
for (std::map<userid_t, android::fscrypt::EncryptionPolicy>::iterator it=key_map.begin(); it!=key_map.end(); ++it) {
|
||||
bytes_to_hex(reinterpret_cast<const uint8_t*>(&it->second.key_raw_ref[0]), FSCRYPT_KEY_IDENTIFIER_SIZE, key_map_hex);
|
||||
std::string key_map_hex_string = std::string(key_map_hex);
|
||||
if (key_map_hex_string == policy_string_hex) {
|
||||
*user_id = it->first;
|
||||
@@ -114,65 +113,72 @@ static bool lookup_ref_key_internal(std::map<userid_t, std::string>& key_map, co
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" bool lookup_ref_key(const uint8_t* policy, uint8_t* policy_type) {
|
||||
userid_t user_id = 0;
|
||||
char policy_string_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
|
||||
char de_raw_ref_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
|
||||
policy_to_hex(policy, policy_string_hex);
|
||||
policy_to_hex(reinterpret_cast<const uint8_t*>(&de_raw_ref[0]), de_raw_ref_hex);
|
||||
std::string de_raw_ref_hex_string = std::string(de_raw_ref_hex);
|
||||
|
||||
#ifdef USE_FSCRYPT_POLICY_V1
|
||||
extern "C" bool lookup_ref_key(fscrypt_policy_v1* v1, uint8_t* policy_type) {
|
||||
#else
|
||||
extern "C" bool lookup_ref_key(fscrypt_policy_v2* v2, uint8_t* policy_type) {
|
||||
#endif
|
||||
userid_t user_id = 0;
|
||||
std::string policy_type_string;
|
||||
if (policy_string_hex == de_raw_ref_hex_string) {
|
||||
|
||||
char policy_hex[FSCRYPT_KEY_IDENTIFIER_HEX_SIZE];
|
||||
bytes_to_hex(v2->master_key_identifier, FSCRYPT_KEY_IDENTIFIER_SIZE, policy_hex);
|
||||
if (std::strncmp((const char*) v2->master_key_identifier, de_key_raw_ref.c_str(), FSCRYPT_KEY_IDENTIFIER_SIZE) == 0) {
|
||||
policy_type_string = "0DK";
|
||||
memcpy(policy_type, policy_type_string.data(), policy_type_string.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!lookup_ref_key_internal(s_de_key_raw_refs, policy, &user_id)) {
|
||||
if (!lookup_ref_key_internal(s_ce_key_raw_refs, policy, &user_id)) {
|
||||
if (!lookup_ref_key_internal(s_de_policies, v2->master_key_identifier, &user_id)) {
|
||||
if (!lookup_ref_key_internal(s_ce_policies, v2->master_key_identifier, &user_id)) {
|
||||
return false;
|
||||
} else
|
||||
} else {
|
||||
policy_type_string = "0CE" + std::to_string(user_id);
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
policy_type_string = "0DE" + std::to_string(user_id);
|
||||
}
|
||||
memcpy(policy_type, policy_type_string.data(), policy_type_string.size());
|
||||
LOG(INFO) << "storing policy type: " << policy_type;
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool lookup_ref_tar(const uint8_t* policy_type, uint8_t* policy) {
|
||||
std::string policy_type_string = std::string((char *) policy_type);
|
||||
char policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
|
||||
policy_to_hex(policy_type, policy_hex);
|
||||
char policy_hex[FSCRYPT_KEY_IDENTIFIER_HEX_SIZE];
|
||||
bytes_to_hex(policy_type, FSCRYPT_KEY_IDENTIFIER_SIZE, policy_hex);
|
||||
|
||||
// Current encryption fscrypt policy is v1 (which is stored as version 0e)
|
||||
userid_t user_id = atoi(policy_type_string.substr(3, 4).c_str());
|
||||
|
||||
// TODO Update version # and make magic strings
|
||||
if (policy_type_string.substr(0,1) != "0") {
|
||||
printf("Unexpected version %c\n", policy_type[0]);
|
||||
LOG(ERROR) << "Unexpected version:" << policy_type[0];
|
||||
return false;
|
||||
}
|
||||
|
||||
if (policy_type_string.substr(1, 2) == "DK") {
|
||||
memcpy(policy, de_raw_ref.data(), de_raw_ref.size());
|
||||
memcpy(policy, de_key_raw_ref.data(), de_key_raw_ref.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
userid_t user_id = atoi(policy_type_string.substr(3, 4).c_str());
|
||||
std::string raw_ref;
|
||||
|
||||
if (policy_type_string.substr(1, 1) == "D") {
|
||||
if (lookup_key_ref(s_de_key_raw_refs, user_id, &raw_ref)) {
|
||||
if (lookup_key_ref(s_de_policies, user_id, &raw_ref)) {
|
||||
memcpy(policy, raw_ref.data(), raw_ref.size());
|
||||
} else
|
||||
return false;
|
||||
} else if (policy_type_string.substr(1, 1) == "C") {
|
||||
if (lookup_key_ref(s_ce_key_raw_refs, user_id, &raw_ref)) {
|
||||
if (lookup_key_ref(s_ce_policies, user_id, &raw_ref)) {
|
||||
memcpy(policy, raw_ref.data(), raw_ref.size());
|
||||
} else
|
||||
return false;
|
||||
} else {
|
||||
printf("unknown policy type '%s'\n", policy_type);
|
||||
LOG(ERROR) << "unknown policy type: " << policy_type;
|
||||
return false;
|
||||
}
|
||||
|
||||
char found_policy_hex[FSCRYPT_KEY_IDENTIFIER_HEX_SIZE];
|
||||
bytes_to_hex(policy, FSCRYPT_KEY_IDENTIFIER_SIZE, found_policy_hex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -688,14 +694,16 @@ std::string unwrapSyntheticPasswordBlob(const std::string& spblob_path, const st
|
||||
return disk_decryption_secret_key;
|
||||
}
|
||||
OperationResult result = future.get();
|
||||
auto handle = std::move(result.token);
|
||||
std::map<uint64_t, android::sp<android::IBinder>> active_operations_;
|
||||
uint64_t next_virtual_handle_ = 1;
|
||||
active_operations_[next_virtual_handle_] = result.token;
|
||||
|
||||
// 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
|
||||
future = {};
|
||||
promise = new OperationResultPromise();
|
||||
future = promise->get_future();
|
||||
binder_result = service->update(promise, handle, empty_params, cipher_text_hidlvec, &error_code);
|
||||
binder_result = service->update(promise, active_operations_[next_virtual_handle_], empty_params, cipher_text_hidlvec, &error_code);
|
||||
rc = ::keystore::KeyStoreNativeReturnCode(error_code);
|
||||
if (!rc.isOk()) {
|
||||
printf("Keystore update returned: %d\n", error_code);
|
||||
@@ -717,11 +725,10 @@ std::string unwrapSyntheticPasswordBlob(const std::string& spblob_path, const st
|
||||
future = {};
|
||||
promise = new OperationResultPromise();
|
||||
future = promise->get_future();
|
||||
std::tie(rc, keyBlob, charBlob, lockedEntry) = mKeyStore->getKeyForName(name8, callingUid, TYPE_KEYMASTER_10);
|
||||
|
||||
auto hidlInput = blob2hidlVec(input_data);
|
||||
::keystore::hidl_vec<uint8_t> signature;
|
||||
binder_result = service->finish(promise, handle, empty_params, hidlInput, signature, entropy, &error_code);
|
||||
|
||||
auto hidlSignature = blob2hidlVec("");
|
||||
auto hidlInput = blob2hidlVec(disk_decryption_secret_key);
|
||||
binder_result = service->finish(promise, active_operations_[next_virtual_handle_], empty_params, hidlInput, hidlSignature, ::keystore::hidl_vec<uint8_t>(), &error_code);
|
||||
if (!binder_result.isOk()) {
|
||||
printf("communication error while calling keystore\n");
|
||||
free(keystore_result);
|
||||
@@ -844,11 +851,7 @@ bool Decrypt_User_Synth_Pass(const userid_t user_id, const std::string& Password
|
||||
|
||||
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;
|
||||
int flags = android::os::IVold::STORAGE_FLAG_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;
|
||||
@@ -1091,11 +1094,8 @@ bool Decrypt_User(const userid_t user_id, const std::string& Password) {
|
||||
printf("Unknown password type\n");
|
||||
return false;
|
||||
}
|
||||
int flags = FLAG_STORAGE_DE;
|
||||
if (user_id == 0)
|
||||
flags = FLAG_STORAGE_DE;
|
||||
else
|
||||
flags = FLAG_STORAGE_CE;
|
||||
|
||||
int flags = android::os::IVold::STORAGE_FLAG_CE;
|
||||
|
||||
if (Default_Password) {
|
||||
if (!fscrypt_unlock_user_key(user_id, 0, "!", "!")) {
|
||||
|
||||
Reference in New Issue
Block a user