Resolve BLE address using Zephry

Hello,

I'm using VS Code and Zephyr to develeop a application for the nRF52840. I am currently scanning for devices, however the device i am looking for uses a random private resolvable address.

Currently i already have a hardcoded list of IRK values. The BLE addresses found while scanning are processed by the device_found() function.
However i cannot find any method to check if these match any of my IRK values using Zephyr. I know that some SoftDevices have this option, however they are not available in vscode.

Do you have any recommendations on how to approach this?

Please see my code below:

static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad)
{
	if (type == BT_GAP_ADV_TYPE_ADV_SCAN_IND || type == BT_GAP_ADV_TYPE_ADV_IND)
	{
		struct scan_result res = {
			.addr = addr,
			.rssi = rssi,
		};

		bt_data_parse(ad, eir_found, &res);
	}
}

static void start_scan(void)
{
	int err;

	struct bt_le_scan_param scan_param = {
		.type = BT_LE_SCAN_TYPE_PASSIVE,
		.options = BT_LE_SCAN_OPT_NONE,
		.interval = BT_GAP_SCAN_FAST_INTERVAL,
		.window = BT_GAP_SCAN_FAST_WINDOW,
	};

	err = bt_le_scan_start(&scan_param, device_found);
	if (err)
	{
		printk("Scanning failed to start (err %d)\n", err);
		return;
	}

	printk("Scanning successfully started\n");
}

Parents
  • Hi,

    If you have a bond with the device, the IRK will be added to the filter accept list when you use bt_le_filter_accept_list_add(). However, there is no API for adding just IRK's. Technically it should be possible to modify the host implementation to support it, but I do not have any suggestion on how to do it. Also, the AAR is reserved by the stack.

    Perhaps you can scan for any device and do the address resolution in SW? And then, try to connect to that specific address? You can take a look at the implementation of im_address_resolve() in id_manager.c the old nRF5 SDK, which does this.

  • Thank you very much for the information. I currently have a working implementation by scanning for all devices and resolving the addresses manually. I have implemented the address_resolve() function myself with inspiration from the im_address_resolve() in id_manager.c and using the PSA crypto library for the ECB encryption.

  • Hi Jarno, 

    I also need to check whether the broadcasting  random private resolvable BLE Address is previously bonded peer using  VS Code and Zephyr recently. 

    Could you please share your address_resolve() function for reference?

Reply Children
  • Sure, here is the code i used:

    #include <psa/crypto.h>
    #include <psa/crypto_extra.h>
    
    void reverse(uint8_t *p_data, uint8_t len)
    {
    	uint8_t temp;
    	for (uint32_t i = 0; i < len / 2; i++)
    	{
    		temp = p_data[i];
    		p_data[i] = p_data[len - 1 - i];
    		p_data[len - 1 - i] = temp;
    	}
    }
    
    // IRKs
    uint8_t irks[NUM_IRKS][16] = {
    	{}, // Insert IRKs here
    	{}, 
    };
    
    psa_key_id_t key_ids[NUM_IRKS];
    
    void setup_key(uint8_t const *key, mbedtls_svc_key_id_t *key_id)
    {
    	psa_status_t status;
    	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    	psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
    	psa_set_key_algorithm(&attributes, PSA_ALG_ECB_NO_PADDING);
    	psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
    	psa_set_key_bits(&attributes, 16 * 8);
    	psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
    
    	uint8_t ecb_key[16];
    	for (uint32_t i = 0; i < 16; i++)
    	{
    		ecb_key[i] = key[16 - 1 - i];
    	}
    
    	status = psa_import_key(&attributes, ecb_key, 16, key_id);
    	if (status != PSA_SUCCESS)
    	{
    		printk("PSA key import failed\n");
    		return;
    	}
    }
    
    // Function to perform ECB encryption
    void encrypt_ecb(uint8_t *input, uint8_t *output, mbedtls_svc_key_id_t key_id)
    {
    	size_t ciphertext_size;
    	psa_status_t status;
    
    	status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, input, 16, output, 16, &ciphertext_size);
    	if (status != PSA_SUCCESS)
    	{
    		printk("PSA encryption failed\n");
    		return;
    	}
    }
    
    void ah(mbedtls_svc_key_id_t key_id, uint8_t *p_r, uint8_t *p_local_hash)
    {
    	uint8_t ecb_plaintext[16];
    	uint8_t ecb_ciphertext[16];
    
    	memset(ecb_plaintext, 0, 16 - 3);
    
    	for (uint32_t i = 0; i < 3; i++)
    	{
    		ecb_plaintext[16 - 1 - i] = p_r[i];
    	}
    
    	encrypt_ecb(ecb_plaintext, ecb_ciphertext, key_id);
    
    	for (uint32_t i = 0; i < 3; i++)
    	{
    		p_local_hash[i] = ecb_ciphertext[16 - 1 - i];
    	}
    }
    
    int resolve_address(uint8_t *p_addr)
    {
    
    	uint8_t hash[3];
    	uint8_t local_hash[3];
    	uint8_t prand[3];
    
    	memcpy(hash, p_addr, 3);
    	memcpy(prand, &p_addr[3], 3);
    
    	for (int i = 0; i < NUM_IRKS; i++)
    	{
    		ah(key_ids[i], prand, local_hash);
    		if (memcmp(hash, local_hash, 3) == 0)
    		{
    			return i;
    		}
    	}
    	return -1;
    }
    
    void main(void)
    {
    
    	for (int i = 0; i < NUM_IRKS; i++)
    	{
    		reverse(irks[i], 16);
    		setup_key(irks[i], &key_ids[i]);
    	}
    	
    	// Rest of the main function
    }

    I took me quite a while to figure this all out, hope this helps you out as well!

  • Hi Jarno, really thanks for your sharing.^^

Related