当前位置: 首页 > news >正文

BlueZ使能Privacy=device后,smp fail (本端DH key check fail)

原始需求:
在dual mode下,客户需要Classic & BLE分别使用不同的名字,这就需要BLE使用RPA,让Classic & BLE成为两个不同的设备。

# Default privacy setting.# Enables use of private address.# Possible values for LE mode: "off", "network/on", "device"# Possible values for Dual mode: "off", "network/on", "device",# "limited-network", "limited-device"## - off: Local privacy disabled.## - network/on: A device will only accept advertising packets from peer# devices that contain private addresses. It may not be compatible with some# legacy devices since it requires the use of RPA(s) all the time.## - device: A device in device privacy mode is only concerned about the# privacy of the device and will accept advertising packets from peer devices# that contain their Identity Address as well as ones that contain a private# address, even if the peer device has distributed its IRK in the past.# - limited-network: Apply Limited Discoverable Mode to advertising, which# follows the same policy as to BR/EDR that publishes the identity address when# discoverable, and Network Privacy Mode for scanning.## - limited-device: Apply Limited Discoverable Mode to advertising, which# follows the same policy as to BR/EDR that publishes the identity address when# discoverable, and Device Privacy Mode for scanning.## Defaults to "off"#Privacy = off

BlueZ main.conf中添加“Privacy = device”,使能BLE RPA。

使用手机连接并配对DUT BLE,发现配对失败。


查看kernel中smp回复DH Key Check Failed的代码:

staticintsmp_cmd_dhkey_check(structl2cap_conn*conn,structsk_buff*skb){structsmp_cmd_dhkey_check*check=(void*)skb->data;structl2cap_chan*chan=conn->smp;structhci_conn*hcon=conn->hcon;structsmp_chan*smp=chan->data;u8 a[7],b[7],*local_addr,*remote_addr;u8 io_cap[3],r[16],e[16];interr;bt_dev_dbg(hcon->hdev,"conn %p",conn);if(skb->len<sizeof(*check))returnSMP_INVALID_PARAMS;memcpy(a,&hcon->init_addr,6);memcpy(b,&hcon->resp_addr,6);a[6]=hcon->init_addr_type;b[6]=hcon->resp_addr_type;if(test_bit(SMP_FLAG_INITIATOR,&smp->flags)){local_addr=a;remote_addr=b;memcpy(io_cap,&smp->prsp[1],3);}else{local_addr=b;remote_addr=a;memcpy(io_cap,&smp->preq[1],3);}memset(r,0,sizeof(r));if(smp->method==REQ_PASSKEY||smp->method==DSP_PASSKEY)put_unaligned_le32(hcon->passkey_notify,r);elseif(smp->method==REQ_OOB)memcpy(r,smp->lr,16);err=smp_f6(smp->tfm_cmac,smp->mackey,smp->rrnd,smp->prnd,r,io_cap,remote_addr,local_addr,e);if(err)returnSMP_UNSPECIFIED;if(crypto_memneq(check->e,e,16))returnSMP_DHKEY_CHECK_FAILED;if(!test_bit(SMP_FLAG_INITIATOR,&smp->flags)){if(test_bit(SMP_FLAG_WAIT_USER,&smp->flags)){set_bit(SMP_FLAG_DHKEY_PENDING,&smp->flags);return0;}/* Responder sends DHKey check as response to initiator */sc_dhkey_check(smp);}sc_add_ltk(smp);if(test_bit(SMP_FLAG_INITIATOR,&smp->flags)){hci_le_start_enc(hcon,0,0,smp->tk,smp->enc_key_size);hcon->enc_key_size=smp->enc_key_size;}return0;}

可以看到是因为本地smp_f6()算出来的结果与对端发过来的计算结果不一致。

本地kernel smp算法库或者其他配置有问题?

做个对比实验,不配置"Privacy = device",看看是否可以正常连接配对。


可以正常连接+配对,排除smp算法库和本地配置问题。

staticintsmp_f6(structcrypto_shash*tfm_cmac,constu8 w[16],constu8 n1[16],constu8 n2[16],constu8 r[16],constu8 io_cap[3],constu8 a1[7],constu8 a2[7],u8 res[16]){u8 m[65];interr;SMP_DBG("w %16phN",w);SMP_DBG("n1 %16phN n2 %16phN",n1,n2);SMP_DBG("r %16phN io_cap %3phN a1 %7phN a2 %7phN",r,io_cap,a1,a2);memcpy(m,a2,7);memcpy(m+7,a1,7);memcpy(m+14,io_cap,3);memcpy(m+17,r,16);memcpy(m+33,n2,16);memcpy(m+49,n1,16);err=aes_cmac(tfm_cmac,w,m,sizeof(m),res);if(err)returnerr;SMP_DBG("res %16phN",res);returnerr;}

这是smp_f6()算法,除了参数7、8之外,其他都是smp配对过程的中间产物,我们已经排除了算法库&本地配置的问题,接下来可以重点关注a1、a2这两个变数上。

我们追一下smp_f6()的参数7、8:a1、a2,他们是remote_addr + addr_type,local_addr + addr_type组合起来的2个7字节数组。

唯一的可能就是DUT和对端手机smp_f6()算法的a1、a2参数不一致。

这是本端HCI Log中Host设置的RPA:

这是用nRF-Connect搜索到的:

果然不一样,难怪SMP DH Key Check Fail.

HCI LE Set Extended Advertising Parameters Command的Own_Address_Type参数,Spec的描述如下:


看起来是Controller另外生成了一个RPA,生成RPA的条件是Controller的resolving list中包含可以匹配的entry,否则controller广播会使用LE_Set_Advertising_Set_Random_Address命令带下来的address。

但这里controller是如何匹配上了resolving list中的entry的呢?



从开机HCI log中看到两处不合理的地方

1)Host开机就下发了HCI_LE_Add_Device_To_Resolving_List,peer address = local public addr,peer IRK = local IRK
这条命令只能用于添加配对过的设备才对

2)LE_Set_Extended_Advertising_Pramam CMD中Peer Addr = local public addr
只有直连广播才会设置这个参数

搜索kernel代码,发现了下面这段,看起来kernel对privacy的实现卡了一个spec的bug,故意设置[HCI_LE_Add_Device_To_Resolving_List,peer addr = local public addr],且[LE_Set_Extended_Advertising_Pramam CMD,peer addr = local public addr],这使得controller正好能够从resolving list匹配到一个entry,使用这个entry的local IRK来生成一个RPA.

staticinthci_powered_update_adv_sync(structhci_dev*hdev){structadv_info*adv,*tmp;interr;if(!hci_dev_test_flag(hdev,HCI_LE_ENABLED))return0;/* If RPA Resolution has not been enable yet it means the * resolving list is empty and we should attempt to program the * local IRK in order to support using own_addr_type * ADDR_LE_DEV_RANDOM_RESOLVED (0x03). */if(!hci_dev_test_flag(hdev,HCI_LL_RPA_RESOLUTION)){hci_le_add_resolve_list_sync(hdev,NULL);hci_le_set_addr_resolution_enable_sync(hdev,0x01);}。。。。。。/* Call for each tracked instance to be scheduled */list_for_each_entry_safe(adv,tmp,&hdev->adv_instances,list)hci_schedule_adv_instance_sync(hdev,adv->instance,true);return0;}inthci_setup_ext_adv_instance_sync(structhci_dev*hdev,u8 instance){。。。。。。/* If Own_Address_Type equals 0x02 or 0x03, the Peer_Address parameter * contains the peer’s Identity Address and the Peer_Address_Type * parameter contains the peer’s Identity Type (i.e., 0x00 or 0x01). * These parameters are used to locate the corresponding local IRK in * the resolving list; this IRK is used to generate their own address * used in the advertisement. */if(own_addr_type==ADDR_LE_DEV_RANDOM_RESOLVED)hci_copy_identity_address(hdev,&cp.peer_addr,&cp.peer_addr_type);err=hci_set_ext_adv_params_sync(hdev,adv,&cp,&rp);if(err)returnerr;。。。。。。return0;}


好了,一切都说得通了,要想解决这个问题,只需要DUT & 手机计算smp_f6()时,a1、a2参数相匹配就行。那host如何能拿到controller实际广播的RPA呢?

答案就在LE Enhanced Connection Complete Event中:


我们的controller上报的Local RPA参数全为0,所以smp_f6()计算结果匹配失败。只需要controller在这个evt中上报实际使用的RPA,那么这个问题就解决了。

我们来延伸一下,如果使能了bluez privacy = device,应用层如何获取当前controller使用的RPA呢?

spec中有这样一条命令,可以获取local RPA,但是需要填两个参数:peer identity address type + peer identity address,从描述上看是使用已配对设备的地址信息来获取local RPA,但是在没有任何配对信息之前,我们如何获取呢?

我们正好可以利用bluez实现privacy的技巧,peer addr就填local addr,这样就能以在resolving list中匹配到一个entry,拿到local RPA。

在bluez/lib/hci.c中增加接口:

typedefstruct{uint8_tpeer_addr_type;bdaddr_tpeer_addr;}__attribute__((packed))le_read_local_resolvable_addr_cp;typedefstruct{uint8_tstatus;bdaddr_tlocal_rpa;}__attribute__((packed))le_read_local_resolvable_addr_rp;#defineOCF_LE_READ_LOCAL_RESOLVABLE_ADDR0x002C#defineLE_READ_LOCAL_RESOLVABLE_ADDR_CP_SIZEsizeof(le_read_local_resolvable_addr_cp)#defineLE_READ_LOCAL_RESOLVABLE_ADDR_RP_SIZEsizeof(le_read_local_resolvable_addr_rp)inthci_le_read_local_resolvable_address(intdd,uint8_tpeer_addr_type,constbdaddr_t*peer_addr,bdaddr_t*local_rpa,intto){structhci_requestrq;le_read_local_resolvable_addr_cp cp;le_read_local_resolvable_addr_rp rp;if(!peer_addr||!local_rpa){errno=EINVAL;return-1;}memset(&cp,0,sizeof(cp));memset(&rp,0,sizeof(rp));cp.peer_addr_type=peer_addr_type;bacpy(&cp.peer_addr,peer_addr);memset(&rq,0,sizeof(rq));rq.ogf=OGF_LE_CTL;rq.ocf=OCF_LE_READ_LOCAL_RESOLVABLE_ADDR;rq.cparam=&cp;rq.clen=LE_READ_LOCAL_RESOLVABLE_ADDR_CP_SIZE;rq.rparam=&rp;rq.rlen=LE_READ_LOCAL_RESOLVABLE_ADDR_RP_SIZE;if(hci_send_req(dd,&rq,to)<0)return-1;if(rp.status){errno=EIO;return-1;}bacpy(local_rpa,&rp.local_rpa);return0;}

在应用层调用这个接口来验证一下:

staticintble_read_local_rpa(void){bdaddr_tlocal_bda,local_rpa;intdd;intdev_id;dev_id=hci_get_route(NULL);if(dev_id<0){AML_LOGI("no default bt adapter \n");returnLM_STATUS_FAIL;}dd=hci_open_dev(dev_id);if(dd<0){AML_LOGE("Failed to open HCI device\n");returnLM_STATUS_FAIL;}hci_devba(dev_id,&local_bda);hci_le_read_local_resolvable_address(dd,0,&local_bda,&local_rpa,1000);hci_close_dev(dd);AML_LOGI("Local BDA %02X:%02X:%02X:%02X:%02X:%02X, Local RPA %02X:%02X:%02X:%02X:%02X:%02X\n",local_bda.b[0],local_bda.b[1],local_bda.b[2],local_bda.b[3],local_bda.b[4],local_bda.b[5],local_rpa.b[0],local_rpa.b[1],local_rpa.b[2],local_rpa.b[3],local_rpa.b[4],local_rpa.b[5]);}

(ble_read_local_rpa): Local BDA 2E:2C:75:62:A5:10, Local RPA 88:8B:30:B6:61:47

http://www.jsqmd.com/news/1248364/

相关文章:

  • 寄电动车用什么物流最省钱?慧寄侠教你避坑指南与比价攻略 - 快递物流资讯
  • 为什么 AI 算命比路边摊更像“读心术”?揭秘大模型、Prompt 与心理暗示背后的技术逻辑
  • 2026厦门闲置奢饰首饰回收榜单出炉!实体连锁持证经营,透明估价,珠宝变现避开套路 - 商业每日快报
  • 泰格豪雅公告:宁波客户服务网点地址与售后电话2026年7月最新版 - 亨得利钟表维修中心
  • 个性化新闻播报系统:智能采集与语音合成实践
  • 聊城黄金回收哪家靠谱?2026东昌府区润富黄金口碑老店实测推荐 - 观金堂黄金回收
  • 澄海区精工装修公司哪家好?2026避坑指南:4个坑+5条硬标准,帮你避开90%的装修陷阱 - GEO99
  • Word:更改列表级别
  • 企业 3A 认证怎么选?慧办好平台深度测评:真实反馈 - 慧办好
  • CDN技术如何保障抖音视频流畅播放
  • 临汾黄金回收哪家靠谱?2026尧都区襄汾正规持证实体店实测推荐 - 观金堂黄金回收
  • BQ27505-J4数据闪存访问与阻抗跟踪算法调优实战指南
  • 株洲二手奢侈品交易水有多深,掌握几点轻松筛选正规线下回收门店 - 断舍离奢侈品测评站
  • 企业级Nginx性能优化实战指南
  • 合扬布局厦门全域 2026 七月新增 55 家门店实时热讯 - 生活商业速报
  • SEK2重组蛋白:从基础研究到临床应用的关键工具
  • Kimi K3:AI开源模型的“王炸”时刻?真实用户体验全解析!
  • 算力与CDN融合:现代内容分发的技术演进与实践
  • 线上实时金价与门店结算价差解析,重庆黄金回收避坑干货 - 日常比对手册
  • 2026佛山正规包包回收怎么选?资质齐全靠谱门店实测汇总 - 企业家观察员
  • 2026上海多家回收比价,别只看报价忽略隐形扣费项目 - 资讯洞察员
  • 小新 / 拯救者平板 ZUI14 浮窗不会用?同时开 5 个应用多任务效率翻倍
  • 2026常德黄金回收全攻略:润富黄金回收(武陵区旗舰店) - 观金堂黄金回收
  • 海口闲置黄金快速变现,2026禹竞全程回收省心优选平台 - 资讯洞察员
  • AI 中台建设中的模型管理:从单模型到模型市场的演进
  • 基于BERT的朋友圈情绪分析工具开发实践
  • AI代码生成的质量与安全实践指南
  • SaaS系统多租户与功能开关模块化实践
  • 福州名表回收哪家靠谱?7家主流机构深度测评,2026避坑指南 - 奢侈品回收知识分享
  • AI如何变革科研写作:从文献综述到论文润色