Connection using old pairing information saved

I am running an experiment to use a static keys for pairing information without breaking the existing flow of pairing/bonding.
What I am doing is I am storing the pairing info of my central device and storing it into a structure and then erasing the flash to remove those information, and after reset I am retrieving those bonding information and connecting again using the same central devices but I am getting "Peer removed bonding info" response on my phone.

void store_ltk_in_zephyr(void)
{
    int id, err;
    struct bt_keys pairing_info = {
    .addr = {
        .type = BT_ADDR_LE_PUBLIC,
        .a.val = {0x43,0x82,0x5E,0xC7,0xE8,0xF4,0xFD}
    },
    .irk = {0x8A, 0x27, 0x1E, 0xA7, 0x92, 0x2A, 0xF0, 0x15, 0x41, 0x69, 0x48, 0xDD, 0xC0, 0x7E, 0xDD, 0xF7},
    .ltk = {
        .val = {0xc0, 0xe6, 0x9a, 0x0a, 0xf7, 0x4b, 0xdc, 0xb7, 0x7d, 0x23, 0xf4, 0xb4, 0x89, 0x8d, 0x96, 0x02},
        .ediv = {0x00,0x00},
        .rand = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
      }
    };

    // Store the keys using the settings API
    err = bt_keys_store(&pairing_info);
    if (err) {
        printk("Failed to store keys (err %d)\n", err);
    } else {
        printk("Keys stored successfully\n");
    }
}


In main, I am calling like this to load the info onto the flash- 

  settings_subsys_init();
  //smp_bt_register();
	bt_conn_auth_cb_register(&auth_cb_display);
  bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
	err = bt_enable(NULL);
	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
    k_sleep(K_MSEC(100));
		err = bt_enable(NULL);                                      //Trying one more time after this system reset
    if(err) NVIC_SystemReset();
	}
  store_ltk_in_zephyr();
  if (IS_ENABLED(CONFIG_SETTINGS)) {
    settings_load();
  }


And on connect I am using like this-
  bt_conn_set_security(conn, BT_SECURITY_L1|BT_SECURITY_FORCE_PAIR);


Do let me know, how can I connect with the same bonding info which I have made a copy of from the same bonding structure.

Parents
  • Hello,

    To troubleshoot this, I recommend you start by enabling CONFIG_BT_LOG_SNIFFER_INFO to have the keys printed on boot. This would help confirm us confirm if they keys were successfully stored or not.

    Best regards,

    Vidar

  • I am reading the pairing info using nrfjprog --memrd 0xfe000 -n 1024, as I know its taking the info from the settings page and the address of the page is this -

    Not getting any logs related to bonding on boot using CONFIG_BT_LOG_SNIFFER_INFO.

  • Here is an updated version of the pre_shared_bond_set() function which should handle legacy pairing:

    static void pre_shared_bond_set(void)
    {
    	int err;
    	int bond_num = 0;
    	struct bt_keys *pairing_info;
    
    	// true if pm_peer_data_bonding.own_ltk.enc_info.ltk.lesc == 0
    	bool legacy_pairing = true;
    
    	bt_foreach_bond(BT_ID_DEFAULT, bond_cb, &bond_num);
    
    	if (bond_num) {
    		return;
    	}
    
    	//pm_peer_data_bonding.peer_ble_id.id_addr_info
    	bt_addr_le_t addr = {
    	    .type = BT_ADDR_LE_PUBLIC,
    	    .a.val = {0x23, ....}
    	};
    
    	//pm_peer_data_bonding.own_ltk.enc_info.ltk
    	struct bt_ltk ltk = {
    	    .val = {0x0e, 0x31, 0xed, 0xa8, 0x6a, 0xdd, 0x9f, 0xba, 0xd5, 0xcc, 0xb7,
    	            0x78, 0x4b, 0xb7, 0xaf, 0xee},
    	    .ediv = {0x02,0x56}, // remember to check the byte order
    	    .rand = {0xcc, 0x57, 0x52, 0xee, 0x4c, 0x5a, 0xa6, 0xc6}		
    	};
    	
    	//pm_peer_data_bonding.peer_ble_id.id_info
    	struct bt_irk irk = {
    		.val = {0xd6, ....},
    		.rpa.val = {0}		
    	}; 
    
    	pairing_info = bt_keys_get_addr(0, &addr);
    	if (pairing_info == NULL) {
    		LOG_ERR("Failed to get keyslot");
    		return;
    	}
    
    	if (legacy_pairing) {
    		memcpy(&pairing_info->periph_ltk, &ltk, sizeof(pairing_info->periph_ltk));
    	} 
    	else {
    		memcpy(&pairing_info->ltk, &ltk, sizeof(pairing_info->ltk));
    	}
    	
    	memcpy(&pairing_info->irk, &irk, sizeof(pairing_info->irk));
    
    	if (legacy_pairing) {
    		pairing_info->flags = 0;
    		pairing_info->enc_size = BT_SMP_MAX_ENC_KEY_SIZE;
    		pairing_info->keys = BT_KEYS_IRK | BT_KEYS_PERIPH_LTK;
    	}
    	else {
    		pairing_info->flags = BT_KEYS_SC;
    		pairing_info->enc_size = BT_SMP_MAX_ENC_KEY_SIZE;
    		pairing_info->keys = BT_KEYS_IRK | BT_KEYS_LTK_P256;
    	}
    
    
    	err = bt_keys_store(pairing_info);
        if (err) {
            LOG_ERR("Failed to store keys (err %d)\n", err);
        } else {
            LOG_INF("Keys stored successfully\n");
        }
    
    }

    I have also noted down which elements in the pm_peer_data_bonding_t struct you should use to populate keys struct with.

  •  These changes I already had in my code, been testing and sending you logs from that only-

    static void pre_shared_bond_set(void)
    {
    	int err;
    	int bond_num = 0;
    	struct bt_keys *pairing_info;
    
    	bt_foreach_bond(BT_ID_DEFAULT, bond_cb, &bond_num);
    
    	if (bond_num) {
    		return;
    	}
    
    	bt_addr_le_t addr = {
    	    .type = BT_ADDR_LE_PUBLIC,
    	    .a.val = {0x43,0x82,0x5E,0xC7,0xE8,0xF4}
    	};
    
    	struct bt_ltk ltk = {
    	    .val = {0x31, 0x30, 0xca, 0x16, 0x8d, 0x53, 0x73, 0x7c, 0x89, 0xee, 0x42, 0x58, 0x61, 0x47, 0x03, 0xb4},//{0xcb, 0xea, 0xd5, 0xea, 0xe1, 0xab, 0x7c, 0x36, 0x91, 0x1b, 0xe7, 0xd3, 0x31, 0xd1, 0xf8, 0xbc},
    	    .ediv = {0},
    	    .rand = {0}		
    	};
    
    	struct bt_irk irk = {
    		.val = {0xF7, 0xDD, 0x7E, 0xC0, 0xDD, 0x48, 0x69, 0x41, 0x15, 0xF0, 0x2A, 0x92, 0xA7, 0x1E, 0x27, 0x8A},
    		.rpa.val = {0}		
    	}; 
    
      /**Copying the retrieved values from the memory onto the relevant array to pass the pairing infos*/
      memcpy(&addr.a.val[0],keys_addr,6);
      memcpy(&irk.val[0],irk_val,16);
      memcpy(&ltk.val[0],ltk_val,16);
      memcpy(&ltk.ediv[0],ltk_ediv,2);
      memcpy(&ltk.rand[0],ltk_rand,8);
    
    	pairing_info = bt_keys_get_addr(0, &addr);
    	if (pairing_info == NULL) {
    		printk("Failed to get keyslot\n");
    	}
    
      memcpy(&pairing_info->periph_ltk, &ltk, sizeof(pairing_info->ltk));
    	//memcpy(&pairing_info->ltk, &ltk, sizeof(pairing_info->ltk));
    	memcpy(&pairing_info->irk, &irk, sizeof(pairing_info->irk));
    
    	pairing_info->flags = 0;
    	pairing_info->enc_size = 16;
    	pairing_info->keys = BT_KEYS_IRK | BT_KEYS_PERIPH_LTK;
    
    	err = bt_keys_store(pairing_info);
        if (err) {
            printk("Failed to store keys (err %d)\n", err);
        } else {
            printk("Keys stored successfully\n");
        }
    
    }
    
    void reverse_copy_bytes(uint8_t* src, uint8_t* dst, size_t size) {
        if (size != 2) {
            printf("Error: Function is intended for size 2.\n");
            return;
        }
    
        // Reverse the bytes during copy
        dst[0] = src[1];
        dst[1] = src[0];
    }
    
    void retrieve_pairing_keys(void)
    {
      const volatile uint32_t *ptr = (const volatile uint32_t *)(0xf5100); //Workaround to read back the pairing info from the old SDK
      uint8_t reversed_ltk_ediv[2]; // Array to store reversed bytes
      uint8_t reversed_ltk_val[16];
      uint8_t reversed_ltk_rand[8];
      memcpy(&irk_val[0],((uint8_t*)ptr),16);
      memcpy(&keys_addr[0],((uint8_t*)ptr+16+1),6);
      memcpy(&reversed_ltk_val[0],((uint8_t*)ptr+16+6+1),16);
      memcpy(&reversed_ltk_ediv[0],((uint8_t*)ptr+16+6+16+1+2),2);
      memcpy(&reversed_ltk_rand[0],((uint8_t*)ptr+16+6+16+2+1+2),8);
      // memcpy(&ltk_val[0],((uint8_t*)ptr+16+6+1),16);
      // memcpy(&ltk_ediv[0],((uint8_t*)ptr+16+6+16+1+2),2);
      // memcpy(&ltk_rand[0],((uint8_t*)ptr+16+6+16+2+1+2),8);  
      // Perform the reverse copy
      reverse_bytes(&ltk_ediv[0], &reversed_ltk_ediv[0], 2);
      reverse_bytes(&ltk_val[0], &reversed_ltk_val[0], 16);
      reverse_bytes(&ltk_rand[0], &reversed_ltk_rand[0], 8);
      for(uint8_t i =0;i<16;i++)
      {
        printk(" %02x",reversed_ltk_val[i]);
      }
      printk("Successfully copied pairing info from the memory\n");
    }


    Needed help from the nrf5SDK side, if anything in copying I missed. I will also share ble sniffer trace tomorrow(But I dont remember seeing EDIV and RAND related logs in sniffer trace ,btw I use wireshark for BLE sniffing).

  • Just read the comments in the code, I`ll test with these changes and let you know.
    Thanks

  • Here is an updated version of the pre_shared_bond_set() function which should handle legacy pairing

    Still disconnecting after the changes,but the EDIV and RAND are matching now-

    00> 8a 27 1e a7 92 2a f0 15 41 69 48 dd c0 7e dd f7 [00:00:08.474,365] <inf> bt_keys: Legacy LTK: 0x81ee0de3848ec6bf4d9d9d4cb98de928 (peripheral)
    00> Connected
    00> [00:00:08.672,668] <dbg> bt_keys: bt_keys_find: type 32 F4:E8:C7:5E:82:43 (public)
    00> [00:00:08.672,851] <dbg> bt_keys: bt_keys_find: type 1 F4:E8:C7:5E:82:43 (public)
    00> [00:00:08.672,851] <dbg> bt_smp: bt_smp_request_ltk: Its inside this loop now 3
    00> 
    00> RAND from key : 12030894171999848549
    00> RAND from HCI buf: 12030894171999848549
    00> EDIV from key : 64060
    00> EDIV from HCI buf : 64060
    00> [00:00:08.762,512] <dbg> bt_smp: bt_smp_disconnected: chan 0x20003ce8 cid 0x0006
    00> [00:00:08.762,847] <dbg> bt_keys: bt_keys_find_addr: F4:E8:C7:5E:82:43 (public)
    00> [00:00:08.763,031] <dbg> bt_keys: bt_keys_find_addr: F4:E8:C7:5E:82:43 (public)
    00> Disconnected (reason 0x13)

  • Still disconnecting after the changes,but the EDIV and RAND are matching now-

     Recheck it again by simply copying the values directly in the structure and still not able to connect.

    00> 8a 27 1e a7 92 2a f0 15 41 69 48 dd c0 7e dd f7 [00:00:08.060,668] <inf> bt_keys: Legacy LTK: 0x863be25911d3af286101dad5dab01db1 (peripheral)
    00> Connected
    00> [00:00:08.060,699] <dbg> bt_smp: smp_send_security_req: 
    00> [00:00:08.060,882] <dbg> bt_keys: bt_keys_get_addr: F4:E8:C7:5E:82:43 (public)
    00> [00:00:08.061,065] <dbg> bt_smp: smp_init: prnd 37a95cfba06b8f8ed4dbabde26d4bdc6
    00> [00:00:08.228,851] <dbg> bt_smp: bt_smp_request_ltk: Its inside this loop now 3
    00> 
    00> RAND from key : 14895755191182585488
    00> RAND from HCI buf: 14895755191182585488
    00> EDIV from key : 2479
    00> EDIV from HCI buf : 2479

    Logs from nrf5SDK version-

    00>  F7 DD 7E C0 DD 48 69 41 15 F0 2A 92 A7 1E 27 8A<info> app: Address:
    00>
    00>  43 82 5E C7 E8 F4 42<info> app: LTK:
    00>
    00>  B1 1D B0 DA D5 DA 01 61 28 AF D3 11 59 E2 3B 86<info> app: LTK others:
    00>
    00> <info> app:  9AF
    00>
    00> <info> app: RAND:
    00>
    00>  90 6E 9E DF 6C 5A B8 CE

Reply
  • Still disconnecting after the changes,but the EDIV and RAND are matching now-

     Recheck it again by simply copying the values directly in the structure and still not able to connect.

    00> 8a 27 1e a7 92 2a f0 15 41 69 48 dd c0 7e dd f7 [00:00:08.060,668] <inf> bt_keys: Legacy LTK: 0x863be25911d3af286101dad5dab01db1 (peripheral)
    00> Connected
    00> [00:00:08.060,699] <dbg> bt_smp: smp_send_security_req: 
    00> [00:00:08.060,882] <dbg> bt_keys: bt_keys_get_addr: F4:E8:C7:5E:82:43 (public)
    00> [00:00:08.061,065] <dbg> bt_smp: smp_init: prnd 37a95cfba06b8f8ed4dbabde26d4bdc6
    00> [00:00:08.228,851] <dbg> bt_smp: bt_smp_request_ltk: Its inside this loop now 3
    00> 
    00> RAND from key : 14895755191182585488
    00> RAND from HCI buf: 14895755191182585488
    00> EDIV from key : 2479
    00> EDIV from HCI buf : 2479

    Logs from nrf5SDK version-

    00>  F7 DD 7E C0 DD 48 69 41 15 F0 2A 92 A7 1E 27 8A<info> app: Address:
    00>
    00>  43 82 5E C7 E8 F4 42<info> app: LTK:
    00>
    00>  B1 1D B0 DA D5 DA 01 61 28 AF D3 11 59 E2 3B 86<info> app: LTK others:
    00>
    00> <info> app:  9AF
    00>
    00> <info> app: RAND:
    00>
    00>  90 6E 9E DF 6C 5A B8 CE

Children
  •  I have made it work now, whole copy LTK,EDIV and RAND endianess was the issue.

    But after this device got conencted but there is one more major issue, services and characteristics are still showing up like nRFSDK one, as in the order of services and characteristics are different on nRFSDK version and the one on Zephyr.
    But the UUIDs are same, with this issue if I am trying to read the relevant values then I am seeing garbage values.

    Two of the services which were meant for only nRF5SDK versions i.e., Buttonloess DFU are still visible on the Zephyr version, I think the services are not getting refreshed.

  • This is what is known as attribute caching. Basically the attribute table from the previous application has been cached by the your GATT Client. About attribute caching from the Core spec:

    Did you existing nRF5 SDK based application include the Service Changed characteristic? In that case, you should be able to send a service changed indication to trigger the client to perform a new service discovery. 

  • Did you existing nRF5 SDK based application include the Service Changed characteristic? In that case, you should be able to send a service changed indication to trigger the client to perform a new service discovery. 

    Yes we have one.
    What is the API for indicating the service change, I didn`t find any online and have enabled the CONFIG_BT_GATT_SERVICE_CHANGED=y also.

  •  I have implemented this part too but nRF Connect application on iOS is not changing the discovery

    static void sc_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
    {
        bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);
        printk("Service Changed notifications %s\n", notif_enabled ? "enabled" : "disabled");
    }
    
    BT_GATT_SERVICE_DEFINE(sc_svc,
        BT_GATT_PRIMARY_SERVICE(BT_UUID_GATT),
        BT_GATT_CHARACTERISTIC(BT_UUID_GATT_SC, BT_GATT_CHRC_INDICATE, BT_GATT_PERM_NONE,
                               NULL, NULL, sc_value),
        BT_GATT_CCC(sc_ccc_cfg_changed,BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
    );
    
    void notify_service_changed(struct bt_conn *conn)
    {
        //struct bt_conn *conn = NULL;  // Update this to point to the correct connection if needed
        uint16_t start_handle = 0x0001; // Start handle of the affected range
        uint16_t end_handle = 0xFFFF;   // End handle of the affected range
    
        sc_value[0] = start_handle & 0xFF;
        sc_value[1] = (start_handle >> 8) & 0xFF;
        sc_value[2] = end_handle & 0xFF;
        sc_value[3] = (end_handle >> 8) & 0xFF;
    
        int err = bt_gatt_notify(conn, &sc_svc.attrs[1], sc_value, sizeof(sc_value));
        if (err) {
            printk("Service Changed notification failed (err %d)\n", err);
        } else {
            printk("Service Changed notification sent\n");
        }
    }

  •  I have tried to expose the sc_indicate(0x00010xffff); and use it on the connected callback so that the services get refreshed but dont see anything changing on nRF Connect application on iOS with these changes.

    static void connected(struct bt_conn *conn, uint8_t err) {
      char addr[BT_ADDR_LE_STR_LEN];
      const bt_addr_le_t *addr_info = bt_conn_get_dst(conn);
      sc_indicate(0x0001, 0xffff);
      start_notif_timer();                                        //Starting timer to notfy for battery data after 5 seconds
      atomic_set(&is_advertising,0);
      atomic_set(&is_connected,1);
      wdt_wdtFeed();
      k_timer_stop(&fast_adv_timer);
      k_timer_start(&wdttimer_feed, K_SECONDS(AVDERTISING_UPDATE_SEC), K_SECONDS(AVDERTISING_UPDATE_SEC));
      k_timer_stop(&advertising_timer);
      //Checking connection count and referencing local variable around that
      if(!local_connection){
        local_connection = bt_conn_ref(conn);
      }
      if (is_first_conn)    hrm_sensor_indication_off();        //Coming out of first time connection indication
      static struct bt_gatt_exchange_params exchange_params;
    	exchange_params.func = exchange_func;
    	int res = bt_gatt_exchange_mtu(conn, &exchange_params);
    	if (err) {
    		printk("Connection failed (err 0x%02x)\n", err);
    	} else {
    		printk("Connected\n");
    	}
      // if (bt_conn_set_security(conn, BT_SECURITY_L1)) {
    	// 	printk("Failed to set security : %d\n", bonded_device_count); 
    	// }
      // bt_set_bondable(true);
    }

Related