BLE协议之设备地址 📅 2026/7/6 3:11:40 1. 概述BLE设备地址Bluetooth Device AddressBD_ADDR是一个48位6字节的标识符用于在蓝牙低功耗网络中唯一识别一个设备。它在概念上类似于网卡MAC地址是BLE通信的基石无论是设备发现、广播还是连接建立都离不开这个地址。一个BLE设备地址通常以16进制表示6个字节用冒号分隔例如00:11:22:33:FF:EE。一个容易被忽略但至关重要的概念是BLE设备地址由“地址值48位”和“地址类型”共同构成。即使两个设备的48位地址值完全相同只要它们的地址类型不同它们就被视为两个不同的设备。地址类型的标识位于链路层广播包的PDU Header中而非48位地址本身2. BLE地址的分类体系BLE设备地址分为两大类公共地址Public Address和随机地址Random Address。随机地址又可细分为三类总计四种地址类型。BLE设备地址 ├── 公共地址Public Address └── 随机地址Random Address ├── 静态地址Static Address └── 私有地址Private Address ├── 不可解析私有地址Non-resolvable Private Address └── 可解析私有地址Resolvable Private Address, RPA3. 公共地址Public Address公共地址是由IEEE注册管理机构分配的全球唯一地址需要向IEEE购买。其格式符合IEEE EUI-48标准高24位组织唯一标识符OUI标识设备制造商低24位厂商内部分配的设备编号示例00:1A:7D:12:34:56中00:1A:7D是Apple的厂商代码特点✅ 全球唯一不会冲突✅ 永久不变适合需要稳定身份识别的场景❌ 需要付费申请流程复杂❌ 固定地址容易被追踪存在隐私风险适用场景工业设备、网关、高端旗舰产品等需要永久固定身份的设备4. 随机地址随机地址分为静态地址和私有地址。其中子类型由bit[47:46]决定如下4.1 静态地址Static Address静态地址是为了帮助厂商节省购买公共地址的费用而引入的。它是由设备随机生成的48位地址需要满足以下条件最高两位bit47:46为11随机部分至少有一位为0随机部分至少有一位为1特征地址以C0-FF开头生命周期设备可以在每次上电/复位时生成一个新的静态地址但在本次上电期间不得更改。⚠️ 重要注意事项如果设备的静态地址发生变化存储在对端设备中的旧地址将失效使用旧地址重新连接的能力将丧失。适用场景智能手环、体重秤、温度计等成本敏感且不需要强隐私保护的外设4.2 不可解析私有地址Non-resolvable Private Address, NRPANRPA是一种完全随机、无法被任何设备解析的临时地址。其最高两位为00地址以00-3F开头。特点周期性更新建议间隔15分钟任何设备都无法识别其真实身份实际应用中较少使用适用场景BLE Beacon广播、一次性数据推送等不需要建立连接的单向通信场景。注使用NRPA的设备仍然必须拥有一个公共地址或静态地址作为身份地址。4.3 可解析私有地址Resolvable Private Address, RPARPA是BLE隐私保护的核心机制。它允许设备使用一个周期性变化的随机地址同时只有持有共享密钥的 trusted 设备才能解析出真实身份。地址特征最高两位为01地址以40-7F开头。工作原理配对时两个BLE设备交换身份解析密钥Identity Resolving Key, IRK广播时设备使用自己的IRK生成一个临时的RPA扫描时持有该设备IRK的对端设备可以通过算法解析出RPA背后的真实身份地址陌生人没有IRK的设备只能看到一个随机变化、无法追踪的地址隐私保护效果外部观察者无法通过地址模式追踪设备的位置和活动只有已配对的信任设备才能相互识别地址定期变化通常每15分钟适用场景iPhone、Apple Watch、Android手机、AirPods等需要隐私保护的消费电子设备。注使用RPA的设备必须同时拥有一个身份地址公共地址或静态地址4.4. 通过地址值判断类型随机地址的三种子类型可以通过地址最高字节的最高两位bit47:46来区分最高两位地址开头范围地址类型0000-3F不可解析私有地址NRPA0140-7F可解析私有地址RPA1080-BF保留未使用11C0-FF静态地址⚠️ 特别注意这种方法仅适用于随机地址类型。要区分“公共地址”和“随机地址”需要查看链路层数据包中的TxAdd/RxAdd标志位而非地址值本身5. 随机地址生成5.1 前置规则在讲具体公式前首先要明确所有随机地址无论哪种子类型在生成时必须遵守的共同底线Core Specification强制要求不能全为00x000000000000不能全为10xFFFFFFFFFFFF必须符合各自子类型的最高两位bit47:46标识要求5.2 静态地址Static Address生成公式静态地址是最简单的随机地址其生成过程本质上就是一个符合特定格式的48位随机数Static_Address random(48 bits)约束条件强制位掩码设地址的最高字节为Byte5即第47~40位则必须满足Byte5 0xC0 0xC0 // 即最高两位 bit47:46 11由于最高两位固定为11静态地址的十六进制范围一定在0xC0~0xFF之间。实现伪代码import random def generate_static_address(): while True: # 1. 生成一个随机的48位整数 addr_int random.getrandbits(48) # 2. 将最高两位强制设置为 11 addr_int | (0b11 46) # 3. 校验非全0非全1且随机部分至少含一个0和一个1 if addr_int ! 0xFFFFFFFFFFFF and addr_int ! 0x0: # 进一步确保除最高两位外至少有一位是0至少有一位是1 lower_bits addr_int 0x3FFFFFFFFFFF # 屏蔽最高两位 if lower_bits ! 0 and lower_bits ! 0x3FFFFFFFFFFF: return addr_int关键点生命周期内不变虽然生成过程简单但规范要求该地址必须在本次上电周期内保持不变。断电重启后可以重新生成新地址5.3 不可解析私有地址NRPA生成公式NRPA与静态地址极为相似只是最高两位标识不同。它也是纯粹的随机数。NRPA_Address random(48 bits)约束条件强制位掩码Byte5 0xC0 0x00 // 最高两位 bit47:46 00十六进制范围一定在0x00~0x3F之间但需排除全0。5.4 可解析私有地址RPA生成公式RPA是BLE隐私保护的核心生成它不是简单的随机数填充而是使用了AES-128加密算法进行密码学运算。5.4.1 RPA的整体结构公式RPA (48 bits) (Hash 24) | Prand其中Prand24位一个满足特定条件的随机数。Hash24位通过密钥和Prand计算出的哈希值。注意这里的Prand是整个RPA的低24位bit23 ~ bit0Hash是高24位bit47 ~ bit245.4.2 Prand的生成约束Prand虽然是24位随机数但有严格的位约束为了配合整体地址的标识最高两位bit23:22必须为10这是生成RPA时对Prand的底层要求非全0非全1由于Prand的最高两位是10因此Prand的十六进制取值范围一定在0x80~0xBF之间针对最高字节。5.4.3 Hash的计算公式核心密码学Hash的计算依赖于身份解析密钥IRK和Prand公式如下Hash ah(IRK, Prand)其中ah函数即“Address Hashing”函数的具体算法为1构造128位输入块将24位的Prand放入128位数据块的最高有效位MSB其余104位全部补0。M Prand (128 - 24) Prand 1042AES-128加密使用IRK128位作为密钥对上述128位输入块M进行AES-128加密运算。Encrypted_Block AES_128(IRK, M)3截取低24位取加密结果128位的最低有效24位LSB作为最终的Hash值。Hash Encrypted_Block 0xFFFFFF5.4.4 至关重要的额外约束生成Hash后必须检查最终48位RPA地址的最高两位是否为01。因为RPA地址的bit47:46来自Hash的最高两位即Hash的最高字节中的前两位。为了确保该地址是合法的RPA范围0x40~0x7FHash的最高两位必须为01。如果在一次生成中算出的Hash最高位不是01怎么办规范要求必须重新生成一个新的Prand重新计算Hash直到满足该条件为止。这解释了为什么手机在开启蓝牙时偶尔会短暂显示非40-7F开头的地址——那是设备在内部循环重试生成符合规则的RPA。5.4.5 RPA生成完整伪代码from Crypto.Cipher import AES import os def ah(irk, prand): # 1. 将24位prand填充到128位块的最高位 M prand (128 - 24) # 将M转换为16字节的字节数组大端序 M_bytes M.to_bytes(16, byteorderbig) # 2. AES-128加密 cipher AES.new(irk, AES.MODE_ECB) encrypted cipher.encrypt(M_bytes) # 3. 取加密结果的最低24位 hash_int int.from_bytes(encrypted, byteorderbig) 0xFFFFFF return hash_int def generate_rpa(irk): while True: # 1. 生成24位Prand确保最高两位为 10 (即0x80-0xBF范围) prand random.getrandbits(24) prand | (0b10 22) # 强制bit23:22 10 # 校验非全0非全1除去固定位 if prand 0x3FFFFF or prand 0x0: continue # 2. 计算Hash hash_val ah(irk, prand) # 3. 关键校验Hash的最高两位必须为 01即Hash最高字节在0x40-0x7F if (hash_val 0xC00000) 0x400000: # 0xC00000是24位的最高两位掩码 # 4. 拼接最终RPA rpa (hash_val 24) | prand return rpa5.5 对端设备解析RPA理解了生成公式解析公式就顺理成章了。当对端设备已拥有该设备的IRK扫描到该RPA时执行以下操作1拆分地址从扫描到的RPA中提取高24位Hash_received和低24位Prand_received。Prand_received RPA 0xFFFFFF Hash_received RPA 242本地计算用自己的IRK存储的该设备IRK和提取出的Prand_received按照相同的ah公式计算本地HashHash_calculated ah(local_IRK, Prand_received)3匹配验证如果Hash_calculated Hash_received则说明该RPA确实是由持有该IRK的设备生成的解析成功该对端设备可以将此RPA视为已知设备进行处理。如果设备本地存储了多个配对设备的IRK它会逐一尝试匹配直到成功或全部失败5.6 公式汇总地址类型生成公式最高位约束核心依赖静态地址random(48)bit47:46 11无纯随机NRPArandom(48)bit47:46 00无纯随机RPA(ah(IRK, Prand) 24) | Prandbit47:46 01由Hash保证IRK AES-1286.常见问题Q1一个BLE设备可以同时拥有多个地址吗可以。一个设备可以同时拥有公共地址和静态随机地址。如果使用RPA还必须有身份地址。设备可以通过其使用的任何地址被寻址。Q2为什么手机的蓝牙地址总是变化现代手机使用可解析私有地址RPA通常每10-15分钟变化一次目的是防止位置追踪。Q3静态地址变化后会怎样如果静态地址在重新上电后发生变化存储在对端设备中的旧地址将失效无法再使用旧地址重新连接。Q4公共地址和随机地址的48位值相同怎么办如果两个设备的48位地址值相同但一个属于公共地址类型、另一个属于随机地址类型它们被视为两个不同的设备。