术语和缩略词
-
Identity Resolving Key(IRK):身份解析密钥,配对过程第三阶段交换的密钥,用于生成和解析 RPA 地址。
-
Identity Address:身份地址,可使用公共地址或者随机静态地址作为身份地址
-
Resolving List:解析列表,链路层维护的表,包含与身份地址相关联的本地和对端 IRK 的一个或多个条目。
-
Device Identity: 设备身份,由对等设备的身份地址以及本地和对等设备的 IRK 对组成。
蓝牙地址类型
-
公共地址 (Public Address)
全球范围内独一无二的固定设备地址,厂商必须为此到 IEEE 组织注册并缴纳一定费用。
-
随机静态地址 (Random Static Address)
无需到 IEEE 组织注册,可以随固件固化于设备,也可以在设备启动时随机生成,在一个电源周期内不会改变;常作为公共地址的平替。
-
可解析随机私有地址 (Resolvable Random Private Address, RPA)
目的是防止恶意第三方跟踪蓝牙设备,同时仍允许一个或多个受信任方识别感兴趣的蓝牙设备。该地址由 IRK 生成和解析。设备在配对过程中共享此密钥,并在绑定时存储它。除了 IRK,设备还共享其身份地址,这是一个随机的静态或公共地址。对等设备的最终信息称为设备身份。
设备身份由对等设备的身份地址以及本地和对等设备的 IRK 对组成。RPA 是蓝牙 LE 隐私的基础。
这种地址会定期更改。蓝牙规范建议每 15 分钟更改一次。
- 0 和 1 固定在最高有效位 (MSB) 中
- 接下来的 22 位是随机生成的
- prand 由这 24 个最高有效位组成
- 低 24 位表示使用 prand 和 IRK 生成的哈希值
-
不可解析随机私有地址 (Non-resolvable Random Private Address)
完全随机的地址,也会定期更改,不可被任何其他设备解析,仅用于防止设备被追踪,非常少用,有时用于信标应用。
BLE 中的隐私(privacy)
这里的隐私指的是确保不受信任的一方无法通过其蓝牙地址跟踪设备,蓝牙设备的隐私是通过使用 RPA 地址来实现的。这种类型的地址需要绑定两个蓝牙设备,以便一个设备能够解析另一个设备的地址。
实现 BLE 隐私涉及如下步骤:
-
IRK 用于生成和解析 RPA 地址。
-
IRK 由每个设备在本地随机生成或在制造期间分配。
-
在绑定期间,每个设备将对端设备的 IRK 存储在解析列表(resolving list) 中。
-
使用 IRK 来解析对端设备的私有地址,比如,当它稍后收到对端设备的广播包时。
-
这是通过根据以下公式验证私有地址中包含的哈希值与本地哈希计算的输出值是否匹配来完成的。
hash = ah(IRK, prand)
-
由于设备本地存储了 IRK,并且可以访问 BLE 数据包中的私有地址中的 prand,因此它可以执行此计算。
值得注意的是,IRK 并不直接用于显示对端的身份地址。相反,它仅用于验证目的。然后,设备可以通过 IRK 和安全数据库将 RPA 映射回身份地址(一旦地址通过验证)。
Address resolution procedure
假设智能手表是广播设备,手机是扫描设备,两者在第一次连接中都使用 RPA。
使用蓝牙 LE 安全连接,加密链接并交换安全数据,包括其身份地址(静态随机或公共地址)和 IRK。
在广播之前,智能手表会生成一个随机数,称为 prand,并将其与自己的 IRK 一起使用,作为哈希函数的输入。输出是哈希值。哈希值和 prand 连接组合为智能手表的地址添加到广播包中。
手机接收来自智能手表的广播包并解析 RPA。它使用收到的 22 位 prand 和存储的 IRK 来生成本地哈希值。它存储了智能手表的 IRK 以及身份地址。这个过程中,会将 resolving list 中的 Peer IRK 都遍历一遍,本地计算哈希值与 RPA 地址中的哈希值进行匹配,并识别出广播设备。但智能手表是否接收手机的连接还取决于白名单。
需要强调的是,此操作既耗时又耗电,因此解析列表的大小受到限制。
Bluetooth LE host and controller privacy
隐私功能有两种变体:基于主机和基于控制器(Host and Controller-based)
Host-based: 在第一个变体中,私有地址由主机解析和生成。主机在解析期间访问对等设备身份。
Controller-based: 在第二个变体中,在主机向控制器提供其自身身份以及对等设备身份后,控制器解析和生成私有地址。主机仍负责在需要时添加和删除设备标识来维护解析列表。此外,在使用第二个变体时,主机可以提供扩展解析列表,以防控制器无法存储绑定设备所需的所有设备身份解析密钥。
如果控制器无法解析广播中对等设备标识地址,它会将事件传递给主机进行解析。
如果对等设备地址已被控制器解析,则从控制器到主机的所有传入事件都使用对等设备身份。
当在控制器中执行地址解析时,设备过滤成为可能,因为可以在检查对等设备是否在白名单中之前解析出对等设备的身份地址。
链路层可以根据对等设备的地址执行设备过滤。此过程允许链路层最小化其响应的设备数量。链路层用于设备过滤的设备集称为白名单。设备过滤也与使用的隐私变体直接相关。当使用基于控制器的隐私时,传入的 RPA 由扫描设备的控制器解析,设备身份在白名单中得到验证,白名单也位于控制器中。如果在白名单中找到收到的身份,则将其传递给主机进行进一步的连接处理。否则,即使它是对等设备,也会被忽略。
隐私功能有两种模式:设备隐私(device privacy) 和 网络隐私(network privacy)。这些模式决定了启用隐私的设备如何处理与其对等设备的连接创建。
处于设备隐私模式的设备只关心自己的隐私,并接受来自对等设备的包含其身份地址的广播数据包以及包含随机私有地址的广播数据包,即使对等设备过去已经分发了其 IRK。
在网络隐私模式下,所有设备都必须使用随机地址。在此模式下,设备仅接受来自对等设备的包含私有地址的广播数据包。网络隐私是基于控制器的隐私的默认行为。
例如,假设智能手表和手机是绑定设备。
在手机的解析列表中,智能手表身份信息设置为设备隐私模式。当智能手表在广播有效负载中使用自己的身份地址(静态随机或公共地址,而不是 RPA)进行广播时,手机会接受广播数据包并建立连接链路。手机并不关心智能手表是否泄露了自己的身份。
第二种情况,在手机的解析列表中,智能手表身份信息设置为网络隐私模式。当智能手表在广播有效载荷中用自己的身份地址进行广播(静态随机或公共地址,而不是 RPA)时,手机不会接受广播包,连接链接也是不可能建立的。在这种情况下,手机确实担心智能手表会泄露自己的身份。
Security models
BLE 安全中常见的三种攻击类型:
- Identity tracking(身份追踪)
身份跟踪利用蓝牙地址来跟踪设备。防止此类攻击需要隐私保护。这可以通过使用随机变化的可解析私有地址(RPA)来实现,其中只有绑定/受信任的设备才能解析私有地址。IRK(身份解析密钥)用于生成和解析私有地址。 - Passive eavesdropping (sniffing) 被动窃听(嗅探)
被动窃听允许攻击者监听设备之间传输的数据。可以通过加密对等设备之间的通信来防止这种情况。这里的挑战是对等设备如何生成和/或交换密钥以安全地加密连接。这是导致 BLE 传统配对(legacy pairing)易受攻击的主要缺点,并产生了对 BLE 安全连接(Secure Connection)的需求。 - Active eavesdropping (Man-in-the-middle, or MITM) 主动窃听(中间人或 MITM)
在主动窃听(或中间人)攻击中,攻击者会冒充两个合法设备,诱骗它们连接到自己。为了防止这种情况发生,需要确保正在通信的设备确实是想要通信的设备,而不是未经身份验证的设备。
安全级别(Security levels)
BLE 在 security mode 1 中定义了 4 个安全级别:
- Level 1: No security (open text, meaning no authentication and no encryption)
- Level 2: Encryption with unauthenticated pairing
- Level 3: Authenticated pairing with encryption
- Level 4: Authenticated LE Secure Connections pairing with encryption
Legacy Pairing | LE Secure Connection | |
---|---|---|
Just Works | Level2 | Level2 |
Passkey Entry | Level3 | Level4 |
Numeric Comparison | N/A | Level4 |
OOB | Level3 | Level4 |
(Legacy Pairing 不支持 Numeric Comparison)
BLE 共有 3 种安全模式。安全模式 2 使用数据签名来确保安全,很少使用。安全模式 3 属于同步广播,用于蓝牙 LE 音频。
Filter Accept List
过滤接受列表(也称为白名单)是一种在广播和扫描中限制对设备列表的访问的方法。
在广播中使用时,只有过滤接受列表中的设备可以发送连接请求以建立连接或发送扫描请求以获取扫描响应。如果不在列表中的设备发送这些请求,广播设备将忽略该请求。
在扫描中使用时,只有列表中设备的广播和扫描响应数据包才会被扫描并报告给应用程序。扫描设备将过滤掉来自其他广播设备的任何数据包。
常见问题分享
-
使用官方 bleprph 示例,开启链路加密,手机连接设备时没有像 gatt_security_server 弹出配对请求窗口是什么原因?
Answer:Nimble 和 Bluedroid 的配对部分有所不同,Bluedroid 是主动调用
esp_ble_set_encryption
发起Security Request
,接下来 Master 才会发起配对请求。Nimble 中与之对应的接口是
ble_gap_security_initiate
,但是 bleprph 例程中没有调用,当 master 连接到 ESP 设备后,对有 read/write 加密标志的特征/描述符进行读/写操作时,才会主动发起配对请求,手机侧会弹出配对请求窗口。与 EXAMPLE_ENCRYPTION 相关的代码:
static const ble_uuid128_t gatt_svr_chr_uuid = BLE_UUID128_INIT(0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33); /* A custom descriptor */ static uint8_t gatt_svr_dsc_val; static const ble_uuid128_t gatt_svr_dsc_uuid = BLE_UUID128_INIT(0x01, 0x01, 0x01, 0x01, 0x12, 0x12, 0x12, 0x12, 0x23, 0x23, 0x23, 0x23, 0x34, 0x34, 0x34, 0x34);
static const struct ble_gatt_svc_def gatt_svr_svcs[] = { { /*** Service ***/ .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &gatt_svr_svc_uuid.u, .characteristics = (struct ble_gatt_chr_def[]) { { /*** This characteristic can be subscribed to by writing 0x00 and 0x01 to the CCCD ***/ .uuid = &gatt_svr_chr_uuid.u, .access_cb = gatt_svc_access, #if CONFIG_EXAMPLE_ENCRYPTION .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE, #else .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE, #endif .val_handle = &gatt_svr_chr_val_handle, .descriptors = (struct ble_gatt_dsc_def[]) { { .uuid = &gatt_svr_dsc_uuid.u, #if CONFIG_EXAMPLE_ENCRYPTION .att_flags = BLE_ATT_F_READ | BLE_ATT_F_READ_ENC, #else .att_flags = BLE_ATT_F_READ, #endif .access_cb = gatt_svc_access, }, { 0, /* No more descriptors in this characteristic */ } }, }, { 0, /* No more characteristics in this service. */ } }, }, { 0, /* No more services. */ }, };
测试时,配置的 IO 能力是
Display Yes/No
,设备端需要输入key Y
进行配对。
本地有抓取蓝牙空口包分析配对功能交换过程,例程未作任何修改时抓包如下:
若要达到和 gatt_security_server 示例同样的效果,可以在BLE_GAP_EVENT_CONNECT
事件处调用ble_gap_security_initiate
。case BLE_GAP_EVENT_CONNECT: /* A new connection was established or a connection attempt failed. */ MODLOG_DFLT(INFO, "connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed", event->connect.status); if (event->connect.status == 0) { rc = ble_gap_conn_find(event->connect.conn_handle, &desc); assert(rc == 0); bleprph_print_conn_desc(&desc); rc = ble_gap_security_initiate(event->connect.conn_handle); if (rc != 0) { MODLOG_DFLT(INFO, "Security could not be initiated, rc = %d\n", rc); return ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM); } else { MODLOG_DFLT(INFO, "Connection secured\n"); } } ...
对应的蓝牙抓包如下,可以看到 Slave 端主动发送
Security Request
数据包。
只有中央设备可以发送配对请求(Pairing Request)。外围设备可以发送安全请求(Security Request),从而触发中央设备的配对请求,蓝牙 Core Spec 中关于配对功能交换过程的框图如下:
-
使用官方 bleprph 示例,手机端和设备进行配对绑定,设备重启后,手机端需要重新配对,是什么原因?
Answer:需要使能
CONFIG_BT_NIMBLE_NVS_PERSIST
,配置路径:Menu path: (Top) -> Component config -> Bluetooth -> NimBLE Options -> [*] Persist the BLE Bonding keys in NVS
该配置项用于将配对信息保存到 NVS 中,默认关闭,当设备重启后,配对信息丢失,会将之前绑定的 master 设备视为一个新设备,需要重新配对。
-
使用 ESP32,官方 bleprph 示例,手机端和设备进行配对绑定,30min 后,手机连接设备需要重新配对,是什么原因?
Answer:请检查是否有使能 EXAMPLE_RESOLVE_PEER_ADDR,手机端一般使用 RPA 地址,蓝牙规范建议每 15 分钟更改一次 RPA,若未开启该选项, 设备之间不会分享 IRK,当手机更改其地址时,ESP 将无法解析,会将其视为新设备,因此需要重新配对。
#ifdef CONFIG_EXAMPLE_RESOLVE_PEER_ADDR /* Stores the IRK */ ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ID; ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ID; #endif
-
ESP32 如何将使用 RPA 地址的设备添加到白名单?
Answer:在 ESP32 上,whitelist 由 controller 实现,privacy 由 host 实现。
ESP32 控制器支持 RPA 地址解析,但它仅支持网络隐私模式,只能接受 RPA 地址,不能接受身份地址,因此我们默认在 ESP32 上使用基于主机的隐私。
白名单由控制器实现,ESP32 默认使用基于主机的隐私,RPA 地址无法解析,可以开启 CONFIG_BT_BLE_RPA_SUPPORTED(配置路径:Menu path: (Top) -> Component config -> Bluetooth -> Bluedroid Options -> [*] Update RPA to Controller
),这样将使用基于控制器的隐私,控制器可以解析 RPA 并使用白名单进行过滤。只有 ESP32 比较特殊,其他支持 BLE 的芯片 whitelist 和 privacy 都是 controller 实现的,可以支持添加 RPA 地址到白名单,只需要添加地址并把参数
wl_addr_type
设置为BLE_WL_ADDR_TYPE_RANDOM
即可。可以
ESP_GAP_BLE_AUTH_CMPL_EVT
事件中添加白名单:esp_ble_gap_update_whitelist(true, param->ble_security.auth_cmpl.bd_addr, param->ble_security.auth_cmpl.addr_type);
参考资料
Security in Bluetooth LE communication
Bluetooth Addresses & Privacy in Bluetooth Low Energy