提供方通告信号

通告:可检测到时

当提供方设备处于 BR/EDR 可检测到状态(即配对模式)时,它应通过 BLE 广播快速配对模型 ID 数据,并且 BLE 地址不应轮替。

通告间隔:可检测到时

通告之间的间隔不应大于 100 毫秒 (10Hz)。快速扫描可让 Seeker 快速找到 Provider,即使在低功耗模式下扫描也是如此。

广告载荷:快速配对模型 ID 数据

通告应包含服务数据数据类型(同上),§ 1.11. UUID 应为快速配对服务 UUID 0xFE2C。服务数据应包含以下内容:

八位字节 数据类型 说明 值
0-2 uint24 24 位模型 ID 视情况而定

LE 音频分享广播载荷:快速配对模型 ID 数据和快速配对功能映射

服务数据应包含以下内容:

八位字节 数据类型 说明 值
0 uint8 版本和标志
0bVVVVFFFF
  • V = 版本
  • F = 标志
0x00
1 uint8 字段长度和类型
0bLLLLTTTT
  • L = 模型 ID 的长度(以字节为单位)
  • T = type
0bLLLL0111
  • length = 0bLLLL = 可变
  • type = 0b0111,模型 ID
2 - s 模型 ID 视情况而定
s + 1 uint8 字段长度和类型
0bLLLLTTTT
  • L = 长度(以字节为单位)
  • T = type
0bLLLL1000
s + 2 uint8 指纹功能映射 视情况而定
指纹功能映射

FP 功能映射是一个位图,表示提供程序支持哪些 FP 功能。位图的第一个字节定义如下:

位图 说明
0bRRRRRRSO R - 预留位,目前会被 seeker 忽略,应设置为 0。
S - FP LE 音频分享支持(如果已启用,则设置为 1,否则设置为 0)。
O - 开箱即用 (OOB) 位,如果设备是全新出厂,则设置为 1。

如果提供方支持 FP LE 音频分享规范(即支持临时配对、LE 音频分享通告载荷和可穿戴设备控制版本 2),请将 FP LE 音频分享支持位设置为 1;否则,请将其设置为 0。

如果提供方未与任何 FP 寻觅方配对,并且是出厂新设备(即提供方上没有 FP 账号密钥),请将 OOB 位设置为 1;否则,请将其设置为 0。

协调集信息广告载荷:快速配对模型 ID 数据和 FP 协调集信息

服务数据应包含以下内容:

八位字节 数据类型 说明 值
0 uint8 版本和标志
0bVVVVFFFF
  • V = 版本
  • F = 标志
0x00
1 uint8 字段长度和类型
0bLLLLTTTT
  • L = 模型 ID 的长度(以字节为单位)
  • T = type
0bLLLL0111
  • length = 0bLLLL = 可变
  • type = 0b0111,模型 ID
2 - s 模型 ID 视情况而定
s + 1 uint8 字段长度和类型
0bLLLLTTTT
  • L = 协调集数据的长度
  • T = type
0b01101011
  • length = 0b0110
  • type = 0b1011
s + 2 - s + 7 uint48 FP 协调集数据 6 字节数据,请参阅快速配对协调集信息
FP 协调集信息

FP 协调集信息用于识别广告设备是否在同一协调集中。

八位字节 数据类型 说明 值
0 uint8 协调套装尺寸 不定
1 uint8 快速配对协调集成员类型 可以是以下值之一
  • 0x00:左侧组件
  • 0x01:右侧组件
2 - 5 uint32 设置身份解析密钥哈希 不定

用于生成 Set Identity Resolving Key 的哈希值的算法为

  • 使用 SHA256 对 SIRK 值进行哈希处理

    SIRK = 0xe3b0c44298fc1c149afbf4c8996fb924
    
    SHA256(SIRK) = 0x2646036bb22781536be710245c8cbb04b92842c587f845996ce8ab542592a25e
    
  • 提取前四个字节作为哈希值

    Hash Value of Set Identity Resolving Key = 0x2646036b
    

如需了解设置身份解析密钥,请参阅协调集标识服务。

通告:不可检测到时

当不可检测到(即不处于配对模式)时,提供方设备应按照以下准则通告快速配对账号数据。

通过通告账号数据,附近的 Seekers 可以识别 Provider 何时属于其账号,并启动配对,而无需先强制 Provider 返回配对模式,这是用户投诉的常见原因。如果用户不想与提供方配对,或者广播不相关(例如,如果他们已经配对),则搜索方将为用户提供忽略此广播的机会。 Seeker 还会自动滤除明显错误的广播,例如账号数据配置错误。

通告间隔:不可检测到时

通告之间的间隔时间不应超过 250 毫秒 (4Hz)。

通告载荷:快速配对账号数据

通告应包含服务数据数据类型,同上,§ 1.11. UUID 应为快速配对服务 UUID 0xFE2C。服务数据应包含以下内容:

八位字节 数据类型 说明 值
0 uint8 版本和标志
0bVVVVFFFF
  • V = 版本
  • F = 标志
0x00
(预留以供日后使用)
1 - 各不相同 账号密钥数据 视情况而定

账号密钥数据包含:

八位字节 数据类型 说明 值
0 uint8 字段长度和类型
0bLLLLTTTT
  • L = 账号密钥过滤器的长度(以字节为单位)
  • T = type
0bLLLL0000
  • length = 0bLLLL = 可变
  • type = 0b0000(显示界面指示)或 0b0010(隐藏界面指示),账号密钥过滤器
1 - s 账号密钥过滤条件 视情况而定
s + 1 uint8 字段长度和类型
0bLLLLTTTT
  • L = 长度(以字节为单位)
  • T = type
0b00100001
  • 长度 = 0b0010 = 2
  • type = 0b0001,Salt
s + 2 - s + 3 uint16 Salt 视情况而定

账号密钥过滤条件

通过广播的账号密钥过滤器,Seeker 可以在进一步互动之前快速检查 Provider 是否可能拥有特定账号密钥(假正例概率较低,平均远低于 0.5%)。当 Seeker 看到正在广播的过滤器的类型为 0(即显示界面指示,可能包含其某个账号密钥)时,可能会自动连接并尝试启动该过程,以便进一步降低误报率。在某些情况下,提供方可能希望被发现方识别,但尚未准备好配对。例如,当耳机放回充电盒时,我们希望停止显示后续配对通知,因为该配对可能会被耳机拒绝。

账号密钥过滤器是一个可变长度的布隆过滤器,其构造如下:

  1. 假设 n 是持久化账号密钥列表中的账号密钥数量 (n >= 1)。
  2. 假设 s(过滤条件的大小,以字节为单位)为 (1.2*n + 3) 截断。例如,如果保留 1 个密钥,则 s = 4 字节。
    uint8_t s = (((uint8_t)(( float )1.2 * n)) + 3);
  3. 将过滤器 F 初始化为 s 字节的数组,每个字节都设置为 0。
    uint8_t F[s] = {0};
  4. 对于永久性账号密钥列表中的每个账号密钥 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 划分为 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 为 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 时,都应重新生成此盐,以避免在地址轮替期间进行跟踪。

如需使用盐生成账号密钥过滤器,请执行以下操作:

  1. 生成一个随机的 2 字节 S。请注意,此值没有“字节序”,因为没有更重要或更不重要的字节,请勿更改字节顺序。
  2. 使用 2 字节 S 作为盐。
  3. 在通告的快速配对账号数据中,在“账号密钥过滤器”字段中添加生成的过滤器,并在“盐”字段中添加 S。