1. 概述
BLE设备地址(Bluetooth Device Address,BD_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, RPA)
3. 公共地址(Public Address)
公共地址是由IEEE注册管理机构分配的全球唯一地址,需要向IEEE购买。其格式符合IEEE EUI-48标准:

-
高24位:组织唯一标识符(OUI),标识设备制造商
-
低24位:厂商内部分配的设备编号
示例 :
00:1A:7D:12:34:56中,00:1A:7D是Apple的厂商代码
特点:
-
✅ 全球唯一,不会冲突
-
✅ 永久不变,适合需要稳定身份识别的场景
-
❌ 需要付费申请,流程复杂
-
❌ 固定地址容易被追踪,存在隐私风险
适用场景:工业设备、网关、高端旗舰产品等需要永久固定身份的设备
4. 随机地址
随机地址分为静态地址和私有地址。
其中子类型由bit47:46决定,如下:

4.1 静态地址(Static Address)
静态地址是为了帮助厂商节省购买公共地址的费用 而引入的。它是由设备随机生成的48位地址,需要满足以下条件:
-
最高两位(bit47:46)为
11 -
随机部分至少有一位为
0 -
随机部分至少有一位为
1

特征 :地址以
C0-FF开头
生命周期 :设备可以在每次上电/复位时 生成一个新的静态地址,但在本次上电期间不得更改。
⚠️ 重要注意事项 :如果设备的静态地址发生变化,存储在对端设备中的旧地址将失效,使用旧地址重新连接的能力将丧失。
适用场景:智能手环、体重秤、温度计等成本敏感且不需要强隐私保护的外设
4.2 不可解析私有地址(Non-resolvable Private Address, NRPA)
NRPA是一种完全随机、无法被任何设备解析 的临时地址。其最高两位为 00,地址以 00-3F 开头。

特点:
-
周期性更新(建议间隔15分钟)
-
任何设备都无法识别其真实身份
-
实际应用中较少使用
适用场景 :BLE Beacon广播、一次性数据推送等不需要建立连接的单向通信场景。
注 :使用NRPA的设备仍然必须拥有一个公共地址或静态地址作为身份地址。
4.3 可解析私有地址(Resolvable Private Address, RPA)
RPA是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) 来区分:
| 最高两位 | 地址开头范围 | 地址类型 |
|---|---|---|
00 |
00-3F | 不可解析私有地址(NRPA) |
01 |
40-7F | 可解析私有地址(RPA) |
10 |
80-BF | 保留(未使用) |
11 |
C0-FF | 静态地址 |
⚠️ 特别注意 :这种方法仅适用于随机地址 类型。要区分"公共地址"和"随机地址",需要查看链路层数据包中的TxAdd/RxAdd标志位,而非地址值本身
5. 随机地址生成
5.1 前置规则
在讲具体公式前,首先要明确所有随机地址(无论哪种子类型)在生成时必须遵守的共同底线(Core Specification强制要求):
-
不能全为0 (
0x000000000000) -
不能全为1 (
0xFFFFFFFFFFFF) -
必须符合各自子类型的最高两位(bit47:46) 标识要求
5.2 静态地址(Static Address)生成公式
静态地址是最简单的随机地址,其生成过程本质上就是一个符合特定格式的48位随机数
Static_Address = random(48 bits)
约束条件(强制位掩码):
设地址的最高字节 为 Byte5(即第47~40位),则必须满足:
Byte5 & 0xC0 == 0xC0 // 即最高两位 bit47:46 = '11'
由于最高两位固定为11,静态地址的十六进制范围一定在 0xC0 ~ 0xFF 之间。
实现伪代码
python
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
其中:
-
Prand(24位):一个满足特定条件的随机数。
-
Hash(24位):通过密钥和Prand计算出的哈希值。
注意 :这里的
Prand是整个RPA的低24位 (bit23 ~ bit0),Hash是高24位(bit47 ~ bit24)
5.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 << 104
(2)AES-128加密:
使用IRK(128位)作为密钥,对上述128位输入块 M 进行AES-128加密运算。
Encrypted_Block = AES_128(IRK, M)
(3)截取低24位:
取加密结果(128位)的最低有效24位(LSB),作为最终的Hash值。
Hash = Encrypted_Block & 0xFFFFFF
5.4.4 至关重要的额外约束
生成 Hash 后,必须检查最终48位RPA地址的最高两位 是否为 '01'。
因为RPA地址的 bit47:46 来自 Hash 的最高两位(即 Hash 的最高字节中的前两位)。为了确保该地址是合法的RPA(范围 0x40~0x7F),Hash 的最高两位必须为 '01'。
如果在一次生成中,算出的Hash最高位不是01怎么办?
规范要求:必须重新生成一个新的Prand,重新计算Hash,直到满足该条件为止。
这解释了为什么手机在开启蓝牙时偶尔会短暂显示非40-7F开头的地址------那是设备在内部循环重试生成符合规则的RPA。
5.4.5 RPA生成完整伪代码
python
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, byteorder='big')
# 2. AES-128加密
cipher = AES.new(irk, AES.MODE_ECB)
encrypted = cipher.encrypt(M_bytes)
# 3. 取加密结果的最低24位
hash_int = int.from_bytes(encrypted, byteorder='big') & 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 rpa
5.5 对端设备解析RPA
理解了生成公式,解析公式就顺理成章了。当对端设备(已拥有该设备的IRK)扫描到该RPA时,执行以下操作:
(1)拆分地址:
从扫描到的RPA中提取高24位(Hash_received)和低24位(Prand_received)。
Prand_received = RPA & 0xFFFFFF
Hash_received = RPA >> 24
(2)本地计算 :
用自己的IRK(存储的该设备IRK)和提取出的Prand_received,按照相同的 ah 公式计算本地Hash:
Hash_calculated = ah(local_IRK, Prand_received)
(3)匹配验证
如果 Hash_calculated == Hash_received,则说明该RPA确实是由持有该IRK的设备生成的,解析成功,该对端设备可以将此RPA视为已知设备进行处理。
如果设备本地存储了多个配对设备的IRK,它会逐一尝试匹配,直到成功或全部失败
5.6 公式汇总
| 地址类型 | 生成公式 | 最高位约束 | 核心依赖 |
|---|---|---|---|
| 静态地址 | random(48) |
bit47:46 = 11 |
无(纯随机) |
| NRPA | random(48) |
bit47:46 = 00 |
无(纯随机) |
| RPA | `(ah(IRK, Prand) << 24) | Prand` | bit47:46 = 01(由Hash保证) |
6.常见问题
Q1:一个BLE设备可以同时拥有多个地址吗?
可以。一个设备可以同时拥有公共地址和静态随机地址。如果使用RPA,还必须有身份地址。设备可以通过其使用的任何地址被寻址。
Q2:为什么手机的蓝牙地址总是变化?
现代手机使用可解析私有地址(RPA),通常每10-15分钟变化一次,目的是防止位置追踪。
Q3:静态地址变化后会怎样?
如果静态地址在重新上电后发生变化,存储在对端设备中的旧地址将失效,无法再使用旧地址重新连接。
Q4:公共地址和随机地址的48位值相同怎么办?
如果两个设备的48位地址值相同,但一个属于公共地址类型、另一个属于随机地址类型,它们被视为两个不同的设备。