【Bluedroid】蓝牙启动之 btif_init_ok 流程源码解析
本文深入分析 Android 蓝牙协议栈(Bluedroid)中 BLE 本地密钥的加载机制。重点剖析
btif_dm_load_ble_local_keys
函数的实现逻辑,解读加密根密钥(ER)和标识密钥组(IR/IRK/DHK)的协同加载策略,揭示了密钥存储与加载的解耦设计。
一、概述
BLE 设备的本地密钥(如 ER、IR、IRK、DHK)是确保蓝牙通信安全的核心数据。在 Android 蓝牙协议栈的btif
(蓝牙接口框架)模块中,密钥的存储与加载涉及三个关键组件:
-
btif_core
:作为初始化入口,通过btif_init_ok
触发密钥加载流程; -
btif_dm
:负责密钥加载的核心逻辑,通过调用存储接口读取密钥并更新全局状态; -
btif_storage
:提供存储映射规则(通过BTIF_STORAGE_LOCAL_LE_KEYS
数组)和密钥读取接口(btif_storage_get_ble_local_key
),实现上层模块与存储系统的解耦。
本文从代码实现出发,详细解析密钥从存储系统到内存的完整加载流程。
二、源码解析
btif_init_ok
packages/modules/Bluetooth/system/btif/src/btif_core.cc
void btif_init_ok() {btif_dm_load_ble_local_keys();
}
btif_dm_load_ble_local_keys
packages/modules/Bluetooth/system/btif/src/btif_dm.ccusing Octet16 = bluetooth::hci::Octet16;
constexpr int kOctet16Length = 16;
using Octet16 = std::array<uint8_t, kOctet16Length>;// 存储 BLE 设备的本地标识密钥组
// btif_dm_local_key_id_t == tBTM_BLE_LOCAL_ID_KEYS == tBTA_BLE_LOCAL_ID_KEYS
typedef struct {Octet16 ir; // 身份解析密钥(Identity Resolving Key, IRK)的关联数据Octet16 irk; // 身份解析密钥(IRK)Octet16 dhk; // Diffie-Hellman 密钥(DHK)
} btif_dm_local_key_id_t;// 记录本地密钥的加载状态和实际数据
typedef struct {bool is_er_rcvd; // ER密钥是否加载成功Octet16 er; // 加密根密钥(Encryption Root Key, ER)bool is_id_keys_rcvd; // 标识密钥组(ir/irk/dhk)是否全部加载成功btif_dm_local_key_id_t id_keys; // 存储标识密钥组的具体值
} btif_dm_local_key_cb_t;// 静态全局变量,在模块内共享当前加载的本地密钥状态和数据
static btif_dm_local_key_cb_t ble_local_key_cb;#define BTIF_DM_LE_LOCAL_KEY_IR (1 << 0)
#define BTIF_DM_LE_LOCAL_KEY_IRK (1 << 1)
#define BTIF_DM_LE_LOCAL_KEY_DHK (1 << 2)
#define BTIF_DM_LE_LOCAL_KEY_ER (1 << 3)void btif_dm_load_ble_local_keys(void) {memset(&ble_local_key_cb, 0, sizeof(btif_dm_local_key_cb_t));// 加载 ER 密钥if (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_ER, &ble_local_key_cb.er) == BT_STATUS_SUCCESS) {ble_local_key_cb.is_er_rcvd = true;log::verbose("BLE ER key loaded");}// 加载标识密钥组(ir/irk/dhk)if ((btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IR,&ble_local_key_cb.id_keys.ir) ==BT_STATUS_SUCCESS) &&(btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IRK,&ble_local_key_cb.id_keys.irk) ==BT_STATUS_SUCCESS) &&(btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_DHK,&ble_local_key_cb.id_keys.dhk) ==BT_STATUS_SUCCESS)) {ble_local_key_cb.is_id_keys_rcvd = true;log::verbose("BLE ID keys loaded");}
}
从存储模块加载BLE 的本地密钥(ER 和标识密钥组),并更新全局变量ble_local_key_cb
的状态。
必须同时加载 IR、IRK、DHK 三个密钥(通过
&&
逻辑与判断),只有全部加载成功时,才标记is_id_keys_rcvd
为true
。说明标识密钥组需要完整加载才有效,任意一个密钥缺失都会导致整个密钥组不可用。
btif_storage_get_ble_local_key
packages/modules/Bluetooth/system/btif/src/btif_storage.cc
// 存储键的元信息
struct BtifStorageKey {uint8_t type; // 密钥类型(与上层模块定义的枚举值绑定)const std::string& name; // 密钥在存储系统中的键名(字符串引用)uint8_t size; // 密钥数据的长度(字节)
};// 定义了 BLE 本地密钥的类型、存储键名、数据长度的映射关系
static const BtifStorageKey BTIF_STORAGE_LOCAL_LE_KEYS[] = {{BTIF_DM_LE_LOCAL_KEY_IR, BTIF_STORAGE_KEY_LE_LOCAL_KEY_IR,sizeof(Octet16)},{BTIF_DM_LE_LOCAL_KEY_IRK, BTIF_STORAGE_KEY_LE_LOCAL_KEY_IRK,sizeof(Octet16)},{BTIF_DM_LE_LOCAL_KEY_DHK, BTIF_STORAGE_KEY_LE_LOCAL_KEY_DHK,sizeof(Octet16)},{BTIF_DM_LE_LOCAL_KEY_ER, BTIF_STORAGE_KEY_LE_LOCAL_KEY_ER,sizeof(Octet16)},
};/** Stores local key of |key_type| into |key_value|* Returns BT_STATUS_SUCCESS if the fetch was successful, BT_STATUS_FAIL* otherwise*/
bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, Octet16* key_value) {// 遍历存储映射数组,查找匹配的密钥类型for (size_t i = 0; i < std::size(BTIF_STORAGE_LOCAL_LE_KEYS); i++) {auto key = BTIF_STORAGE_LOCAL_LE_KEYS[i];if (key.type == key_type) { // 匹配密钥类型// 获取Octet16的长度(固定16字节)size_t length = key_value->size();// 从存储系统读取二进制数据bool ret = btif_config_get_bin(BTIF_STORAGE_SECTION_ADAPTER, // 存储段(属于“适配器”相关分区)key.name, // 存储键名(如BTIF_STORAGE_KEY_LE_LOCAL_KEY_IRK)key_value->data(), // 数据缓冲区(Octet16的底层字节数组)&length // 传入/传出参数:期望长度和实际读取长度);// 根据读取结果返回状态return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;}}// 未找到匹配的密钥类型时记录警告并返回失败log::warn("Unknown LE key type: {}", key_type);return BT_STATUS_FAIL;
}
定义了BLE本地密钥的存储映射关系,并提供了从存储中读取密钥的接口函数。解耦蓝牙上层模块与存储系统,确保密钥数据的存储位置、格式和读取逻辑被统一管理,提高了代码的可维护性和可靠性。
btif_config_get_bin分析见【Bluedroid】蓝牙配对设备管理的源码研究:从NVRAM加载到安全机制实现-CSDN博客
数组作用:
解耦上层与存储系统:上层模块(如
btif_dm
)只需通过密钥类型(type
)即可查询到存储系统中的键名(name
)和数据长度(size
),无需直接关心存储系统的具体实现。标准化存储规则:所有 BLE 本地密钥的存储键名和数据长度通过该数组统一管理,避免因分散定义导致的键名冲突或长度错误。
三、总结
BLE 本地密钥的存储与加载机制是蓝牙安全通信的基础支撑,其核心设计思想可归纳为以下三点:
-
解耦设计:通过
BTIF_STORAGE_LOCAL_LE_KEYS
存储映射数组,将上层模块(如btif_dm
)与存储系统解耦,上层只需关注密钥类型,无需感知存储键名或数据格式; -
状态标准化:通过
ble_local_key_cb
全局变量记录密钥加载状态(is_er_rcvd
、is_id_keys_rcvd
),确保其他模块可快速判断密钥是否可用; -
可靠性保障:标识密钥组(IR/IRK/DHK)需全部加载成功才标记有效,避免因部分密钥缺失导致的通信安全风险。
该机制通过标准化、模块化的设计,有效提升了蓝牙密钥管理的可维护性和可靠性,为 BLE 设备的安全通信提供了关键支撑。