GAP Bond Manager 和 LE 安全连接

ble 2024-06-18 943 次浏览 次点赞


GAP Bond Manager 和 LE 安全连接

GAP Bond Manager (GAPBondMgr) 是一个可配置模块,用于从应用程序中承担大部分与安全管理器 (SM) 协议相关的配对和绑定安全机制。GAPBondMgr 在协议栈任务的上下文中执行。

术语描述
配对 (Pairing)生成和交换密钥的过程。不要与建立两个设备之间的 BLE 连接混淆。
加密 (Encryption)配对后或重新连接时加密数据。
关联 (Association)基于设备的 I/O 能力选择的配对方法。支持 Just Works、数字比较、密码输入和带外 (OOB) 配对。
认证 (Authentication)使用支持 MITM 保护的关联方法进行的配对过程。
绑定 (Bonding)将配对过程中生成的密钥存储在非易失性内存中,以用于下次加密。
授权 (Authorization)除了认证之外的附加应用级别验证。
OOB (Out of Band)配对密钥不是通过 RF 交换,而是通过串口或 NFC 等其他方式交换。这也提供了 MITM 保护。
MITM (Man in the Middle)中间人攻击保护。在配对过程中提供认证,防止恶意攻击者在密钥交换期间冒充对等设备。
Just Works无认证的配对关联方法,密钥交换不受 MITM 保护。
  1. 配对过程:通过 配对方法选择 中描述的方法交换密钥。
  2. 加密过程:使用步骤 1 中的密钥加密链路。
  3. 绑定过程:将密钥存储在安全闪存 (Simple Non Volatile memory, SNV) 中。
  4. 重新连接:使用存储在 SNV 中的密钥加密链路。

配对方法选择

蓝牙核心规范版本 4.2 添加了支持 LE Secure Connections 的功能,以增强 BLE 配对过程的强度。详细描述请参见 Bluetooth Core Specification Version 5.1Security Architecture 部分 ([Vol 1], Part A, Section 5.1)。以前版本 (4.1 和 4.0) 使用的方法定义为 LE Legacy Pairing。主要区别在于 Secure Connection 使用椭圆曲线 Diffie-Hellman (ECDH) 密码术,而 LE Legacy Pairing 则不使用。

以下是核心规范中定义的四种配对方法,每种配对方法在 不同配对方法的 GAPBondMgr 示例 中有详细描述。

  • Just Works (LE Secure Connections 或 LE Legacy)
  • 密码输入 (Passkey Entry, LE Secure Connections 或 LE Legacy)
  • 数字比较 (Numeric Comparison, LE Secure Connections)
  • 带外 (Out Of Band, LE Secure Connections 或 LE Legacy)

配对方法的选择以及配对是否成功取决于配对过程中双方设备的以下参数:

  • 带外 (OOB) 设置 / 未设置
  • 中间人攻击保护 (MITM) 设置 / 未设置
  • 输入/输出 (IO) 能力
  • 支持 / 不支持 LE 安全连接

GAPBondMgr 参数与以下参数相对应,详情请参见 BLE Stack API 参考 (GAPBondMgr 部分)。

超出 Bluetooth Core Specification Version 5.1 定义的内容,本参数还会影响配对是否成功,详情参见 BLE Stack API 参考 (GAPBondMgr 部分)。

以下是从 Bluetooth Core Specification Version 5.1Selecting Key Generation Method 部分 ([Vol 3], Part H, Section 2.3.5.1) 中的表格。使用这些表格确定任何参数组合下选择的配对模式。

如果两台设备都支持 LE 安全连接,请使用 Figure 83 确定下一步。

Figure 83

图 83. 当两台设备都支持 LE 安全连接时的 GAPBondMgr 参数。

如果至少有一台设备 支持 LE 安全连接,请使用 Figure 84 确定下一步。

Figure 84

图 84. 当一台或两台设备不支持 LE Secure Connections 时的 GAPBondMgr 参数。

如果基于上述表格,IO 能力被用于确定关联模型,请使用以下图表。

Figure 85

图 85. 具有 IO 能力的 GAPBondMgr 参数。

使用 GAPBondMgr

本节描述了应用程序必须执行的配置、启动和使用 GAPBondMgr 的步骤。GAPBondMgr 定义在 gapbondmgr.cgapbondmgr.h 中。完整的 API 包括命令、可配置参数、事件和回调,详情请参见 BLE Stack API Reference (GAPBondMgr 部分)。

使用 GAPBondMgr 模块的一般步骤如下:

  1. 在协议栈项目的 build_config.opt 中定义以下内容,以包含 GAPBondMgr 功能:

    -DGAP_BOND_MGR
  2. 如果使用 LE Secure Connections,PDU 大小必须 >= 69。可以通过在应用项目中定义以下预处理符号来设置:MAX_PDU_SIZE=69。另外,LE Secure Connections 可用的最小堆大小为 3690。详见 Dynamic Memory Allocation
  3. 通过初始化所需的参数来配置 GAPBondMgr。GAPBondMgr 配置参数不是持久性的,设备重置后必须重新配置。详见 BLE Stack API Reference (GAPBondMgr 部分)。有关各种配对/绑定模式的示例,请参见 GAPBondMgr Examples for Different Pairing Methods
  4. 使用 GAPBondMgr 注册应用回调,以便应用程序可以与 GAPBondMgr 通信并接收事件通知。

    // 在启动设备后向 Bond Manager 注册
    GAPBondMgr_Register(&bondmanager_callbacks);

    这里的 bondmanager_callbacks 定义为包含 GAPBondMgr 回调的结构体。一个密码回调函数是必须的。

    // Bond Manager 回调
    static gapBondCBs_t bondMgrCBs =
    {
      SimpleCentral_passcodeCb, // 密码回调
      SimpleCentral_pairStateCb // 配对/绑定状态回调
    };
  5. 一旦 GAPBondMgr 配置完成,从应用程序的角度来看,它主要是自主运行的。当建立连接时,GAPBondMgr 根据初始化期间设置的配置参数管理配对和绑定。它还通过定义的回调与应用程序进行通信。

    可以随时异步设置一些参数并调用函数,详见 BLE Stack API Reference (GAPBondMgr 部分)。

    大部分 GAPBondMgr 和应用程序之间的通信此时通过在步骤 4 中注册的回调进行。图 86 是 GAPBondMgr 通知应用程序配对完成的流程图示例。其他各种事件的流程也类似,后续部分将详细说明。

    Figure 86

    图 86. GAPBondMgr 回调示例。

不同配对方法的 GAPBondMgr 示例

本节提供了可以实现的安全类型的消息图示。这些模式假设存在合适的 I/O 能力,并且是否支持 LE Secure Connections 允许配对方法。详见 配对方法选择 了解这些参数如何影响配对。这些示例仅考虑配对方面。绑定可以添加到每种配对类型中,并在下一节中展示。

注意此处的代码片段不是完整的功能示例,仅用于说明目的。

禁用配对

将配对模式设置为 GAPBOND_PAIRING_MODE_NO_PAIRING 时,BLE 栈会自动拒绝任何配对尝试。按如下方式配置 GAPBondMgr 以禁用配对:

// 禁用配对
uint8_t pairMode = GAPBOND_PAIRING_MODE_NO_PAIRING;
GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);

启用配对

在形成连接后开始或允许配对过程,GAPBondMgr 可以配置为自动请求配对或等待对等设备的配对请求。实际行为取决于设备的 GAP 角色(Central 或 Peripheral)和 GAPBondMgr 配对模式 (GAPBOND_PAIRING_MODE) 的设置。

在 Peripheral 角色设备上启动配对过程时,GAPBOND_PAIRING_MODE_INITIATE 会在 GAPBondMgr 知道连接已形成后不久发送 Slave Security Request。对于 Central 角色设备,GAPBOND_PAIRING_MODE_INITIATE 会发送配对请求或请求 Link Layer 加密链路(如果设备之前已配对/绑定):

// 启动配对请求
uint8_t pairMode = GAPBOND_PAIRING_MODE_INITIATE;
GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);

Peripheral 可以配置为在配对模式设置为 GAPBOND_PAIRING_MODE_WAIT_FOR_REQ 时等待 Central 的 配对请求。选择此配对模式时,GAPBondMgr 会根据其他配置参数自动响应 配对响应

// 等待配对请求
uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
提示:当与智能手机 Central 设备配对时,建议使用 GAPBOND_PAIRING_MODE_WAIT_FOR_REQ,因为当 Peripheral 发送 Slave Security Request 时可能会出现未定义行为。当访问 GATT 安全特性时,iOS 和 Android 都会在 Peripheral 响应 身份验证不足 错误响应时启动配对。

LE Secure Connections

LE Secure Connections 在 BLE5-Stack 中默认启用。如果不想使用 LE Secure Connections,请在 GAPBondMgr 初始化期间将 GAPBOND_SECURE_CONNECTION 变量设置为 GAPBOND_SECURE_CONNECTION_NONE

uint8_t gapbondSecure = GAPBOND_SECURE_CONNECTION_NONE;
GAPBondMgr_SetParameter(GAPBOND_SECURE_CONNECTION, sizeof(uint8_t), &gapbondSecure);

在使用 LE Secure Connections 时解读空中嗅探器日志时,需使用 Bluetooth Core Specification Version 5.1 Vol 3 Part H 第 2.3.5.6.1 节中定义的特定“调试”密钥。在 BLE5-Stack 中,可以通过 SysConfig 启用该密钥,选中 BLE,Bond Manager 下的 'ECC Debug Keys'。当启动设备或非启动设备使用此特定调试密钥时,支持 LE Secure Connections 的空中嗅探器设备可以确定 LTK,从而监控/解密整个连接中的加密通信。

LESC 限制和建议

LE Secure Connections 使用 ECDH 公私钥对作为配对过程的一部分。详见 配对方法选择Bluetooth Core Specification Version 5.1 的 LE Secure Connections 配对第二阶段。

简而言之,在 LESC 配对的第一阶段,每个设备会生成自己的 ECDH 公私钥对。在第二阶段,每个设备将根据交换的公钥计算 Diffie-Hellman (DH) 密钥。

ECC 公私钥和 DH 密钥生成由 CC13x2 或 CC26x2 上的私钥加速器 (PKA) 的 ECDH TI-RTOS 驱动实现。这些操作是 阻塞 的,需要约 136.5ms 执行。在 LESC 配对过程中,链接层 (LL) 会两次访问 ECDH 驱动程序,一次生成公私钥对,一次生成 DH 密钥。这意味着堆栈 OSAL 任务将在配对过程中两次阻塞约 136.5ms。然而,用户应用程序任务在此期间仍然可以运行。

因此,TI 建议在使用 LESC 时遵循以下建议:

  • 监督超时时间 >= 140ms

为减少所需的阻塞时间,用户应用程序可以在配对过程之前生成公私钥对,或定义何时回收密钥,使用以下 GapBondMgr 参数。这些选项是互斥的,因为应用程序生成密钥会绕过回收参数。要真正最小化 ECC 对 BLE 连接的影响,请在建立任何连接之前执行 ECC。

Just Works 配对

Just Works 配对允许加密而无需中间人 (MITM) 认证,因此易受 MITM 攻击。Just Works 配对可以是 LE Legacy 或 LE Secure Connections 配对。对于 Just Works 配对,GAPBondMgr 不需要应用程序的额外输入。如下配置 GAPBondMgr 进行 Just Works 配对:

uint8_t mitm = FALSE;
GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);

图 87 描述了 GAPBondMgr 和应用程序在 Just Works 配对中的交互。应用程序在发送配对请求后会收到 GAPBOND_PAIRING_STATE_STARTED 事件,在配对过程完成后会收到 GAPBOND_PAIRING_STATE_COMPLETE 事件。此时,链路已加密。

Figure 87

图 87. Just Works 配对。

Passcode Entry

密码输入是一种认证配对方式,可以防止 MITM 攻击。它可以与 LE Legacy 配对或 Secure Connections 配对一起使用。在这种配对方法中,一个设备显示 6 位数密码,另一个设备输入密码。详见 配对方法选择,IO 能力决定哪个设备执行哪个角色。启动 GAPBondMgr 时注册的密码回调用于输入或显示密码。以下是启动密码输入配对的示例,其中密码被显示。

  1. 定义密码回调

    // Bond Manager 回调
    static gapBondCBs_t bondMgrCBs =
    {
      SimpleCentral_passcodeCb, // 密码回调
      SimpleCentral_pairStateCb // 配对/绑定状态回调
    };
    static void SimpleCentral_passcodeCb(uint8_t *deviceAddr, uint16_t connHandle,
                                         uint8_t uiInputs, uint8_t uiOutputs,
                                         uint32_t numComparison)
    {
      uint8_t *pData;
    
      // 为密码事件分配空间。
      if ((pData = ICall_malloc(sizeof(uint8_t))))
      {
        *pData = uiOutputs;
    
        // 排队事件。
        SimpleCentral_enqueueMsg(SC_EVT_PASSCODE_NEEDED, 0, pData);
      }
    }
  2. 配置 GAPBondMgr

    uint8_t pairMode = GAPBOND_PAIRING_MODE_INITIATE;
    uint8_t mitm = TRUE;
    GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
    GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
  3. 处理密码回调并发送响应到栈。

    //! BLE 默认密码
    #define B_APP_DEFAULT_PASSCODE 123456
    
    static void SimpleCentral_processPasscode(uint16_t connHandle,
                                              uint8_t uiOutputs)
    {
      // 向用户显示密码
      if (uiOutputs != 0)
      {
        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Passcode: %d",
                       B_APP_DEFAULT_PASSCODE);
      }
    
      // 发送密码响应
      GAPBondMgr_PasscodeRsp(connHandle, SUCCESS, B_APP_DEFAULT_PASSCODE);
    }

    根据从 GAPBondMgr 返回的 uiInputsuiOutputs,密码必须显示或输入。然后将密码发送到 GAPBondMgr 以继续配对。在此情况下,密码静态设置为 123456。在实际产品中,密码可能是随机生成的,设备必须提供一种方式让用户输入密码,然后将其发送到 GAPBondMgr。GAPBondMgr 和应用程序之间的交互如图 88 所示。

    Figure 88

居中示例

Numeric Comparison

数字比较是一种认证配对方式,可以防止中间人 (MITM) 攻击。它仅作为 LE Secure Connections 配对方式;不适用于 LE Legacy。在数字比较配对中,两个设备都会显示一个 6 位数的代码。每个设备然后通过按钮按压或其他 Yes-No 输入确认代码是否匹配。启动 GAPBondMgr 时注册的密码回调用于显示 6 位数的代码。以下是启动数字比较配对的示例,其中显示了密码。IO 能力必须设置为显示/Yes-No 才能选择数字比较(即两边都是显示/Yes-No)。

  1. 定义密码回调以显示代码。

    // Bond Manager 回调
    static gapBondCBs_t bondMgrCBs =
    {
      SimpleCentral_passcodeCb, // 密码回调
      SimpleCentral_pairStateCb // 配对/绑定状态回调
    };
    
    static void SimpleCentral_passcodeCb(uint8_t *deviceAddr, uint16_t connHandle, uint8_t uiInputs, uint8_t uiOutputs, uint32_t numComparison)
    {
      gapPasskeyNeededEvent_t *pData;
    
      // 为密码事件分配空间。
      if ((pData = ICall_malloc(sizeof(gapPasskeyNeededEvent_t))))
      {
        memcpy(pData->deviceAddr, deviceAddr, B_ADDR_LEN);
        pData->connectionHandle = connHandle;
        pData->numComparison = numComparison;
    
        // 排队事件。
        SimpleCentral_enqueueMsg(SC_EVT_PASSCODE_NEEDED, 0, pData);
      }
    }
  2. 配置 GAPBondMgr

    uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
    uint8_t scMode = GAPBOND_SECURE_CONNECTION_ONLY;
    uint8_t mitm = TRUE;
    uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_YES_NO;
    
    GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
    GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
    GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
    GAPBondMgr_SetParameter(GAPBOND_SECURE_CONNECTION, sizeof(uint8_t), &scMode);
  3. 处理密码回调并显示代码。

    static void SimpleCentral_processPasscode(uint16_t connHandle, uint8_t uiOutputs)
    {
      // 向用户显示密码
      if (uiOutputs != 0)
      {
        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Passcode: %d", B_APP_DEFAULT_PASSCODE);
      }
    
      // 发送密码响应
      GAPBondMgr_PasscodeRsp(connHandle, SUCCESS, B_APP_DEFAULT_PASSCODE);
    }
  4. 接受用户输入的 Yes-No 并将响应发送到 GAPBondMgr。

    if (keys & KEY_RIGHT)
    {
      // 发送响应以表明代码匹配
      GAPBondMgr_PasscodeRsp(connHandle, SUCCESS, TRUE);
      return;
    }

在这种情况下,GAPBondMgr_PasscodeRsp 的第三个参数通常接受一个密码,被重载为向堆栈发送 TRUE 以表明代码匹配并继续配对。数字比较过程如图 89 所示。

Figure 89

图 89. 数字比较。

Out of Band 配对

带外 (OOB) 是一种功能,允许两个设备通过不在设备频段内的通信通道(例如 NFC)发送认证信息。目的是让没有输入或输出能力的两个设备创建认证配对。通过发送三个认证参数来实现:设备地址、随机数和确认值。

OOB 认证的主要目的是防止 MITM 攻击。方法是由一个设备生成密钥(可以是发起方或响应方)。然后 OOB 数据通过 BLE 之外的其他通信手段传输给另一台设备。

OOB 数据在运行时生成。这可以使用椭圆曲线密码术 (ECC) 或不使用。在此示例中,我们将使用 ECC 生成密钥。要使用 Central 应用(如 Simple Central)生成 OOB 数据,请执行以下步骤:

  1. 创建 gapBondOOBData_t 变量,一个用于本地 OOB 数据,一个用于远程设备的数据:

    gapBondOOBData_t localOobData;
    gapBondOOBData_t remoteOobData;
  2. 定义配对状态回调

    // Bond Manager 回调
    static gapBondCBs_t bondMgrCBs =
    {
      SimpleCentral_passcodeCb, // 密码回调
      SimpleCentral_pairStateCb // 配对/绑定状态回调
    };
    static void SimpleCentral_pairStateCb(uint16_t connHandle, uint8_t state, uint8_t status)
    {
      scPairStateData_t *pData;
      // 为事件数据分配空间。
      if ((pData = ICall_malloc(sizeof(scPairStateData_t))))
      {
        pData->connHandle = connHandle;
        pData->status = status;
        // 排队事件。
        if (SimpleCentral_enqueueMsg(SC_EVT_PAIR_STATE, state, (uint8_t*) pData) != SUCCESS)
        {
          ICall_free(pData);
        }
      }
    }
  3. 如果要使用 ECC 生成密钥,请调用 GAPBondMgr_GenerateEccKeys。(如果不调用此 API,则密钥将在没有 ECC 的情况下生成。)
  4. 在处理配对状态回调时添加对 GAPBondMgr_SCGetLocalOOBParameters 的调用。

    static void SimpleCentral_processPairState(uint8_t state, scPairStateData_t* pPairData)
    {
      uint8_t status = pPairData->status;
      uint8_t pairMode = 0;
      if (state == GAPBOND_GENERATE_ECC_DONE)
      {
        if (status == SUCCESS)
        {
          GAPBondMgr_SCGetLocalOOBParameters(&localOobData);
          uint8_t i;
          for (i = 0; i < KEYLEN; i++)
          {
            Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "OOB data confirm[%d]: %d", i, localOobData.confirm[i]);
          }
          for (i = 0; i < KEYLEN; i++)
          {
            Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "OOB data rand[%d]: %d", i, localOobData.rand[i]);
          }
        }
        break;
      }
    }

    或者将此添加到现有的配对状态回调中。

    else if (state == GAPBOND_GENERATE_ECC_DONE)
    {
      if (status == SUCCESS)
      {
          GAPBondMgr_SCGetLocalOOBParameters(&localOobData);
          uint8_t i;
          for (i = 0; i < KEYLEN; i++)
          {
              Display_printf(dispHandle, SC_ROW_CUR_CONN+i, 0, "OOB data confirm[%d]: %d", i, localOobData.confirm[i]);
          }
          for (i = 0; i < KEYLEN; i++)
          {
              Display_printf(dispHandle, SC_ROW_CUR_CONN+16+i, 0, "OOB data rand[%d]: %d", i, localOobData.rand[i]);
          }
      }
    }    
  5. 接收到 OOB 数据的设备(而不是生成它的设备)应将 GAPBOND_OOB_ENABLED 参数设置为 true。如果两台设备都生成并共享了它们的 OOB 数据,则都应设置此标志。在本例中,我们只在外设设备上设置此标志。

    uint8_t oobEnabled = TRUE;
    
    GAPBondMgr_SetParameter(GAPBOND_OOB_ENABLED, sizeof(uint8_t), &oobEnabled);
  6. 执行 OOB 通信,即将 localOobData 中的数据传输给响应设备。为了简单起见,在本例中,Central 设备将显示数据,因此可以在外设设备上硬编码这些数据。

    Figure 90

    Figure 90. Central 设备显示 OOB 数据

    Listing 79. SimplePeripheral_processGapMessage::GAP_DEVICE_INIT_DONE_EVENT OOB 数据应编码在 peripheral 设备.

    uint8_t oobEnabled = TRUE;
    GAPBondMgr_SetParameter(GAPBOND_OOB_ENABLED, sizeof(uint8_t), &oobEnabled);
    remoteOobData.confirm[0] = 204;
    remoteOobData.confirm[1] = 29;
    remoteOobData.confirm[2] = 240;
    remoteOobData.confirm[3] = 154;
    remoteOobData.confirm[4] = 141;
    remoteOobData.confirm[5] = 40;
    remoteOobData.confirm[6] = 132;
    remoteOobData.confirm[7] = 41;
    remoteOobData.confirm[8] = 156;
    remoteOobData.confirm[9] = 106;
    remoteOobData.confirm[10] = 91;
    remoteOobData.confirm[11] = 230;
    remoteOobData.confirm[12] = 11;
    remoteOobData.confirm[13] = 88;
    remoteOobData.confirm[14] = 117;
    remoteOobData.confirm[15] = 104;
    remoteOobData.rand[0] = 56;
    remoteOobData.rand[1] = 242;
    remoteOobData.rand[2] = 38;
    remoteOobData.rand[3] = 152;
    remoteOobData.rand[4] = 189;
    remoteOobData.rand[5] = 78;
    remoteOobData.rand[6] = 164;
    remoteOobData.rand[7] = 36;
    remoteOobData.rand[8] = 153;
    remoteOobData.rand[9] = 82;
    remoteOobData.rand[10] = 167;
    remoteOobData.rand[11] = 190;
    remoteOobData.rand[12] = 140;
    remoteOobData.rand[13] = 235;
    remoteOobData.rand[14] = 207;
    remoteOobData.rand[15] = 93;
    GAPBondMgr_SCSetRemoteOOBParameters(&remoteOobData, 1);

    OOB 配对处理流程 Figure 91..

    Figure 91. OOB 配对流程

启用绑定的 GAPBondMgr 示例

绑定可以为任何类型的配对启用或禁用,通过 GAPBOND_BONDING_ENABLED 参数设置。绑定发生在配对过程完成之后。要启用绑定,请按如下方式配置 GAPBondMgr:

uint8_t bonding = TRUE;
GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);

启用绑定后,GAPBondMgr 会将配对过程中传输的长期密钥 (LTK) 存储到 SNV 中。有关更多信息,请参见 GAPBondMgr and SNV。完成绑定后,应用程序会收到 GAPBOND_PAIRING_STATE_COMPLETE 事件。当初次连接、配对和绑定时,应用程序配对状态回调只会传递 GAPBOND_PAIRING_STATE_BOND_SAVED。对于与已绑定设备的未来连接,安全密钥从闪存中加载,从而跳过配对过程。在这种情况下,应用程序配对状态回调只会传递 GAPBOND_PAIRING_STATE_BONDED。如图 92 所示。

Figure 92

图 92. 启用绑定的 GAPBondMgr 示例。

GAPBondMgr 和 SNV

本节描述 GAPBondMgr 如何使用 SNV 闪存区域存储绑定信息。有关 SNV 的更多信息,请参见 Flash。可以存储的绑定数量由 GAP_BONDINGS_MAX 定义,该值在 gapbondmgr.h 中默认设置为 10,应用程序可以根据需要修改。如果启用“最近最少使用”方案(least recently used, LRU),则 GAPBondMgr 在没有更多可用绑定时的功能会有所不同。有关 GAPBOND_LRU_BOND_REPLACEMENT 参数的更多信息,请参见 BLE Stack API Reference (GAPBondMgr 部分)。如果此参数设置为 false,则无法添加更多绑定,除非手动删除一个绑定。如果参数设置为 true,则删除最近最少使用的绑定以为新绑定腾出空间。

一个绑定条目包含以下组件:

  1. 绑定记录: 包括对等设备的地址、地址类型、隐私重连地址和状态标志。总共 8 个字节,定义如下:

    // NV 数据结构,用于存储连接设备的地址信息
    typedef struct
    {
       //
       // 对等设备地址
       // 如果此绑定存在身份信息,则这是一个身份地址
       //
      uint8_t addr[B_ADDR_LEN];
       //
       // 对等设备地址类型
       //
      GAP_Peer_Addr_Types_t addrType;
       //
       // 绑定状态标志
       // GAP_BONDED_STATE_FLAGS
      
      uint8_t stateFlags;
    } gapBondRec_t;
  2. 客户端特征配置 (CCC): 每个条目中存储的 CCC 数量由 GAP_CHAR_CFG_MAX 定义,默认设置为 4。每个 CCC 由 4 个字节组成,定义如下:

    // NV 数据结构,用于存储连接设备的特征配置
    typedef struct
    {
      uint16 attrHandle;  // 特征句柄
      uint8  value;       // 该设备的特征值
    } gapBondCharCfg_t;
  3. 本地长期密钥 (LTK) 信息: 存储本地设备的加密信息。总共 28 个字节,结构如下:

    typedef struct
    {
      uint8   LTK[KEYLEN];              // 长期密钥 (LTK)
      uint16  div;  // LTK eDiv
      uint8   rand[B_RANDOM_NUM_SIZE];  // LTK 随机数
      uint8   keySize;                  // LTK 密钥大小
    } gapBondLTK_t;
  4. 连接设备长期密钥信息: 存储连接设备的加密信息。也是一个 gapBondLTK_t 结构,总共 28 个字节。
  5. 连接设备身份解析密钥 (IRK): 存储配对期间生成的 IRK。是一个 16 字节数组。
  6. 连接设备签名解析密钥 (SRK): 存储配对期间生成的 SRK。是一个 16 字节数组。
  7. 连接设备签名计数器: 存储配对期间生成的签名计数器。是一个 4 字节的字。

增加绑定条目数量

可以存储的绑定数量由 GAP_BONDINGS_MAX 定义,在 gapbondmgr.h 中默认设置为 10。然而,由于 SNV 的结构,如果需要 GAP_BONDINGS_MAX 值超过 13,则需要进行一些额外的更改以支持存储更多的绑定:

  1. 修改 GAP_BONDINGS_MAX 为所需的最大绑定条目数。在需要删除旧绑定之前,此值不应超过 32。
  2. 在文件 bcomdef.h 中修改 Bonding NV Items、GATT Configuration NV Items 和 Customer NV Items 的起始和结束范围。这通过修改 BLE_NVID_GAP_BOND_END、BLE_NVID_GATT_CFG_START、BLE_NVID_GATT_CFG_END、BLE_NVID_CUST_START 和 BLE_NVID_CUST_END 来实现。修改必须遵循以下规则:

    • 对于 GAP: (BLE_NVID_GAP_BOND_END - BLE_NVID_GAP_BOND_START) >= GAP_BONDINGS_MAX * 6
    • 对于 GATT: (BLE_NVID_GATT_CFG_END - BLE_NVID_GATT_CFG_START) >= GAP_BONDINGS_MAX。
    • 各范围之间不能有重叠。
    • 所有索引都是 1 字节的值,因此不应超过 0xFF 或 255。
注意:任何绑定配置的更改,例如增加绑定条目的最大数量,都必须在完全擦除 NV 后进行。由于堆栈中没有 API 执行此操作,因此必须使用编程工具(如 CCS 或 Uniflash)进行擦除。

本文由 Jay 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处,点赞0

还不快抢沙发

添加新评论