CH57x/CH58x/CH59xBLE利用IRK解析RPA : 识别可解析私有地址对应的身份地址

前言

在 BLE 开发中,如果希望主机一连接就能判断它是否已经绑定过。直接比对连接事件里的六字节地址,在部分电脑上看似可行,换成手机后却发现地址会变化,同一部手机经常被判成新设备,这类地址通常可以看到它的地址类型为0x03,也就是可解析私有地址;

常见的地址类型如下:

类型

含义

识别方式

0x00 PUBLIC

公开地址

按类型和地址匹配

0x01 STATIC

随机静态地址

按类型和地址匹配

0x02 PRIVATE_NONRESOLVE

不可解析私有地址

不能用 IRK 解析

0x03 PRIVATE_RESOLVE

可解析私有地址

用对端 IRK 匹配


本文只讨论这个识别判断:当设备已经保存了手机的绑定信息(包含1字节地址类型和6字节可解析私有地址)和对端 IRK 时,可用当前 RPA 先匹配绑定记录,再读取该记录的身份地址。

 

解析地址的含义

可解析私有地址 RPA 是会变化的连接地址。IRK 是身份解析密钥,用于判断某个 RPA 是否属于持有该身份的设备。

image

解析接口的结果是匹配或不匹配,不会把 RPA 原地改写成手机的真实 MAC。

准确流程是:当前 RPA → 逐一尝试有效绑定记录的对端 IRK → 找到匹配槽位 → 读取该槽位的身份地址。身份地址可以是公开地址,也可以是随机静态地址;

 

 

解析与读取步骤

1、BLE_SNV_NUM决定着从机可同时存有多少个主机的绑定信息

 【SNV】
 BLE_SNV                                    - 是否开启SNV功能,用于储存绑定信息( 默认:TRUE )
 BLE_SNV_ADDR                               - SNV信息保存地址,使用data flash最后512字节( 默认:0x77E00 )
 BLE_SNV_BLOCK                              - SNV信息保存块大小( 默认:256 )
 BLE_SNV_NUM                                - SNV信息保存数量( 默认:1 )

 

2、通过协议栈给出的tmos_snv_read接口和读取偏移量,我们可得到对端IRK所存放的位置;

image

 

本例通过 tmos_snv_read 访问协议栈的逻辑 SNV 项;对端 IRK 的项 ID 由 devIRKNvID(bondIdx) 计算,主绑定记录由 mainRecordNvID(bondIdx) 定位;
#define BLE_NVID_GAP_BOND_START  0x0200
#define GAP_BOND_REC_IDS         6
#define GAP_BOND_DEV_IRK_OFFSET  3
 
/* 本例头文件宏的等价表达式,仅用于解释 */
/* devIRKNvID(n) = 0x0200 + n * 6 + 3 */

 以BLE_SNV_NUM = 3为例,

协议栈槽位 bondIdx

主记录 SNV ID

对端 IRK SNV ID

0

0x0200

0x0203

1

0x0206

0x0209

2

0x020C

0x020F

 

bondIdx 传 0、1、2 等槽位号,不要先计算出 0x0203 再传给 devIRKNvID,否则宏会再次计算,最终读到错误位置,应用自己维护的设备列表下标也不等于协议栈绑定槽位.
uint8_t peerIRK[KEYLEN];
gapBondRec_t record = {0};

/* 读取指定槽位的对端 IRK */
tmos_snv_read(devIRKNvID(bondIdx),
sizeof peerIRK, peerIRK);

/* 读取该槽位的身份信息 */
tmos_snv_read(mainRecordNvID(bondIdx),
sizeof record, &record);

/* record.publicAddrType:身份地址类型 */
/* record.publicAddr:身份地址 */
BLE_NVID_IRK 和 GAPROLE_IRK 对应本设备自身的 IRK,不能拿来识别手机,这里需要的是 devIRKNvID 对应的对端 IRK

 

3、最终实现

在我们配对完成至多BLE_SNV_NUM个主机后,如果下次连接需要判断本次连接的主机是否在已配对列表中,可参考以下函数实现:

函数作用:

①传入pType=0x03,和待解析pAddr,如果协议栈存储列表中存有对应设备信息,可通过dstType和dstAddr接取身份地址及类型,返回0;

②传入pType=0x03,和待解析pAddr,如果协议栈中未匹配到设备信息,不处理,原封返回至dstType和dstAddr,返回1;

③传入pType=0x00/0x01/0x02,不处理,原封返回至dstType和dstAddr,返回0;

/*
pType-连接事件传入原始地址类型
pAddr-连接事件传入原始地址
dstType-待接收的真实地址类型
dstAddr-待接收的真实身份地址
*/
uint8_t ble_ResolveAddr(uint8_t pType, uint8_t *pAddr,uint8_t *dstType,uint8_t *dstAddr)
{
    uint8_t matchedBondIdx = 0xFF;
    if(pType == ADDRTYPE_PRIVATE_RESOLVE)//如果地址是可解析私有地址(地址会动态变化)
    {
        //利用主机IRK逐一匹配身份地址
        uint8_t bondIdx = 0;
        for(bondIdx = 0; bondIdx < BLE_SNV_NUM; bondIdx++)
        {
            uint8_t peerIRK[KEYLEN];
            uint8_t addr[B_ADDR_LEN];
            gapBondRec_t record = {0};

            //读取当前槽位的对端 IRK
            uint8_t status = tmos_snv_read(devIRKNvID(bondIdx),sizeof(peerIRK),peerIRK);
            PRINT("bondIdx = %d, IRK read status = %02X\n",bondIdx,status);
            if(status != SUCCESS)//
            {
                PRINT("IRK READ FAIL\n");
                continue;//读不到则跳过
            }

            //验证当前 RPA(ResolvePrivateAddr) 是否匹配该 IRK
            status = GAP_ResolvePrivateAddr(peerIRK,  pAddr);
            PRINT("bondIdx = %d, resolve status = %02X\n",bondIdx,status);
            if(status != SUCCESS)
            {
                continue;//不匹配则跳过当前流程
            }

            matchedBondIdx = bondIdx;
            //匹配成功后读取该槽位的真实身份地址
            status = tmos_snv_read( mainRecordNvID(bondIdx),sizeof(record), &record );
            if(status == SUCCESS)
            {
                PRINT("Matched bondIdx: %d\n",bondIdx);
                PRINT("Identity type: %02X\n",record.publicAddrType);
                PRINT("Identity address: ");
                for(uint8_t i=0;i<6;i++)
                {
                    PRINT("%02X ",record.publicAddr[i]);
                }
                PRINT("\n");

                *dstType = record.publicAddrType;
                tmos_memcpy(dstAddr,record.publicAddr,6);
            }
            else
            {
                PRINT("Read identity failed: %02X\n",status);
            }
            break;
        }
        if(bondIdx >= (BLE_SNV_NUM))  
        {
            *dstType = pType;
            tmos_memcpy(dstAddr,pAddr,6);
            PRINT("NEW PAIR DEVICE\n");
            //所有轮次未找到,说明是新配对的ADDRTYPE_PRIVATE_RESOLVE类型主机,
            //再进入配对完成GAPBOND_PAIRING_STATE_COMPLETE回调后需要对原始地址解析为真实身份地址再存储到flash
            return 1;
        }
    }
    else  //其余主机型号基本都是0x00,拿到的都是公共地址,无需解析,0x01/0x02本文未作处理
    {
        *dstType = pType;
        tmos_memcpy(dstAddr,pAddr,6);
    }
    return 0;
}

 调用位置参考:

image

 

posted @ 2026-10-30 21:09  oTvTo  阅读(11)  评论(0)    收藏  举报