快速配对服务

快速配对提供方应实现快速配对服务 (UUID 0xFE2C),该服务包含以下特征。

名称 已加密 权限 UUID 是否强制?
模型 ID 否 读取 FE2C1233-8366-4814-8EB0-01DE32100BEA 强制
基于密钥的配对 否 写入和通知 FE2C1234-8366-4814-8EB0-01DE32100BEA 强制
通行密钥 否 写入和通知 FE2C1235-8366-4814-8EB0-01DE32100BEA 强制
账号密钥 否 写入 FE2C1236-8366-4814-8EB0-01DE32100BEA 强制
附加数据 否 写入和通知 FE2C1237-8366-4814-8EB0-01DE32100BEA *C1
消息流 PSM 是 读取 FE2C1239-8366-4814-8EB0-01DE32100BEA *C2
其他通行密钥 否 读取、写入和通知 FE2C123A-8366-4814-8EB0-01DE32100BEA *C3
FP 设备操作 否 写入和通知 FE2C123B-8366-4814-8EB0-01DE32100BEA *C4

有条件强制

特征:模型 ID

此特征允许 Seeker 在需要时读取模型 ID,而无需等到设备在可检测模式下通告。它应始终返回以下数据:

八位字节 数据类型 说明 值
0 - 2 uint24 模型 ID 不定

特征:基于密钥的配对

此特征控制基于密钥的配对过程。在此过程中,通过验证搜索者和提供者是否都拥有预共享密钥,建立了一定程度的信任。每种情况下的密钥都不同:

  • 情况 1:预共享密钥基于防欺骗公钥/私钥对以及 Seeker 自己的公钥/私钥对,后者会在每次配对尝试时发生变化。

    • 提供方处于配对模式。
    • Seeker 会验证 Provider 是否拥有防欺骗私钥。

    请注意,在配对模式下,提供方当然也可以采用常规方式进行配对,例如与不支持“快速配对”基于密钥的配对功能的设备进行配对。

  • 情况 2:预共享密钥是账号密钥之一。

    • 提供方通常不处于配对模式。(但这不是一项要求,提供方应支持在配对模式下使用账号密钥。)
    • Seeker 和 Provider 各自验证对方是否拥有账号密钥。

由于这两种情况非常相似,只是使用的预共享密钥不同,因此它们在过程中合并。

数据格式

如需了解每种格式的使用方法,请参阅过程。

八位字节 数据类型 说明 值 是否强制?
0 - 15 uint128 加密请求 不定 强制
16 - 79 公钥 不定 可选

表 1.1:由 Seeker 写入特征的加密请求。

八位字节 数据类型 说明 值 是否强制?
0 uint8 消息类型 0x00 = 基于密钥的配对请求 强制
1 uint8 标志
  • 位 0 (MSB):已弃用,且会被 Seeker 忽略。
  • 第 1 位:如果 Seeker 请求 Provider 发起绑定,并且此请求包含 Seeker 的 BR/EDR 地址,则为 1。否则为 0。
  • 第 2 位:如果 Seeker 请求 Provider 应通知现有名称,则为 1。否则为 0。
  • 第 3 位:如果此项用于追溯写入账号密钥,则为 1。否则为 0。
  • 第 4 位:如果 Seeker 支持 BLE 设备,则为 1。否则为 0。
  • 位 5:如果 Seeker 支持 LE 音频,则为 1。否则为 0。
  • 位 6 - 7 预留以供日后使用,应忽略。
视情况而定 强制
2 - 7 uint48 请执行以下任一操作:
  • 提供方的当前 BLE 地址
  • 提供商的身份地址
视情况而定 强制
8 - 13 uint48 Seeker 的 BR/EDR 地址 视情况而定 仅在设置了标志位 1 或 3 时显示
n - 15 随机值(盐) 视情况而定 强制

表 1.2.1:原始请求(类型 0x00)。从表 1.1中的加密请求解密。

八位字节 数据类型 说明 值 是否强制?
0 uint8 消息类型 0x10 = 操作请求 强制
1 uint8 标志 视情况而定 强制
2 - 7 uint48 请执行以下任一操作:
  • 提供方的当前 BLE 地址
  • 提供商的身份地址
视情况而定 强制
8 uint8 发起群聊 视情况而定 如果设置了标志位 0,则为必填项
9 uint8 消息代码 视情况而定 如果设置了标志位 0,则为必填项
10 uint8 取决于标志:
  • 位 0 已设置:附加数据长度,小于 6
  • 设置了第 1 位:数据 ID
视情况而定 如果设置了标志位 0 或 1,则为必填
11 - n 附加数据 视情况而定 可选
n - 15 随机值(盐) 视情况而定 强制

表 1.2.2:原始请求(类型 0x10)。从表 1.1中的加密请求解密。

八位字节 数据类型 说明 值
0 uint8 消息类型 0x01 = 基于密钥的配对响应
1 - 6 uint48 提供方的公共 (BR/EDR) 地址 视情况而定
7 - 15 随机值(盐) 视情况而定

表 1.3:原始响应(类型 0x01)。经过加密,生成表 1.4 中的加密响应。

八位字节 数据类型 说明 值
0 uint8 消息类型 0x02 = Key-based Pairing Extended Response
1 uint8 标志
  • 位 0 (MSB):如果提供方是仅支持 LE 的设备,则为 1;否则为 0。如果位 0 设为 1,则 Seeker 会假定位 1 设为 1。
  • 位 1:如果提供方更倾向于 LE 绑定,则为 1,否则为 0。
  • 位 2:如果第二个地址的地址类型为“随机”,则为 1;如果为“公开”,则为 0。
  • 位 3 - 7 预留以供日后使用,应忽略。
视情况而定
2 uint8 提供商地址的数量
有效值为 1 和 2。
视情况而定
3 - 8 或
3 - 14
  • 第一个地址应为主设备的身份地址,如果首选 BR/EDR 绑定,则应为可绑定地址
  • 如果辅助地址可用,则第二个地址应为辅助地址的可绑定地址
视情况而定
9 - 15 或 15 随机值(盐) 视情况而定

表 1.3.2:原始响应(类型 0x02)。经过加密,生成表 1.4 中的加密响应。

八位字节 数据类型 说明 值
0 -15 uint128 加密响应 视情况而定

表 1.4:提供程序通过通知发送给 Seek 程序的加密响应。

特征:通行密钥

此特征在基于密钥的配对过程中使用。

八位字节 数据类型 说明 值
0 - 15 uint128 已加密的通行密钥块 视情况而定

表 2.1:加密的通行密钥块。如需了解用法,请参阅“基于密钥的配对”过程。

八位字节 数据类型 说明 值
0 uint8 消息类型 以下之一:
  • 0x02 = 搜索者的通行密钥
  • 0x03 = 提供方的通行密钥
1 - 3 unit32 6 位数通行密钥 视情况而定
4 - 15 随机值(盐) 视情况而定

表 2.2:原始通行密钥块。表 2.1 的解密版本。

特征:账号密钥

配对后,快速配对搜索器会将账号密钥写入快速配对提供器。

八位字节 数据类型 说明 值
0 - 15 uint128 账号密钥(已加密) 视情况而定

收到写入请求后,快速配对提供方应执行以下操作:

  1. 使用过程第 4 步中生成的共享密钥解密账号密钥。
    • 对于需要提供保证金的提供商(常见):
      • 在解密之前,请验证共享密钥是否已用于解密第 12 步中的通行密钥请求。如果此步骤未使用此密钥通过,请忽略此写入并退出。
    • 此时,共享密钥(过程中的 K)将不会再用于此配对。在不重启该过程的情况下,任何使用此密钥加密的传入请求都应被拒绝。
  2. 验证解密后的值是否以 0x04 或 0xFF 开头。如果不是,请忽略此写入并退出。
    • 如果值为 0x04:
      • 检查持久化的账号密钥列表是否有空间容纳新值。
      • 如果未找到,则从列表中删除最近最不常用的值。
      • 将新值添加到列表中。
    • 如果值为 0xFF:
      • 将此视为临时配对会话,不执行任何操作。
      • 追溯性写入账号密钥流程可能会出现这种情况。
      • 请勿存储该密钥,也不要在账号密钥列表、加密或 MAC 计算中使用该密钥。
      • 绑定移除由特定于功能的事件或超时触发。对于 LE 音频分享,强烈建议在临时会话断开连接 10 分钟后移除 BLE 绑定和链接密钥。

列表中的账号密钥会在基于密钥的配对期间使用。

特征:其他数据

此服务应具有以下特征。

快速配对服务特征 已加密 权限 UUID
数据 否 写入和通知 FE2C1237-8366-4814-8EB0-01DE32100BEA
旧版快速配对服务特征(目标是在 2021 年 1 月 1 日弃用) 已加密 权限 UUID
数据 否 写入和通知 0x1237

在写入或通知此特征之前,必须通过特征 FE2C1234-8366-4814-8EB0-01DE32100BEA 进行握手,以获得共享密钥。AES-CTR 将用于加密流经此特征的数据,其算法定义如下。对于超出单个 16 字节块的数据,此模式更安全。HMAC-SHA256 将用于确保数据完整性,其定义如下。

八位字节 说明 值
0 - 7 HMAC-SHA256 的前 8 个字节。 视情况而定
8 - 15 Nonce,由 AES-CTR 加密使用。 视情况而定
16 - var 加密数据。 视情况而定

表 3.1:数据包,由提供方通过通知发送给寻觅方,或由寻觅方通过写入发送给提供方。

八位字节 数据类型 说明 值
0 - var byte array 数据 varies,根据表 1.2.2 的数据 ID 进行解码:
  • 0x01(个性化名称):utf8s

表 3.2:原始数据。从表 3.1 中的加密数据解密。

当请求通知时(例如,通过表 1.2.1 中的第 2 位请求个性化名称),快速配对提供方应执行以下操作:

  1. 为 Nonce 生成加密随机 8 字节。
  2. 使用 AES-CTR 加密数据,其中每个 16 字节块都是使用

    encryptedBlock[i] = clearBlock[i] ^ AES(key, concat((uint8) i, 0x00000000000000, nonce))
    

    其中

    1. AES 密钥是过程第 4 步中的共享密钥。
    2. clearBlock[i] 是从 data[i * 16] 开始的 16 字节块。最后一个块可以小于 16 字节。
  3. 执行 concat(encryptedBlock[0], encryptedBlock[1],…) 以创建加密数据。

  4. 通过以下方式生成 HMAC-SHA256

    sha256(concat((K ^ opad), sha256(concat((K ^ ipad), concat(nonce, encrypted_data)))))
    

    其中

    1. K 由 concat(shared_secret, 48-byte ZEROs) 生成,shared_secret 来自过程中的第 4 步。
    2. opad 是 64 字节的外部填充,由值为 0x5C 的重复字节组成。
    3. ipad 是 64 字节的内部填充,由值为 0x36 的重复字节组成。
  5. 从 HMAC-SHA256 中提取前 8 个字节作为数据包的前缀。

收到写入请求后,快速配对提供方应执行以下操作:

  1. 通过检查 HMAC-SHA256 的前 8 个字节来验证数据的完整性。
  2. 使用 AES-CTR 解密加密数据,其中每个块都是使用以下算法生成的:

    clearBlock[i] = encryptedBlock[i] ^ AES(key, concat((uint8) i, 0x00000000000000, nonce))
    

    其中

    1. encryptedBlock[i] 是从 encrypted_data[i * 16] 开始的 16 字节块。 最后一个块可以小于 16 字节。
    2. AES 密钥通过握手生成或识别,例如:
      1. 在命名流程 1 中,它来自 ECDH,并且不会在此配对中再次使用。任何使用此密钥加密且未重启该过程的请求都应被拒绝。
      2. 在命名流程 2 中,它是账号密钥。
  3. 执行 concat(clearBlock[0], clearBlock[1],…) 以创建原始数据。

特征:消息流 PSM

请参阅 BLE 设备:消息流 PSM

特征:其他通行密钥

请参阅 BLE 设备:其他通行密钥

特征:FP 设备操作

快速配对服务特征 已加密 权限 UUID
FP 设备操作 否 写入和通知 FE2C123B-8366-4814-8EB0-01DE32100BEA

八位字节 说明 值
0 - 7 HMAC-SHA256 的前 8 个字节。 视情况而定
8 - 15 Nonce,由 AES-CTR 加密使用。 视情况而定
16 - var 加密数据。 视情况而定

表 4.1:数据包,由提供方作为通知发送给 Seek 方,或由 Seek 方作为写入发送给提供方。

八位字节 数据类型 说明 值
0 - var byte array 操作请求 以下密钥之一:
  • 读取个性化名称,0x01
  • 写入个性化名称,请参阅表 4.3.1
  • 读取协调集信息,0x02
  • 读取设备功能,0x03

表 4.2:原始数据。表 4.1 中由 seeker 发送给 provider 的加密数据解密而来,作为写入操作。

八位字节 数据类型 说明 值
0 - var byte array 操作响应 以下密钥之一:
  • 个性化名称,请参阅表 4.3.1
  • 协调集信息,请参阅表 4.3.2
  • 设备功能,请参阅表 4.3.3
  • 错误代码
    • 0x80(请求不受支持)
    • 0x81(请求无效)

表 4.3:原始数据。从提供方作为通知发送给搜索方的表 4.1 中的加密数据解密。

八位字节 数据类型 说明 值
0 uint8 操作 ID 0x01
1 - var utf8s 个性化名称 不定

表 4.3.1:个性化名称格式

八位字节 数据类型 说明 值
0 uint8 操作 ID 0x02
1 uint8 快速配对协调集成员类型
  • 0x00:左侧组件
  • 0x01:右侧组件
2 uint8 协调套装尺寸 组件数量
3 uint8 设置身份解析密钥类型 0x01(明文 SIRK)
4 - 19 uint128 设置身份解析键值对 16 字节数据,请参阅协调集标识服务

表 4.3.2:协调集信息格式

八位字节 数据类型 说明 值
0 uint8 操作 ID 0x03
1 - 2 uint16 设备功能
  • 位 0 - 15:预留,应设为 0

表 4.3.3:设备功能格式

快速配对操作

为此特征定义了两个主要操作

  • 快速配对读取:从提供程序读取数据
    1. Seeker:启用 GATT 通知
    2. 提供方:已注册 GATT 通知
    3. Seeker:GATT 写入请求,原始数据仅包含 Action ID
    4. 提供方:GATT 写入响应
    5. 提供方:GATT 通知,原始数据包含
      • 操作 ID
      • 操作 ID 的数据
    6. Seeker:收到 GATT 通知
  • 快速配对写入:向提供方写入数据
    1. Seeker:GATT 写入请求,原始数据包含
      • 操作 ID
      • 操作 ID 的数据
    2. 提供方:GATT 写入响应

快速配对读取支持的操作 ID

  • 0x01(个性化名称)
  • 0x02(协调集信息)
  • 0x03(设备功能)

快速配对写入支持的操作 ID

如果提供方无法理解操作 ID,则会使用包含“不支持的请求”(0x80) 的 GATT 通知进行响应,如表 4.3 中所述。

加密算法

当收到通知请求时,快速配对提供方应执行以下操作:

  1. 为 Nonce 生成加密随机 8 字节。
  2. 使用 AES-CTR 加密数据,其中每个 16 字节块都是使用

    encryptedBlock[i] = clearBlock[i] ^ AES(key, concat((uint8) i, 0x00000000000000, nonce))
    

    其中

    1. AES 密钥是过程第 4 步中的共享密钥。
    2. clearBlock[i] 是从 data[i * 16] 开始的 16 字节块。最后一个块可以小于 16 字节。
  3. 执行 concat(encryptedBlock[0], encryptedBlock[1],...) 以创建加密数据。

  4. 通过以下方式生成 HMAC-SHA256

    sha256(concat((K ^ opad), sha256(concat((K ^ ipad), concat(nonce, encrypted_data)))))
    

    其中

    1. K 由 concat(shared_secret, 48-byte ZEROs) 生成,shared_secret 来自过程中的第 4 步。
    2. opad 是 64 字节的外部填充,由值为 0x5C 的重复字节组成。
    3. ipad 是 64 字节的内部填充,由值为 0x36 的重复字节组成。
  5. 从 HMAC-SHA256 中提取前 8 个字节作为数据包的前缀。

收到写入请求后,快速配对提供方应执行以下操作:

  1. 通过检查 HMAC-SHA256 的前 8 个字节来验证数据的完整性。
  2. 使用 AES-CTR 解密加密数据,其中每个块都是使用以下算法生成的:

    clearBlock[i] = encryptedBlock[i] ^ AES(key, concat((uint8) i, 0x00000000000000, nonce))
    

    其中

    1. encryptedBlock[i] 是从 encrypted_data[i * 16] 开始的 16 字节块。最后一个块可以小于 16 字节。
    2. AES 密钥通过握手生成或识别,例如:
      1. 在命名流程 1 中,它来自 ECDH,并且不会在此配对中再次使用。任何使用此密钥加密且未重启该过程的请求都应被拒绝。
      2. 在命名流程 2 中,它是账号密钥。
  3. 执行 concat(clearBlock[0], clearBlock[1],...) 以创建原始数据。

设备信息服务

快速配对提供方还应支持设备信息服务 (UUID 0x180A)。快速配对搜索方使用以下特征。

名称 已加密 权限 UUID
固件修订版本 否 读取 0x2A26

特征:固件修订版本

此特征允许 Seekers 根据需要读取 Providers 的固件修订版本。它应始终返回以下数据:

八位字节 数据类型 说明 值
0 - var utf8s 固件修订代码 视情况而定

即使提供方上有多个固件(例如,左耳机、右耳机和充电盒各有 1 个固件,共 3 个固件),也应将其封装到单个 utf8 字符串中。 提供程序还可以针对特殊情况返回特定字符串:

  1. status-updating:如果提供方正在更新到新固件。 或者,提供方可以返回暂存固件的版本。

  2. status-abnormal:如果提供方处于异常状态。例如,由于固件更新失败,设备出现故障。此值会导致 Seeker 显示一条消息,让用户知道现在必须更新。

提供者应限制对固件修订版本特征的访问,以防止设备跟踪。建议的限制:

  • 已绑定的设备应随时可以访问
  • 当提供方可被检测到时,任何设备都应有权访问

如果提供方支持“查找中心”,则需要进行额外的实现。如需了解详情,请参阅“查找中心”固件更新。