提供商广告信号
广告:可被发现时
当提供方设备可被 BR/EDR 发现(即处于配对模式)时,它应通过 BLE 通告快速配对模型 ID 数据,并且 BLE 地址不得轮替。
广告间隔时间:在可检测到时
广告之间的间隔不得超过 100 毫秒 (10Hz)。快速速率可让查找器快速找到提供方,即使在低功耗模式下扫描也是如此。
广告载荷:快速配对模型 ID 数据
通告应包含服务数据数据类型,同上,§ 1.11. UUID 应为 0xFE2C
的快速配对服务 UUID。服务数据应包含以下内容:
八位字节 | 数据类型 | 说明 | 值 |
---|---|---|---|
0-2 | uint24 |
24 位型号 ID | 不定 |
广告:不可检测到时
在不可检测(即未处于配对模式)时,提供方设备应按照以下准则通告快速配对账号数据。
通过通告账号数据,附近的查找者可以识别提供商是否属于其账号,并发起配对,而无需先强制将提供商恢复为配对模式(这也是用户投诉的常见原因)。在用户不等待与提供方配对或广播不相关(例如,如果他们已配对)的情况下,查找器会让用户有机会忽略此广播。查找者还会自动滤除明显不良的直播,例如账号数据配置错误时。
广告间隔时间:不可检测时
广告之间的间隔不得超过 250 毫秒 (4 Hz)。
广告载荷:快速配对账号数据
广告应包含“服务数据”数据类型,§ 1.11. UUID 应为 0xFE2C
的快速配对服务 UUID。服务数据应包含以下内容:
八位字节 | 数据类型 | 说明 | 值 |
---|---|---|---|
0 | uint8 |
版本和标志 0bVVVVFFFF
|
0x00 (预留以供日后使用) |
1 - 不定 | 账号密钥数据 | 不定 |
账号键数据包含:
八位字节 | 数据类型 | 说明 | 值 |
---|---|---|---|
0 | uint8 |
字段长度和类型 0bLLLLTTTT
|
0bLLLL0000
|
1 - s | 账号密钥过滤条件 | 不定 | |
s + 1 | uint8 |
字段长度和类型 0bLLLLTTTT
|
0b00100001
|
s + 2 - s + 3 | uint16 |
Salt | 不定 |
账号密钥过滤条件
借助所宣传的账号密钥过滤条件,查找方可以在进一步互动之前快速检查提供方是否可能拥有某个账号密钥(假正例概率较低,平均低于 0.5%)。当 Seeker 看到正在广播的过滤条件类型为 0(即显示界面指示)且可能包含其账号密钥之一时,可能会自动连接并尝试启动该过程,以进一步降低误报率。在某些情况下,提供方可能希望被查找方识别,但尚未准备好配对。例如,当耳机放回耳机盒时,我们希望停止显示后续配对通知,因为耳机可能会拒绝该配对。
账号密钥过滤器是一种可变长度的布卢姆过滤器,构建方式如下:
- 设 n 为持久性账号密钥列表中的账号密钥数量(n >= 1)。
- 设 s(过滤器的大小,以字节为单位)为经过截断的 (1.2*n + 3)。例如,如果有 1 个键要持久化,则 s = 4 字节。
uint8_t s = (((uint8_t)(( float )1.2 * n)) + 3);
- 将过滤器 F 初始化为 s 字节的数组,每个字节都设为 0。
uint8_t F[s] = {0};
对于持久化账号密钥列表中的每个账号密钥 K:
a. 设 V 为 concat(K, Salt)。// In the sample code, the size of salt is 2 bytes. #define SALT_SIZE 2 uint8_t V[FASTPAIR_ACCOUNT_KEY_SIZE + SALT_SIZE]; for (uint8_t keyIndex = 0; keyIndex < n; keyIndex++) { // concat (K, Salt) fastpair_get_account_key_by_index(keyIndex, V); uint8_t randomSalt = (uint8_t)rand(); V[FASTPAIR_ACCOUNT_KEY_SIZE] = randomSalt; ... }
b. 使用 SHA256 对 V 进行哈希处理,获取 32 字节的值 H = {H0, …, H31}。
uint8_t H[32] = {0}; SHA256_hash_function(V, H);
c. 将 H 分为八个 4 字节的无符号整数(采用大端序),X = {X0, …, X7},其中 X0 = 0xH0H1H2H3。
uint32_t X[8]; for (index = 0; index < 8; index++) { X[index] = (((uint32_t)(H[index * 4])) << 24) | (((uint32_t)(H[index * 4 + 1])) << 16) | (((uint32_t)(H[index * 4 + 2])) << 8) | (((uint32_t)(H[index * 4 + 3])) << 0); }
d. 对于每个 Xi:
设 M 为 Xi 对过滤器中位数(s * 8)取模。
ii. 获取 F 中索引 (M / 8) 处的字节(向下取整)。
iii. 在字节中,将索引 (M % 8) 对应的位设置为 1。
iv. 换句话说:// M = Xi % (s * 8) // F[M/8] = F[M/8] | (1 << (M % 8)) for (index = 0; index < 8; index++) { uint32_t M = X[index] % (s * 8); F[M / 8] = F[M / 8] | (1 << (M % 8)); }
在广告数据中,将过滤条件 F 添加为“账号键过滤条件”字段。请注意,此值没有“字节序”,因为没有更重要或更不重要的字节,因此请勿更改字节顺序。
盐田
盐是构建布隆过滤器时附加到账号键的随机值。每次为提供商更新 RPA 时,都应重新生成此盐值,以避免跨地址轮替进行跟踪。
如需使用盐生成账号密钥过滤条件,请执行以下操作:
- 生成一个随机的 2 字节 S。请注意,此值没有“字节序”,因为没有更重要或更不重要的字节,因此请勿更改字节顺序。
- 使用 2 字节的 S 作为盐。
- 在所宣传的快速配对账号数据中,在“账号键过滤条件”字段中添加生成的过滤条件,并在“盐”字段中添加 S。