Loading system/btif/include/btif_api.h +2 −2 Original line number Diff line number Diff line Loading @@ -105,7 +105,7 @@ bool is_restricted_mode(void); /******************************************************************************* * * Function is_single_user_mode_ * Function is_niap_mode * * Description Checks if BT was enabled in single user mode. In this * mode, use of keystore for key attestation of LTK is limitee Loading @@ -114,7 +114,7 @@ bool is_restricted_mode(void); * Returns bool * ******************************************************************************/ bool is_single_user_mode(void); bool is_niap_mode(void); /******************************************************************************* * Loading system/btif/include/btif_keystore.h +9 −3 Original line number Diff line number Diff line Loading @@ -59,12 +59,18 @@ class BtifKeystore { */ std::string Decrypt(const std::string& input_filename); /** * Check for existence of keystore key. * * This key can be cleared if a user manually wipes bluetooth storage data * b/133214365 */ bool DoesKeyExist(); private: std::unique_ptr<keystore::KeystoreClient> keystore_client_; std::mutex api_mutex_; keystore::KeyStoreNativeReturnCode GenerateKey(const std::string& name, int32_t flags, bool auth_bound); bool GenerateKey(const std::string& name, int32_t flags); }; } // namespace bluetooth system/btif/src/bluetooth.cc +6 −6 Original line number Diff line number Diff line Loading @@ -81,7 +81,7 @@ using bluetooth::hearing_aid::HearingAidInterface; bt_callbacks_t* bt_hal_cbacks = NULL; bool restricted_mode = false; bool single_user_mode = false; bool niap_mode = false; /******************************************************************************* * Externs Loading Loading @@ -134,9 +134,9 @@ static bool is_profile(const char* p1, const char* p2) { ****************************************************************************/ static int init(bt_callbacks_t* callbacks, bool start_restricted, bool is_single_user_mode) { LOG_INFO(LOG_TAG, "%s: start restricted = %d ; single user = %d", __func__, start_restricted, is_single_user_mode); bool is_niap_mode) { LOG_INFO(LOG_TAG, "%s: start restricted = %d ; niap = %d", __func__, start_restricted, is_niap_mode); if (interface_ready()) return BT_STATUS_DONE; Loading @@ -146,7 +146,7 @@ static int init(bt_callbacks_t* callbacks, bool start_restricted, bt_hal_cbacks = callbacks; restricted_mode = start_restricted; single_user_mode = is_single_user_mode; niap_mode = is_niap_mode; stack_manager_get_interface()->init_stack(); btif_debug_init(); return BT_STATUS_SUCCESS; Loading @@ -169,7 +169,7 @@ static int disable(void) { static void cleanup(void) { stack_manager_get_interface()->clean_up_stack(); } bool is_restricted_mode() { return restricted_mode; } bool is_single_user_mode() { return single_user_mode; } bool is_niap_mode() { return niap_mode; } static int get_adapter_properties(void) { /* sanity check */ Loading system/btif/src/btif_config.cc +121 −10 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "btif_config.h" #include <base/base64.h> #include <base/logging.h> #include <ctype.h> #include <openssl/rand.h> Loading Loading @@ -60,8 +61,8 @@ static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S"; constexpr int kBufferSize = 400 * 10; // initial file is ~400B static bool use_key_attestation() { return getuid() == AID_BLUETOOTH && is_single_user_mode(); static bool btif_is_niap_mode() { return getuid() == AID_BLUETOOTH && is_niap_mode(); } #define BT_CONFIG_METRICS_SECTION "Metrics" Loading Loading @@ -93,10 +94,22 @@ static void btif_config_remove_restricted(config_t* config); static std::unique_ptr<config_t> btif_config_open(const char* filename, const char* checksum_filename); // Key attestation static std::string btif_convert_to_encrypt_key( const std::string& unencrypt_str); static std::string btif_convert_to_unencrypt_key( const std::string& encrypt_str); static bool btif_in_encrypt_key_name_list(std::string key); static bool btif_is_key_encrypted(int key_from_config_size, std::string key_type_string); static std::string hash_file(const char* filename); static std::string read_checksum_file(const char* filename); static void write_checksum_file(const char* filename, const std::string& hash); static const int ENCRYPT_KEY_NAME_LIST_SIZE = 7; static const std::string encrypt_key_name_list[] = { "LinkKey", "LE_KEY_PENC", "LE_KEY_PID", "LE_KEY_LID", "LE_KEY_PCSRK", "LE_KEY_LENC", "LE_KEY_LCSRK"}; static enum ConfigSource { NOT_LOADED, ORIGINAL, Loading Loading @@ -269,7 +282,8 @@ static std::unique_ptr<config_t> btif_config_open(const char* filename, const ch std::string stored_hash = read_checksum_file(checksum_filename); if (stored_hash.empty()) { LOG(ERROR) << __func__ << ": stored_hash=<empty>"; if (!current_hash.empty()) { // Will encrypt once since the bt_config never encrypt. if (!btif_keystore.DoesKeyExist() && !current_hash.empty()) { write_checksum_file(checksum_filename, current_hash); stored_hash = read_checksum_file(checksum_filename); } Loading Loading @@ -406,14 +420,29 @@ bool btif_config_get_bin(const std::string& section, const std::string& key, CHECK(length != NULL); std::unique_lock<std::recursive_mutex> lock(config_lock); const std::string* value_str = config_get_string(*config, section, key, NULL); const std::string* value_str; const std::string* value_str_from_config = config_get_string(*config, section, key, NULL); if (!value_str) { if (!value_str_from_config) { VLOG(1) << __func__ << ": cannot find string for section " << section << ", key " << key; return false; } bool in_encrypt_key_name_list = btif_in_encrypt_key_name_list(key); bool is_key_encrypted = btif_is_key_encrypted(value_str_from_config->size(), key); if (in_encrypt_key_name_list && is_key_encrypted) { VLOG(2) << __func__ << " decrypt section: " << section << " key:" << key; std::string tmp_value_str = btif_convert_to_unencrypt_key(*value_str_from_config); value_str = &tmp_value_str; } else { value_str = value_str_from_config; } size_t value_len = value_str->length(); if ((value_len % 2) != 0 || *length < (value_len / 2)) { LOG(WARNING) << ": value size not divisible by 2, size is " << value_len; Loading @@ -427,12 +456,72 @@ bool btif_config_get_bin(const std::string& section, const std::string& key, } const char* ptr = value_str->c_str(); for (*length = 0; *ptr; ptr += 2, *length += 1) for (*length = 0; *ptr; ptr += 2, *length += 1) { sscanf(ptr, "%02hhx", &value[*length]); } if (btif_is_niap_mode()) { if (in_encrypt_key_name_list && !is_key_encrypted) { VLOG(2) << __func__ << " encrypt section: " << section << " key:" << key; std::string encrypt_str = btif_convert_to_encrypt_key(*value_str_from_config); config_set_string(config.get(), section, key, encrypt_str); } } else { if (in_encrypt_key_name_list && is_key_encrypted) { config_set_string(config.get(), section, key, value_str->c_str()); } } return true; } static bool btif_in_encrypt_key_name_list(std::string key) { return std::find(encrypt_key_name_list, encrypt_key_name_list + ENCRYPT_KEY_NAME_LIST_SIZE, key) != (encrypt_key_name_list + ENCRYPT_KEY_NAME_LIST_SIZE); } static bool btif_is_key_encrypted(int key_from_config_size, std::string key_type_string) { if (key_type_string.compare("LinkKey") == 0) { return sizeof(LinkKey) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_PENC") == 0) { return sizeof(tBTM_LE_PENC_KEYS) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_PID") == 0) { return sizeof(tBTM_LE_PID_KEYS) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_LID") == 0) { return sizeof(tBTM_LE_PID_KEYS) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_PCSRK") == 0) { return sizeof(tBTM_LE_PCSRK_KEYS) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_LENC") == 0) { return sizeof(tBTM_LE_LENC_KEYS) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_LCSRK") == 0) { return sizeof(tBTM_LE_LCSRK_KEYS) * 2 != key_from_config_size; } else { VLOG(2) << __func__ << ": " << key_type_string << " Key type is unknown, return false first"; return false; } } static std::string btif_convert_to_unencrypt_key( const std::string& encrypt_str) { if (!encrypt_str.empty()) { std::string tmp_encrypt_str(""); if (base::Base64Decode(encrypt_str, &tmp_encrypt_str)) { std::string unencrypt_str = btif_keystore.Decrypt(tmp_encrypt_str); if (!unencrypt_str.empty()) { return unencrypt_str; } } else { LOG(WARNING) << __func__ << ": base64string decode fail, will return empty string"; } } return ""; } size_t btif_config_get_bin_length(const std::string& section, const std::string& key) { CHECK(config != NULL); Loading Loading @@ -466,15 +555,37 @@ bool btif_config_set_bin(const std::string& section, const std::string& key, str[(i * 2) + 1] = lookup[value[i] & 0x0F]; } std::string value_str; if (btif_is_niap_mode() && btif_in_encrypt_key_name_list(key)) { VLOG(2) << __func__ << " encrypt section: " << section << " key:" << key; value_str = btif_convert_to_encrypt_key(str); } else { value_str = str; } { std::unique_lock<std::recursive_mutex> lock(config_lock); config_set_string(config.get(), section, key, str); config_set_string(config.get(), section, key, value_str); } osi_free(str); return true; } static std::string btif_convert_to_encrypt_key( const std::string& unencrypt_str) { if (!unencrypt_str.empty()) { std::string encrypt_str = btif_keystore.Encrypt(unencrypt_str, 0); if (!encrypt_str.empty()) { base::Base64Encode(encrypt_str, &encrypt_str); return encrypt_str; } else { LOG(ERROR) << __func__ << ": Encrypt fail, will return empty str."; } } return ""; } std::list<section_t>& btif_config_sections() { return config->sections; } bool btif_config_remove(const std::string& section, const std::string& key) { Loading Loading @@ -641,7 +752,7 @@ static void delete_config_files(void) { } static std::string hash_file(const char* filename) { if (!use_key_attestation()) { if (!btif_is_niap_mode()) { LOG(INFO) << __func__ << ": Disabled for multi-user"; return DISABLED; } Loading Loading @@ -669,7 +780,7 @@ static std::string hash_file(const char* filename) { } static std::string read_checksum_file(const char* checksum_filename) { if (!use_key_attestation()) { if (!btif_is_niap_mode()) { LOG(INFO) << __func__ << ": Disabled for multi-user"; return DISABLED; } Loading @@ -683,7 +794,7 @@ static std::string read_checksum_file(const char* checksum_filename) { static void write_checksum_file(const char* checksum_filename, const std::string& hash) { if (!use_key_attestation()) { if (!btif_is_niap_mode()) { LOG(INFO) << __func__ << ": Disabled for multi-user, since config changed removing " "checksums."; Loading system/btif/src/btif_keystore.cc +83 −36 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ ******************************************************************************/ #include "btif_keystore.h" #include "keystore_client.pb.h" #include "string.h" #include <base/files/file_util.h> #include <base/logging.h> Loading @@ -29,7 +31,9 @@ using namespace keystore; using namespace bluetooth; constexpr char kKeyStore[] = "AndroidKeystore"; const std::string kKeyStore = "bluetooth-key-encrypted"; constexpr uint32_t kAESKeySize = 256; // bits constexpr uint32_t kMACOutputSize = 128; // bits namespace bluetooth { Loading @@ -43,19 +47,45 @@ std::string BtifKeystore::Encrypt(const std::string& data, int32_t flags) { LOG(ERROR) << __func__ << ": empty data"; return output; } if (!keystore_client_->doesKeyExist(kKeyStore)) { auto gen_result = GenerateKey(kKeyStore, 0, false); if (!gen_result.isOk()) { LOG(FATAL) << "EncryptWithAuthentication Failed: generateKey response=" << gen_result; if (!GenerateKey(kKeyStore, flags)) { return output; } AuthorizationSetBuilder encrypt_params; encrypt_params.Authorization(TAG_BLOCK_MODE, BlockMode::GCM) .Authorization(TAG_MAC_LENGTH, kMACOutputSize) .Padding(PaddingMode::NONE); AuthorizationSet output_params; std::string raw_encrypted_data; if (!keystore_client_->oneShotOperation( KeyPurpose::ENCRYPT, kKeyStore, encrypt_params, data, std::string() /* signature_to_verify */, &output_params, &raw_encrypted_data)) { LOG(ERROR) << __func__ << ": AES operation failed."; return output; } if (!keystore_client_->encryptWithAuthentication(kKeyStore, data, flags, &output)) { LOG(FATAL) << "EncryptWithAuthentication failed."; auto init_vector_blob = output_params.GetTagValue(TAG_NONCE); if (!init_vector_blob.isOk()) { LOG(ERROR) << __func__ << ": Missing initialization vector."; return output; } const hidl_vec<uint8_t>& value = init_vector_blob.value(); std::string init_vector = std::string(reinterpret_cast<const std::string::value_type*>(&value[0]), value.size()); if (memcmp(&init_vector_blob, &init_vector, init_vector.length()) == 0) { LOG(ERROR) << __func__ << ": Protobuf nonce data doesn't match the actual nonce."; } EncryptedData protobuf; protobuf.set_init_vector(init_vector); protobuf.set_encrypted_data(raw_encrypted_data); if (!protobuf.SerializeToString(&output)) { LOG(ERROR) << __func__ << ": Failed to serialize EncryptedData protobuf."; } return output; } Loading @@ -66,36 +96,53 @@ std::string BtifKeystore::Decrypt(const std::string& input) { return ""; } std::string output; if (!keystore_client_->decryptWithAuthentication(kKeyStore, input, &output)) { LOG(FATAL) << "DecryptWithAuthentication failed.\n"; EncryptedData protobuf; if (!protobuf.ParseFromString(input)) { LOG(ERROR) << __func__ << ": Failed to parse EncryptedData protobuf."; return output; } AuthorizationSetBuilder encrypt_params; encrypt_params.Authorization(TAG_BLOCK_MODE, BlockMode::GCM) .Authorization(TAG_MAC_LENGTH, kMACOutputSize) .Authorization(TAG_NONCE, protobuf.init_vector().data(), protobuf.init_vector().size()) .Padding(PaddingMode::NONE); AuthorizationSet output_params; if (!keystore_client_->oneShotOperation( KeyPurpose::DECRYPT, kKeyStore, encrypt_params, protobuf.encrypted_data(), std::string() /* signature_to_verify */, &output_params, &output)) { LOG(ERROR) << __func__ << ": AES operation failed."; } return output; } // Note: auth_bound keys created with this tool will not be usable. KeyStoreNativeReturnCode BtifKeystore::GenerateKey(const std::string& name, int32_t flags, bool auth_bound) { bool BtifKeystore::GenerateKey(const std::string& name, int32_t flags) { if (!DoesKeyExist()) { AuthorizationSetBuilder params; params.RsaSigningKey(2048, 65537) .Digest(Digest::SHA_2_224) .Digest(Digest::SHA_2_256) .Digest(Digest::SHA_2_384) .Digest(Digest::SHA_2_512) .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) .Padding(PaddingMode::RSA_PSS); if (auth_bound) { // Gatekeeper normally generates the secure user id. // Using zero allows the key to be created, but it will not be usuable. params.Authorization(TAG_USER_SECURE_ID, 0); } else { params.Authorization(TAG_NO_AUTH_REQUIRED); } params.AesEncryptionKey(kAESKeySize) .Authorization(TAG_NO_AUTH_REQUIRED) .Authorization(TAG_BLOCK_MODE, BlockMode::GCM) .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT) .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT) .Padding(PaddingMode::NONE) .Authorization(TAG_MIN_MAC_LENGTH, kMACOutputSize); AuthorizationSet hardware_enforced_characteristics; AuthorizationSet software_enforced_characteristics; return keystore_client_->generateKey(name, params, flags, &hardware_enforced_characteristics, auto result = keystore_client_->generateKey( name, params, flags, &hardware_enforced_characteristics, &software_enforced_characteristics); if (!result.isOk()) { LOG(FATAL) << __func__ << "Failed to generate key: name: " << name << ", error code: " << result.getErrorCode(); return false; } } return true; } bool BtifKeystore::DoesKeyExist() { return keystore_client_->doesKeyExist(kKeyStore); } } // namespace bluetooth Loading
system/btif/include/btif_api.h +2 −2 Original line number Diff line number Diff line Loading @@ -105,7 +105,7 @@ bool is_restricted_mode(void); /******************************************************************************* * * Function is_single_user_mode_ * Function is_niap_mode * * Description Checks if BT was enabled in single user mode. In this * mode, use of keystore for key attestation of LTK is limitee Loading @@ -114,7 +114,7 @@ bool is_restricted_mode(void); * Returns bool * ******************************************************************************/ bool is_single_user_mode(void); bool is_niap_mode(void); /******************************************************************************* * Loading
system/btif/include/btif_keystore.h +9 −3 Original line number Diff line number Diff line Loading @@ -59,12 +59,18 @@ class BtifKeystore { */ std::string Decrypt(const std::string& input_filename); /** * Check for existence of keystore key. * * This key can be cleared if a user manually wipes bluetooth storage data * b/133214365 */ bool DoesKeyExist(); private: std::unique_ptr<keystore::KeystoreClient> keystore_client_; std::mutex api_mutex_; keystore::KeyStoreNativeReturnCode GenerateKey(const std::string& name, int32_t flags, bool auth_bound); bool GenerateKey(const std::string& name, int32_t flags); }; } // namespace bluetooth
system/btif/src/bluetooth.cc +6 −6 Original line number Diff line number Diff line Loading @@ -81,7 +81,7 @@ using bluetooth::hearing_aid::HearingAidInterface; bt_callbacks_t* bt_hal_cbacks = NULL; bool restricted_mode = false; bool single_user_mode = false; bool niap_mode = false; /******************************************************************************* * Externs Loading Loading @@ -134,9 +134,9 @@ static bool is_profile(const char* p1, const char* p2) { ****************************************************************************/ static int init(bt_callbacks_t* callbacks, bool start_restricted, bool is_single_user_mode) { LOG_INFO(LOG_TAG, "%s: start restricted = %d ; single user = %d", __func__, start_restricted, is_single_user_mode); bool is_niap_mode) { LOG_INFO(LOG_TAG, "%s: start restricted = %d ; niap = %d", __func__, start_restricted, is_niap_mode); if (interface_ready()) return BT_STATUS_DONE; Loading @@ -146,7 +146,7 @@ static int init(bt_callbacks_t* callbacks, bool start_restricted, bt_hal_cbacks = callbacks; restricted_mode = start_restricted; single_user_mode = is_single_user_mode; niap_mode = is_niap_mode; stack_manager_get_interface()->init_stack(); btif_debug_init(); return BT_STATUS_SUCCESS; Loading @@ -169,7 +169,7 @@ static int disable(void) { static void cleanup(void) { stack_manager_get_interface()->clean_up_stack(); } bool is_restricted_mode() { return restricted_mode; } bool is_single_user_mode() { return single_user_mode; } bool is_niap_mode() { return niap_mode; } static int get_adapter_properties(void) { /* sanity check */ Loading
system/btif/src/btif_config.cc +121 −10 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "btif_config.h" #include <base/base64.h> #include <base/logging.h> #include <ctype.h> #include <openssl/rand.h> Loading Loading @@ -60,8 +61,8 @@ static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S"; constexpr int kBufferSize = 400 * 10; // initial file is ~400B static bool use_key_attestation() { return getuid() == AID_BLUETOOTH && is_single_user_mode(); static bool btif_is_niap_mode() { return getuid() == AID_BLUETOOTH && is_niap_mode(); } #define BT_CONFIG_METRICS_SECTION "Metrics" Loading Loading @@ -93,10 +94,22 @@ static void btif_config_remove_restricted(config_t* config); static std::unique_ptr<config_t> btif_config_open(const char* filename, const char* checksum_filename); // Key attestation static std::string btif_convert_to_encrypt_key( const std::string& unencrypt_str); static std::string btif_convert_to_unencrypt_key( const std::string& encrypt_str); static bool btif_in_encrypt_key_name_list(std::string key); static bool btif_is_key_encrypted(int key_from_config_size, std::string key_type_string); static std::string hash_file(const char* filename); static std::string read_checksum_file(const char* filename); static void write_checksum_file(const char* filename, const std::string& hash); static const int ENCRYPT_KEY_NAME_LIST_SIZE = 7; static const std::string encrypt_key_name_list[] = { "LinkKey", "LE_KEY_PENC", "LE_KEY_PID", "LE_KEY_LID", "LE_KEY_PCSRK", "LE_KEY_LENC", "LE_KEY_LCSRK"}; static enum ConfigSource { NOT_LOADED, ORIGINAL, Loading Loading @@ -269,7 +282,8 @@ static std::unique_ptr<config_t> btif_config_open(const char* filename, const ch std::string stored_hash = read_checksum_file(checksum_filename); if (stored_hash.empty()) { LOG(ERROR) << __func__ << ": stored_hash=<empty>"; if (!current_hash.empty()) { // Will encrypt once since the bt_config never encrypt. if (!btif_keystore.DoesKeyExist() && !current_hash.empty()) { write_checksum_file(checksum_filename, current_hash); stored_hash = read_checksum_file(checksum_filename); } Loading Loading @@ -406,14 +420,29 @@ bool btif_config_get_bin(const std::string& section, const std::string& key, CHECK(length != NULL); std::unique_lock<std::recursive_mutex> lock(config_lock); const std::string* value_str = config_get_string(*config, section, key, NULL); const std::string* value_str; const std::string* value_str_from_config = config_get_string(*config, section, key, NULL); if (!value_str) { if (!value_str_from_config) { VLOG(1) << __func__ << ": cannot find string for section " << section << ", key " << key; return false; } bool in_encrypt_key_name_list = btif_in_encrypt_key_name_list(key); bool is_key_encrypted = btif_is_key_encrypted(value_str_from_config->size(), key); if (in_encrypt_key_name_list && is_key_encrypted) { VLOG(2) << __func__ << " decrypt section: " << section << " key:" << key; std::string tmp_value_str = btif_convert_to_unencrypt_key(*value_str_from_config); value_str = &tmp_value_str; } else { value_str = value_str_from_config; } size_t value_len = value_str->length(); if ((value_len % 2) != 0 || *length < (value_len / 2)) { LOG(WARNING) << ": value size not divisible by 2, size is " << value_len; Loading @@ -427,12 +456,72 @@ bool btif_config_get_bin(const std::string& section, const std::string& key, } const char* ptr = value_str->c_str(); for (*length = 0; *ptr; ptr += 2, *length += 1) for (*length = 0; *ptr; ptr += 2, *length += 1) { sscanf(ptr, "%02hhx", &value[*length]); } if (btif_is_niap_mode()) { if (in_encrypt_key_name_list && !is_key_encrypted) { VLOG(2) << __func__ << " encrypt section: " << section << " key:" << key; std::string encrypt_str = btif_convert_to_encrypt_key(*value_str_from_config); config_set_string(config.get(), section, key, encrypt_str); } } else { if (in_encrypt_key_name_list && is_key_encrypted) { config_set_string(config.get(), section, key, value_str->c_str()); } } return true; } static bool btif_in_encrypt_key_name_list(std::string key) { return std::find(encrypt_key_name_list, encrypt_key_name_list + ENCRYPT_KEY_NAME_LIST_SIZE, key) != (encrypt_key_name_list + ENCRYPT_KEY_NAME_LIST_SIZE); } static bool btif_is_key_encrypted(int key_from_config_size, std::string key_type_string) { if (key_type_string.compare("LinkKey") == 0) { return sizeof(LinkKey) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_PENC") == 0) { return sizeof(tBTM_LE_PENC_KEYS) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_PID") == 0) { return sizeof(tBTM_LE_PID_KEYS) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_LID") == 0) { return sizeof(tBTM_LE_PID_KEYS) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_PCSRK") == 0) { return sizeof(tBTM_LE_PCSRK_KEYS) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_LENC") == 0) { return sizeof(tBTM_LE_LENC_KEYS) * 2 != key_from_config_size; } else if (key_type_string.compare("LE_KEY_LCSRK") == 0) { return sizeof(tBTM_LE_LCSRK_KEYS) * 2 != key_from_config_size; } else { VLOG(2) << __func__ << ": " << key_type_string << " Key type is unknown, return false first"; return false; } } static std::string btif_convert_to_unencrypt_key( const std::string& encrypt_str) { if (!encrypt_str.empty()) { std::string tmp_encrypt_str(""); if (base::Base64Decode(encrypt_str, &tmp_encrypt_str)) { std::string unencrypt_str = btif_keystore.Decrypt(tmp_encrypt_str); if (!unencrypt_str.empty()) { return unencrypt_str; } } else { LOG(WARNING) << __func__ << ": base64string decode fail, will return empty string"; } } return ""; } size_t btif_config_get_bin_length(const std::string& section, const std::string& key) { CHECK(config != NULL); Loading Loading @@ -466,15 +555,37 @@ bool btif_config_set_bin(const std::string& section, const std::string& key, str[(i * 2) + 1] = lookup[value[i] & 0x0F]; } std::string value_str; if (btif_is_niap_mode() && btif_in_encrypt_key_name_list(key)) { VLOG(2) << __func__ << " encrypt section: " << section << " key:" << key; value_str = btif_convert_to_encrypt_key(str); } else { value_str = str; } { std::unique_lock<std::recursive_mutex> lock(config_lock); config_set_string(config.get(), section, key, str); config_set_string(config.get(), section, key, value_str); } osi_free(str); return true; } static std::string btif_convert_to_encrypt_key( const std::string& unencrypt_str) { if (!unencrypt_str.empty()) { std::string encrypt_str = btif_keystore.Encrypt(unencrypt_str, 0); if (!encrypt_str.empty()) { base::Base64Encode(encrypt_str, &encrypt_str); return encrypt_str; } else { LOG(ERROR) << __func__ << ": Encrypt fail, will return empty str."; } } return ""; } std::list<section_t>& btif_config_sections() { return config->sections; } bool btif_config_remove(const std::string& section, const std::string& key) { Loading Loading @@ -641,7 +752,7 @@ static void delete_config_files(void) { } static std::string hash_file(const char* filename) { if (!use_key_attestation()) { if (!btif_is_niap_mode()) { LOG(INFO) << __func__ << ": Disabled for multi-user"; return DISABLED; } Loading Loading @@ -669,7 +780,7 @@ static std::string hash_file(const char* filename) { } static std::string read_checksum_file(const char* checksum_filename) { if (!use_key_attestation()) { if (!btif_is_niap_mode()) { LOG(INFO) << __func__ << ": Disabled for multi-user"; return DISABLED; } Loading @@ -683,7 +794,7 @@ static std::string read_checksum_file(const char* checksum_filename) { static void write_checksum_file(const char* checksum_filename, const std::string& hash) { if (!use_key_attestation()) { if (!btif_is_niap_mode()) { LOG(INFO) << __func__ << ": Disabled for multi-user, since config changed removing " "checksums."; Loading
system/btif/src/btif_keystore.cc +83 −36 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ ******************************************************************************/ #include "btif_keystore.h" #include "keystore_client.pb.h" #include "string.h" #include <base/files/file_util.h> #include <base/logging.h> Loading @@ -29,7 +31,9 @@ using namespace keystore; using namespace bluetooth; constexpr char kKeyStore[] = "AndroidKeystore"; const std::string kKeyStore = "bluetooth-key-encrypted"; constexpr uint32_t kAESKeySize = 256; // bits constexpr uint32_t kMACOutputSize = 128; // bits namespace bluetooth { Loading @@ -43,19 +47,45 @@ std::string BtifKeystore::Encrypt(const std::string& data, int32_t flags) { LOG(ERROR) << __func__ << ": empty data"; return output; } if (!keystore_client_->doesKeyExist(kKeyStore)) { auto gen_result = GenerateKey(kKeyStore, 0, false); if (!gen_result.isOk()) { LOG(FATAL) << "EncryptWithAuthentication Failed: generateKey response=" << gen_result; if (!GenerateKey(kKeyStore, flags)) { return output; } AuthorizationSetBuilder encrypt_params; encrypt_params.Authorization(TAG_BLOCK_MODE, BlockMode::GCM) .Authorization(TAG_MAC_LENGTH, kMACOutputSize) .Padding(PaddingMode::NONE); AuthorizationSet output_params; std::string raw_encrypted_data; if (!keystore_client_->oneShotOperation( KeyPurpose::ENCRYPT, kKeyStore, encrypt_params, data, std::string() /* signature_to_verify */, &output_params, &raw_encrypted_data)) { LOG(ERROR) << __func__ << ": AES operation failed."; return output; } if (!keystore_client_->encryptWithAuthentication(kKeyStore, data, flags, &output)) { LOG(FATAL) << "EncryptWithAuthentication failed."; auto init_vector_blob = output_params.GetTagValue(TAG_NONCE); if (!init_vector_blob.isOk()) { LOG(ERROR) << __func__ << ": Missing initialization vector."; return output; } const hidl_vec<uint8_t>& value = init_vector_blob.value(); std::string init_vector = std::string(reinterpret_cast<const std::string::value_type*>(&value[0]), value.size()); if (memcmp(&init_vector_blob, &init_vector, init_vector.length()) == 0) { LOG(ERROR) << __func__ << ": Protobuf nonce data doesn't match the actual nonce."; } EncryptedData protobuf; protobuf.set_init_vector(init_vector); protobuf.set_encrypted_data(raw_encrypted_data); if (!protobuf.SerializeToString(&output)) { LOG(ERROR) << __func__ << ": Failed to serialize EncryptedData protobuf."; } return output; } Loading @@ -66,36 +96,53 @@ std::string BtifKeystore::Decrypt(const std::string& input) { return ""; } std::string output; if (!keystore_client_->decryptWithAuthentication(kKeyStore, input, &output)) { LOG(FATAL) << "DecryptWithAuthentication failed.\n"; EncryptedData protobuf; if (!protobuf.ParseFromString(input)) { LOG(ERROR) << __func__ << ": Failed to parse EncryptedData protobuf."; return output; } AuthorizationSetBuilder encrypt_params; encrypt_params.Authorization(TAG_BLOCK_MODE, BlockMode::GCM) .Authorization(TAG_MAC_LENGTH, kMACOutputSize) .Authorization(TAG_NONCE, protobuf.init_vector().data(), protobuf.init_vector().size()) .Padding(PaddingMode::NONE); AuthorizationSet output_params; if (!keystore_client_->oneShotOperation( KeyPurpose::DECRYPT, kKeyStore, encrypt_params, protobuf.encrypted_data(), std::string() /* signature_to_verify */, &output_params, &output)) { LOG(ERROR) << __func__ << ": AES operation failed."; } return output; } // Note: auth_bound keys created with this tool will not be usable. KeyStoreNativeReturnCode BtifKeystore::GenerateKey(const std::string& name, int32_t flags, bool auth_bound) { bool BtifKeystore::GenerateKey(const std::string& name, int32_t flags) { if (!DoesKeyExist()) { AuthorizationSetBuilder params; params.RsaSigningKey(2048, 65537) .Digest(Digest::SHA_2_224) .Digest(Digest::SHA_2_256) .Digest(Digest::SHA_2_384) .Digest(Digest::SHA_2_512) .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) .Padding(PaddingMode::RSA_PSS); if (auth_bound) { // Gatekeeper normally generates the secure user id. // Using zero allows the key to be created, but it will not be usuable. params.Authorization(TAG_USER_SECURE_ID, 0); } else { params.Authorization(TAG_NO_AUTH_REQUIRED); } params.AesEncryptionKey(kAESKeySize) .Authorization(TAG_NO_AUTH_REQUIRED) .Authorization(TAG_BLOCK_MODE, BlockMode::GCM) .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT) .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT) .Padding(PaddingMode::NONE) .Authorization(TAG_MIN_MAC_LENGTH, kMACOutputSize); AuthorizationSet hardware_enforced_characteristics; AuthorizationSet software_enforced_characteristics; return keystore_client_->generateKey(name, params, flags, &hardware_enforced_characteristics, auto result = keystore_client_->generateKey( name, params, flags, &hardware_enforced_characteristics, &software_enforced_characteristics); if (!result.isOk()) { LOG(FATAL) << __func__ << "Failed to generate key: name: " << name << ", error code: " << result.getErrorCode(); return false; } } return true; } bool BtifKeystore::DoesKeyExist() { return keystore_client_->doesKeyExist(kKeyStore); } } // namespace bluetooth