提供商广告信号
广告:可发现时
当提供程序设备是 BR/EDR 可发现(即处于配对模式)时,应通过 BLE 通告快速配对模型 ID 数据,并且 BLE 地址不应轮替。
广告间隔:可检测时
广告之间的时间间隔不应超过 100 毫秒 (10Hz)。快速速率可让 Seek 快速找到 Provider,即使在低功耗模式下扫描时也是如此。
广告载荷:快速配对模型 ID 数据
通告应包含服务数据类型 ibid。第 1.11 条。UUID 应该是 0xFE2C
的快速配对服务 UUID。服务数据应包含以下内容:
八位字节 | 数据类型 | 说明 | 值 |
---|---|---|---|
0 - 2 年 | uint24 |
24 位型号 ID | 不尽相同 |
广告:无法发现时
如果无法发现(即未处于配对模式),提供方设备应按照以下准则宣传快速配对帐号数据。
通过通告帐号数据,附近的搜索者能够识别提供商属于其帐号的情况并启动配对,而不必先强制提供商重新进入配对模式,这是导致用户投诉的常见原因。观看者可以在不等待与提供方配对或广播不相关(例如,已配对)的情况下忽略此广播的机会。跳转程序还会自动过滤掉明显不良的广播,例如在帐号数据配置错误时。
广告间隔:当无法检测到时
广告之间的时间间隔不得超过 250 毫秒 (4Hz)。
广告载荷:快速配对帐号数据
广告应包含服务数据类型“Ibid”。第 1.11 条。UUID 应该是 0xFE2C
的快速配对服务 UUID。服务数据应包含以下内容:
八位字节 | 数据类型 | 说明 | 值 |
---|---|---|---|
0 | uint8 |
版本和标志 0bVVVFFFF
|
0x00 (预留以供日后使用) |
1 - 不尽相同 | 帐号密钥数据 | 不相同 或 0x00 (如果帐号密钥列表为空) |
帐号密钥数据包含:
八位字节 | 数据类型 | 说明 | 值 |
---|---|---|---|
0 | uint8 |
字段长度和类型 0bLLLLTTTT
|
0bLLLL0000
|
1 - s | 帐号密钥过滤器 | 不尽相同 | |
s + 1 | uint8 |
字段长度和类型 0bLLLLTTTT
|
0b00100001
|
s + 2 - s + 3 | uint16 |
Salt | 不尽相同 |
帐号密钥过滤器
借助通告式帐号密钥过滤器,跳转者可在进一步互动之前快速检查提供商是否可能拥有某个帐号密钥(误报概率较低,平均远低于 0.5%)。当发现正在广播某个类型为 0 的过滤条件(即显示界面指示)时,还原器可能会自动连接并尝试启动该流程,该扩展可能会包含它的某个帐号键,以便进一步降低误报率。在某些情况下,提供方可能希望在未做好配对准备时由 Seek 识别。例如,耳机重新回到耳机充电盒之前,我们希望停止显示后续配对通知,因为耳机可能会拒绝配对。
帐号密钥过滤器是一个长度可变的布洛姆过滤器,其构造如下:
- 让 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 表示串联(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 除以 8 个 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:
i. 以 M 为 X 取模中位数的模数 (s * 8)。
ii. 获取索引 (M/8) 中的 F 字节,向下舍入。
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 作为“帐号密钥过滤条件”字段。 请注意,该值没有“字节顺序”,因为有效字节已大于或等于多少,因此请勿更改字节顺序。
盐场
盐是构建 Bloom 过滤器时附加到帐号密钥的随机值。每当提供商更新 RPA 时,都应重新生成此盐,以避免跨地址轮替进行跟踪。
要使用盐生成帐号密钥过滤器,请执行以下操作:
- 生成一个随机的 2 字节 S。请注意,该值没有“字节顺序”,因为不存在明显或较少的字节 - 请勿更改字节顺序。
- 将 2 字节的 S 用作盐。
- 在所宣传的快速配对帐号数据中,在“帐号密钥过滤器”字段中添加生成的过滤器,并在“盐”字段中添加 S。