BLE 蓝牙地址类型详解
·
一、BLE 蓝牙地址的两种基本类型
在蓝牙低功耗(Bluetooth Low Energy, BLE)中,设备地址(Bluetooth Device Address, BD_ADDR)分为两大类别:
1. 公共地址(Public Device Address)
- 定义:由 IEEE 分配给制造商的全球唯一地址,类似于以太网的 MAC 地址。
- 特点:
- 48 位(6 字节)长度
- 前 24 位为 Company ID(OUI, Organizationally Unique Identifier),由 IEEE 分配
- 后 24 位由厂商自行分配,确保全球唯一性
- 永不改变,烧录在硬件中
- 标识特征:地址的最高两位(bit 47-46)为
00
2. 随机地址(Random Device Address)
- 定义:设备动态生成的地址,非全球唯一,用于隐私保护。
- 特点:
- 同样为 48 位长度
- 最高两位(bit 47-46)为
01、10或11,用于区分子类型 - 可以周期性更换,防止被追踪
- 子类型:
- 静态随机地址(Static Random Address)
- 私有随机地址(Private Random Address)
- 不可解析私有地址(Non-resolvable Private Address)
- 可解析私有地址(Resolvable Private Address)
二、地址类型的详细标识规则
BLE 地址的 最高两位(bit 47-46) 是区分地址类型的关键标志位:
| 地址类型 | Bit 47 | Bit 46 | 二进制前缀 | 说明 |
|---|---|---|---|---|
| 公共地址 | 0 | 0 | 00... | IEEE 分配的全球唯一地址 |
| 静态随机地址 | 1 | 1 | 11... | 上电时生成,生命周期内不变 |
| 不可解析私有地址 | 0 | 1 | 01... | 周期性更换,不可被解析 |
| 可解析私有地址 | 1 | 0 | 10... | 周期性更换,可被配对设备解析 |
注意:随机地址的其余 46 位不能全为 0 或全为 1,这是 BLE 规范的要求。
三、各地址类型详解
1. 公共地址(Public Device Address)
格式: [OUI (3 bytes)][Company Assigned (3 bytes)]
示例: 00:1A:7D:DA:71:13
└──┬──┘ └────┬────┘
Company ID 厂商分配
- 优点:全球唯一,稳定可靠
- 缺点:永久暴露设备身份,存在隐私风险
- 应用场景:不需要隐私保护的场景,如固定 Beacon、公开设备
2. 静态随机地址(Static Random Address)
- 生成时机:设备每次上电时生成,或首次使用时生成并存储在 Flash 中
- 生命周期:直到设备重新上电或恢复出厂设置前保持不变
- 用途:设备没有公共地址时的替代方案
- 隐私性:中等,地址不随时间变化,但仍非全球唯一
格式: 11xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
↑↑
固定前缀 11
3. 不可解析私有地址(Non-resolvable Private Address)
- 生成方式:完全随机生成(除标志位外)
- 更换周期:建议每 15 分钟更换一次
- 特点:
- 连配对设备也无法识别其身份
- 提供最高级别的隐私保护
- 缺点:配对设备无法自动重连,需要用户手动选择
- 应用场景:对隐私要求极高且不需要自动重连的场景
格式: 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
↑↑
固定前缀 01
4. 可解析私有地址(Resolvable Private Address)
- 生成方式:基于 Identity Resolving Key (IRK) 和随机数生成
- 更换周期:建议每 15 分钟更换一次
- 特点:
- 只有持有相同 IRK 的配对设备才能解析出真实身份
- 兼顾隐私保护和自动重连能力
- 解析原理:
- 地址包含 24 位哈希值和 24 位随机数
- 配对设备使用 IRK 和随机数计算哈希,匹配则识别成功
- 应用场景:大多数 BLE 设备(如手环、耳机)的默认选择
格式: 10xx xxxx xxxx xxxx xxxx xxxx | xxxx xxxx xxxx xxxx xxxx xxxx
↑↑ └────┬────┘ └────┬────┘
固定前缀 10 哈希值(24b) 随机数(24b)
四、地址类型对连接的影响
1. 扫描与广播阶段
| 场景 | 影响 | 说明 |
|---|---|---|
| 广播地址类型 | 决定扫描响应的处理方式 | 扫描方需要根据地址类型决定是否尝试连接 |
| 可解析私有地址广播 | 只有配对设备能识别 | 未配对设备看到的是不断变化的随机地址 |
| 公共地址广播 | 所有设备可见 | 设备身份公开,容易被追踪 |
2. 连接建立阶段
| 地址类型组合 | 连接可行性 | 注意事项 |
|---|---|---|
| 公共 ↔ 公共 | ✅ 完全支持 | 最稳定的连接方式 |
| 公共 ↔ 随机 | ✅ 完全支持 | 需正确识别对方地址类型 |
| 随机 ↔ 随机 | ✅ 完全支持 | 静态随机地址需注意地址冲突(概率极低) |
| 可解析私有 ↔ 可解析私有 | ✅ 支持 | 双方需已配对并交换 IRK |
| 不可解析私有 ↔ 任意 | ⚠️ 受限 | 配对设备无法自动识别,需用户干预 |
3. 连接后的影响
| 特性 | 公共地址 | 静态随机 | 可解析私有 | 不可解析私有 |
|---|---|---|---|---|
| 自动重连 | ✅ 支持 | ✅ 支持 | ✅ 支持(需 IRK) | ❌ 不支持 |
| 隐私保护 | ❌ 无 | ⚠️ 弱 | ✅ 强 | ✅ 最强 |
| 地址变化 | ❌ 不变 | ❌ 不变 | ✅ 周期性变化 | ✅ 周期性变化 |
| 配对要求 | 无 | 无 | 需要配对 | 需要配对 |
| 追踪难度 | 极易 | 较难 | 困难 | 极难 |
4. 实际开发中的注意事项
-
地址类型声明:
- 广播数据包中必须正确声明地址类型(
TxAdd字段) - 连接请求中必须正确指定目标地址类型
- 广播数据包中必须正确声明地址类型(
-
白名单(White List)过滤:
- 使用可解析私有地址时,控制器需要 IRK 才能正确过滤白名单
- 白名单可以配置为只接受特定地址类型的设备
-
绑定(Bonding)与 IRK:
- 配对过程中交换 IRK 是支持可解析私有地址自动重连的前提
- 如果 IRK 丢失,已配对设备将无法识别地址变化后的设备
-
Android/iOS 差异:
- iOS:强制使用随机地址(通常是可解析私有地址),公共地址很少暴露
- Android:较为灵活,但新版本也倾向于使用随机地址保护隐私
- 这导致在开发跨平台应用时,必须正确处理地址类型
-
连接失败排查:
- 如果设备使用随机地址但连接请求中指定为公共地址,连接会失败
- 如果 IRK 不匹配,可解析私有地址设备将无法被白名单接受
五、Python 示例:解析 BLE 地址类型
def parse_ble_address(address: str) -> dict:
"""
解析 BLE 蓝牙地址类型
Args:
address: 蓝牙地址字符串,如 "A4:CF:12:34:56:78"
Returns:
包含地址类型信息的字典
"""
# 清理地址字符串
addr_clean = address.replace(':', '').replace('-', '').replace(' ', '')
if len(addr_clean) != 12:
raise ValueError("无效的蓝牙地址长度")
# 获取第一个字节
first_byte = int(addr_clean[:2], 16)
# 提取最高两位
bit47 = (first_byte >> 7) & 0x01
bit46 = (first_byte >> 6) & 0x01
# 判断地址类型
if bit47 == 0 and bit46 == 0:
addr_type = "公共地址 (Public Device Address)"
subtype = "IEEE 全球唯一地址"
elif bit47 == 1 and bit46 == 1:
addr_type = "随机地址 (Random Device Address)"
subtype = "静态随机地址 (Static Random Address)"
elif bit47 == 0 and bit46 == 1:
addr_type = "随机地址 (Random Device Address)"
subtype = "不可解析私有地址 (Non-resolvable Private Address)"
elif bit47 == 1 and bit46 == 0:
addr_type = "随机地址 (Random Device Address)"
subtype = "可解析私有地址 (Resolvable Private Address)"
else:
addr_type = "未知"
subtype = "未知"
return {
"address": address,
"first_byte": f"0x{addr_clean[:2].upper()}",
"bit47": bit47,
"bit46": bit46,
"address_type": addr_type,
"subtype": subtype,
"oui": addr_clean[:6].upper() if bit47 == 0 and bit46 == 0 else None,
"is_random": not (bit47 == 0 and bit46 == 0)
}
# 示例测试
if __name__ == "__main__":
test_addresses = [
"00:1A:7D:DA:71:13", # 公共地址 (00)
"F4:CF:A2:34:56:78", # 静态随机地址 (11)
"5E:CF:A2:34:56:78", # 不可解析私有地址 (01)
"A4:CF:A2:34:56:78", # 可解析私有地址 (10)
]
for addr in test_addresses:
result = parse_ble_address(addr)
print(f"\n地址: {result['address']}")
print(f" 首字节: {result['first_byte']} (Bit47={result['bit47']}, Bit46={result['bit46']})")
print(f" 类型: {result['address_type']}")
print(f" 子类型: {result['subtype']}")
if result['oui']:
print(f" OUI: {result['oui']}")
六、总结
| 核心要点 | 说明 |
|---|---|
| 地址长度 | 所有 BLE 地址均为 48 位(6 字节) |
| 类型标识 | 最高两位(bit 47-46)决定地址类型 |
| 隐私优先级 | 不可解析私有 > 可解析私有 > 静态随机 > 公共 |
| 自动重连 | 只有公共、静态随机、可解析私有地址支持 |
| 开发注意 | 必须正确声明和识别地址类型,否则连接失败 |
BLE 的地址类型设计在 设备识别 和 隐私保护 之间取得了平衡。理解这些地址类型及其标识规则,对于开发稳定的 BLE 应用和排查连接问题至关重要。
更多推荐



所有评论(0)