首页 > 其他分享 >esp32 蓝牙配对码 ESP_IO_CAP_OUT方式

esp32 蓝牙配对码 ESP_IO_CAP_OUT方式

时间:2024-03-02 14:57:54浏览次数:32  
标签:ESP esp32 CAP ble MITM 密钥 BLE 配对

1 简介

为了安全连接,必不可少的修改蓝牙的配对方式,提高产品的安全性。安全配置使充当从设备的GATT服务器能够与主设备绑定,并在它们之间建立加密链接。此功能由[蓝牙规范4.2版]定义(https://www.bluetooth.com/specifications/bluetooth-core-specification)并在ESP-IDF BLE堆栈上实现,特别是在安全管理器协议(SMP)API上实现。

BLE安全涉及三个相互关联的概念:配对、绑定和加密。

与交换所需的安全功能和密钥类型有关的配对问题。此外,配对过程还负责生成和交换共享密钥。核心规范定义了ESP32支持的传统配对和安全连接配对(在蓝牙4.2中引入)。一旦共享密钥的交换完成,就建立临时加密链路来交换短期和长期密钥。绑定是指为后续连接存储交换的密钥,这样它们就不必再次传输。最后,加密涉及使用AES-128引擎和共享密钥对纯文本数据进行加密。服务器属性也可以被定义为只允许加密的写入和读取消息。在通信的任何时候,从设备总是可以通过向另一个对等设备发出安全请求来请求开始加密,该对等设备通过调用API返回安全响应。

2 修改案例

2.1 创建移植工程

例程使用VS Code创建gatt_server例程,并在此例程上修改

2.2 添加安全绑定功能

2.2.1 设置安全参数

ESP32需要一系列安全参数,以定义如何构建配对请求和响应。GATT Server构建的配对响应数据包包括输入/输出功能、安全连接配对、经过身份验证的中间人(MITM)保护或无安全要求等字段(参见[Bluetooth Specification Version 4.2]的第2.3.1节)(https://www.bluetooth.com/specifications/bluetooth-core-specification)[第3卷,第H部分])。在本例中,此过程在app_main()函数中完成。配对请求由启动器发送,在这种情况下,启动器是远程GATT客户端。在此示例中实现的ESP32服务器接收此请求并使用配对响应进行回复,该配对响应包含相同的安全参数,以便两个设备商定可用的资源和适用的配对算法(Just WorksPasskey Entry)。配对请求和响应命令都具有以下参数:

  • IO功能:描述设备是否具有输入/输出功能,如显示器或键盘。
  • OOB标志:描述设备是否支持带外密钥交换,例如使用NFC或Wi-Fi将密钥交换为TK。

  • 授权请求:表示请求的安全属性,如绑定、安全连接(SC)、MITM保护或不存在于配对请求和响应数据包中。

  • 最大加密密钥大小:以八位字节为单位的最大加密密钥尺寸。

  • 启动器密钥分发/生成:指示启动器在传输特定密钥分发阶段请求分发/生成或使用的密钥。在配对请求中,请求这些密钥,而在配对响应中,确认这些密钥被分发。

  • 响应程序密钥分发/生成:指示发起者在传输特定密钥分发阶段请求响应程序分发/生成或使用的密钥。在配对请求中,请求这些密钥,而在配对响应中,确认这些密钥被分发。

在app_main中添加如下:

  • IO Capability:
esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE;//set the IO capability to No Input No Output

IO Capability包括如下几种

ESP_IO_CAP_OUT         0   /*!< DisplayOnly */
ESP_IO_CAP_IO          1   /*!< DisplayYesNo */
ESP_IO_CAP_IN          2   /*!< KeyboardOnly */
ESP_IO_CAP_NONE        3   /*!< NoInputNoOutput */
ESP_IO_CAP_KBDISP      4   /*!< Keyboard display */
  • Authorization Request:
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_BOND; //bonding with peer device after authentication

Authorization Request的可能值是绑定、MITM保护和安全连接请求的组合:

ESP_LE_AUTH_NO_BOND: No bonding.
ESP_LE_AUTH_BOND: Bonding is performed.
ESP_LE_AUTH_REQ_MITM: MITM Protection is enabled.
ESP_LE_AUTH_REQ_SC_ONLY: Secure Connections without bonding enabled.
ESP_LE_AUTH_REQ_SC_BOND: Secure Connections with bonding enabled.
ESP_LE_AUTH_REQ_SC_MITM: Secure Connections with MITM Protection and no bonding enabled.
ESP_LE_AUTH_REQ_SC_MITM_BOND: Secure Connections with MITM Protection and bonding enabled.
  • Maximum Encryption Key Size:
uint8_t key_size = 16;      //the key size should be 7~16 bytes
  • Initiator Key Distribution/Generation:
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;

启动器通过设置EncKey和IdKey掩码来分发LTK和IRK密钥。

  • Responder Key Distribution/Generation:
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;

响应程序通过设置EncKeyIdKey掩码来分发LTK和IRK密钥。

定义后,使用“esp_ble_gap_set_security_param()”函数设置参数。此函数用于设置参数类型、参数值和参数长度:

esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));

这些信息足以让BLE堆栈执行配对过程,包括配对确认和密钥生成。该过程对用户不可见,并由堆栈自动执行。

2.2.2 连接和绑定到对等设备

先前设置的安全参数存储在本地,以便稍后在主设备连接到从设备时使用。每次远程设备连接到本地GATT服务器时,都会触发连接事件“ESP_GATTS_CONNECT_EVT”。此事件用于通过调用“esp_ble_set_encryption()”函数来执行配对和绑定过程,该函数将远程设备地址和将要执行的加密类型作为参数。BLE堆栈然后在后台执行实际的配对过程。在本例中,加密包括MITM保护,此权限可根据gatt 特征的权限进行修改。

将下列代码添加至一个gatt服务的handle里面,如gatts_profile_b_event_handler()等。

case ESP_GATTS_CONNECT_EVT:
     //start security connect with peer device when receive the connect event sent by the master.  
    esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_MITM);  
    break;

可用的加密类型有:

  • ESP_BLE_SEC_NONE
  • ESP_BLE_SEC_ENCRYPT
  • ESP_BLE_SEC_ENCRYPT_NO_MITM
  • ESP_BLE_SEC_ENCRYPT_MITM

“ESP_BLE_SEC_ENCRYPT”和“ESP_BLE _SEC_ENCRYPT_NO_MITM”之间的区别在于,以前的连接可能具有需要升级的安全级别,因此需要再次交换密钥。
在本例中将“IO Capability”设置为“仅显示”,因此需要生成6位密钥。因此,根据远程设备的I/O能力,可以在ESP32上生成密钥,该密钥以“ESP_GAP_BLE_passkey_NOTIF_EVT”呈现给用户:

case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:    
     ///the app will receive this evt when the IO  has Output capability and the peer device IO has Input capability.
     ///show the passkey number to the user to input it in the peer device.
     ESP_LOGE(GATTS_TABLE_TAG, "The passkey Notify number:%d", param->ble_security.key_notif.passkey);
     break;

决定使用哪种算法的输入和输出能力的组合是:

Display Only Display Yes/No Keyboard Only No Input No Output Keyboard Display
Display Only Just Works Just Works Passkey Entry Just Works Passkey Entry
Display Yes/No Just Works Just Works Passkey Entry Just Works Passkey Entry
Keyboard Only Passkey Entry Passkey Entry Passkey Entry Just Works Passkey Entry
No Input No Output Just Works Just Works Just Works Just Works Just Works
Keyboard Display Passkey Entry Passkey Entry Passkey Entry Just Works Passkey Entry

2.2.3 交换密钥

当客户端连接到服务器并且配对成功完成时,交换由“init_key”和“rsp_key”安全参数指示的密钥。在本例中,将生成并分发以下密钥:

  • Local device LTK
  • Local device IRK
  • Local device CSRK
  • Peer device LTK
  • Peer device IRK

注意:

仅对于该示例,不交换对等设备CSRK。对于每个密钥交换消息,都会触发一个“ESP_GAP_BLE_KEY_EVT”事件,该事件可用于打印接收到的密钥类型:

case ESP_GAP_BLE_KEY_EVT:
     //shows the ble key info share with peer device to the user.
     ESP_LOGI(GATTS_TABLE_TAG, "key type = %s", esp_key_type_to_str(param->ble_security.ble_key.key_type));
     break;

当密钥交换成功后,配对过程就完成了。这会触发“ESP_GAP_BLE_AUTH_CMPL_EVET”事件,该事件用于打印远程设备、地址类型和配对状态等信息:

case ESP_GAP_BLE_AUTH_CMPL_EVT: {
     esp_bd_addr_t bd_addr;
     memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr,  
            sizeof(esp_bd_addr_t));
     ESP_LOGI(GATTS_TABLE_TAG, "remote BD_ADDR: %08x%04x",\
              (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) +   
              bd_addr[3],  
              (bd_addr[4] << 8) + bd_addr[5]);
     ESP_LOGI(GATTS_TABLE_TAG, "address type = %d",   
              param->ble_security.auth_cmpl.addr_type);  
              ESP_LOGI(GATTS_TABLE_TAG, "pair status = %s",  
              param->ble_security.auth_cmpl.success ? "success" : "fail");
     break;
}

2.2.4 属性的安全权限

在定义服务器的属性时,可以对写入和读取事件设置不同的权限。属性权限可以是:

  • Permission to read
  • Permission to read with encryption
  • Permission to read with encryption and MITM protection
  • Permission to write
  • Permission to write with encryption
  • Permission to write with encryption and MITM protection
  • Permission to signed write
  • Permission to signed write with MITM protection

这些权限在API中定义为:

  • ESP_GATT_PERM_READ
  • ESP_GATT_PERM_READ_ENCRYPTED
  • ESP_GATT_PERM_READ_ENC_MITM
  • ESP_GATT_PERM_WRITE
  • ESP_GATT_PERM_WRITE_ENCRYPTED
  • ESP_GATT_PERM_WRITE_ENC_MITM
  • ESP_GATT_PERM_WRITE_SIGNED
  • ESP_GATT_PERM_WRITE_SIGNED_MITM

创建服务表时,无论是否加密,每个属性都可以具有读取或写入权限。当某个属性具有加密权限,而不具有所需安全权限的对等设备试图读取或写入该属性时,本地主机会发送“授权不足错误”。在其他新的例子中,以下属性是使用加密权限定义的,本例无需添加

…
// Body Sensor Location Characteristic Value
    [HRS_IDX_BOBY_SENSOR_LOC_VAL]   = {
    {ESP_GATT_AUTO_RSP},  
    {ESP_UUID_LEN_16,  
    (uint8_t *)&body_sensor_location_uuid,
    ESP_GATT_PERM_READ_ENCRYPTED,
    sizeof(uint8_t),  
    sizeof(body_sensor_loc_val),  
    (uint8_t *)body_sensor_loc_val}
    },
…
// Heart Rate Control Point Characteristic Value
    [HRS_IDX_HR_CTNL_PT_VAL]        = {
    {ESP_GATT_AUTO_RSP},  
    {ESP_UUID_LEN_16,  
    (uint8_t *)&heart_rate_ctrl_point,  
    ESP_GATT_PERM_WRITE_ENCRYPTED|ESP_GATT_PERM_READ_ENCRYPTED,  
    sizeof(uint8_t),  
    sizeof(heart_ctrl_point),   
    (uint8_t *)heart_ctrl_point}  
    },
…

2.2.5 安全请求

在主设备和从设备之间的通信过程中,从设备可能随时通过发出安全请求命令来请求开始加密。此命令将在主机上触发“ESP_GAP_BLE_SEC_REQ_EVT”事件,该事件将向对等设备回复肯定(真)安全响应以接受请求,或回复否定(假)安全响应来拒绝请求。在本例中,此事件用于通过使用esp_ble_gap_security_rsp()neneneba API调用来回复启动加密响应。需添加至gap_event_handler()中。

case ESP_GAP_BLE_SEC_REQ_EVT:
     /* send the positive (true) security response to the peer device to accept the security request.
     If not accept the security request, should send the security response with negative(false) accept value*/
     esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
     break;

2.2.6 总结

2.2部分在全新工程需要添加的内容,此工程只需要将2.1和2.5部分添加至工程即可。

3 测试

标签:ESP,esp32,CAP,ble,MITM,密钥,BLE,配对
From: https://www.cnblogs.com/wfagly/p/18048620

相关文章

  • KubeSphere 社区双周报|2024.02.01-02.29
    KubeSphere社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过commit的贡献者,并对近期重要的PR进行解析,同时还包含了线上/线下活动和布道推广等一系列社区动态。因假期,上期双周报停更,因此本次双周报会包含四周的内容。本次双周报涵盖时间为:2......
  • 编译opencapwap 编译环境加密库openssl版本调整
    1、删除原来版本:sudoapt-getremovelibssl1.0-devlibssl-dev删除链接:删除/bin/openssl2、下载版本wget--no-check-certificatehttps://www.openssl.org/source/old/1.0.0/openssl-1.0.0.tar.gz解压安装:tar-xzvf./openssl-OpenSSL_1_0_2t.tar.gzcdopenssl-OpenSSL......
  • CF932F Escape Through Leaf【DP,李超线段树】
    有一颗\(n\)个节点的树,根节点为\(1\)。每个节点有两个权值,第\(i\)个节点的权值为\(a_i,b_i\)。你可以从一个节点跳到它的子树内任意一个节点上。从节点\(x\)跳到节点\(y\)一次的花费为\(a_x\timesb_y\)。跳跃多次走过一条路径的总费用为每次跳跃的费用之和。求每个节......
  • esp32 VS Code环境搭建
    1清除旧的环境1.1删除已经安装过的espressidf残留环境1.2删除环境变量2安装Python环境https://www.python.org/downloads/需要注意将python添加至环境变量3安装ESP-IDF-tool离线包以管理员权限安装此工具包,且VSCode在安装过程中不要打开!!出现下列情况为安装成功......
  • 13.分布式事件总线DotNetCore.CAP的简单使用
    DotNetCore.CAP框架提供了一个简单易用的API和多种消息传输协议支持(包括Redis、RabbitMQ等),可以让用户轻松地实现消息队列、事件发布/订阅、分布式事务等功能。它还具备自动重试、异常处理、数据序列化等高级特性,可以保证消息的可靠性和一致性。使用DotNetCore.CAP框架,你可以:1.......
  • Dockerfile构建出错:Error response from daemon: pull access denied for hwjdk, rep
    原因:FROMhwjdk这样写,其实默认查找的是hwjdk:latest,而如果你的image里hwjdk镜像版本不是latest就会报这个错误解决方法:写上版本号即可: FROMhwjdk:1.19.1参考文章:Errorresponsefromdaemon:pullaccessdeniedforjdk,repositorydoesnotexistormayrequire......
  • NanoFramework操作ESP32(一)_基础元器件篇(二十七)_ 气体质量、可燃气体、烟雾检测传感器
    一、元器件介绍1、针脚用途编号名称功能1GND电源地2+5V电源正3AO信号脚二、示例代码1、代码:元器件的针脚ESP32模块的针脚GND;供电脚-GND+5V;供电脚++5VAO;信号脚IO16   未完2、结果: ......
  • NanoFramework操作ESP32(一)_基础元器件篇(三十一)_ MPU6050陀螺仪模块
    一、元器件介绍    MPU-6050是InvenSense公司生产的一款六轴运动处理器,集成了3轴加速度计和3轴陀螺仪;内置的数字运动处理器(DMP)可以实现高级运动处理功能,如六轴运动融合、姿态估计等。这款传感器广泛应用于运动控制和测量领域,如无人机、智能手机、运动手环等。通信接口:I2C(......
  • NanoFramework操作ESP32(一)_基础元器件篇(十三)_ SL620人体红外传感器
    一、元器件介绍1、针脚用途编号名称功能1GND电源地2+5V电源正3S信号脚;倾斜时输出低电平二、示例代码1、代码:元器件的针脚ESP32模块的针脚GND;供电脚-GND+5V;供电脚++5VS;信号脚IO16 #regionKY-010光遮断传感......
  • NanoFramework操作ESP32(一)_基础元器件篇(十七)_ KY-019继电器(1路5V继电器)
    一、元器件介绍 1、针脚介绍针脚(左到右)介绍S控制针脚+电源+-电源-二、示例代码元器件的针脚ESP32模块的针脚SIO16+3.3V-GND1、代码 publicstaticvoidMain(){#region激光头KY008HelperkY008=newKY008H......