Add IRK support to allow tracking of devices with random MAC addresses (#6335)

* Add IRK support to allow tracking of devices with random MAC addresses

* make CONF_IRK a local definition

* Add tests

---------

Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com>
This commit is contained in:
chbmuc 2024-03-10 23:58:50 +01:00 committed by GitHub
parent d4489ac373
commit 247baa414a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 86 additions and 2 deletions

View file

@ -10,6 +10,8 @@ from esphome.const import (
CONF_MIN_RSSI, CONF_MIN_RSSI,
) )
CONF_IRK = "irk"
DEPENDENCIES = ["esp32_ble_tracker"] DEPENDENCIES = ["esp32_ble_tracker"]
ble_presence_ns = cg.esphome_ns.namespace("ble_presence") ble_presence_ns = cg.esphome_ns.namespace("ble_presence")
@ -34,6 +36,7 @@ CONFIG_SCHEMA = cv.All(
.extend( .extend(
{ {
cv.Optional(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
cv.Optional(CONF_IRK): cv.uuid,
cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t, cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t,
cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t, cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t,
@ -45,7 +48,9 @@ CONFIG_SCHEMA = cv.All(
) )
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
.extend(cv.COMPONENT_SCHEMA), .extend(cv.COMPONENT_SCHEMA),
cv.has_exactly_one_key(CONF_MAC_ADDRESS, CONF_SERVICE_UUID, CONF_IBEACON_UUID), cv.has_exactly_one_key(
CONF_MAC_ADDRESS, CONF_IRK, CONF_SERVICE_UUID, CONF_IBEACON_UUID
),
_validate, _validate,
) )
@ -61,6 +66,10 @@ async def to_code(config):
if mac_address := config.get(CONF_MAC_ADDRESS): if mac_address := config.get(CONF_MAC_ADDRESS):
cg.add(var.set_address(mac_address.as_hex)) cg.add(var.set_address(mac_address.as_hex))
if irk := config.get(CONF_IRK):
irk = esp32_ble_tracker.as_hex_array(str(irk))
cg.add(var.set_irk(irk))
if service_uuid := config.get(CONF_SERVICE_UUID): if service_uuid := config.get(CONF_SERVICE_UUID):
if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format): if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format):
cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid))) cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid)))

View file

@ -6,6 +6,16 @@
#ifdef USE_ESP32 #ifdef USE_ESP32
#ifdef USE_ARDUINO
#include "mbedtls/aes.h"
#include "mbedtls/base64.h"
#endif
#ifdef USE_ESP_IDF
#define MBEDTLS_AES_ALT
#include <aes_alt.h>
#endif
namespace esphome { namespace esphome {
namespace ble_presence { namespace ble_presence {
@ -17,6 +27,10 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
this->match_by_ = MATCH_BY_MAC_ADDRESS; this->match_by_ = MATCH_BY_MAC_ADDRESS;
this->address_ = address; this->address_ = address;
} }
void set_irk(uint8_t *irk) {
this->match_by_ = MATCH_BY_IRK;
this->irk_ = irk;
}
void set_service_uuid16(uint16_t uuid) { void set_service_uuid16(uint16_t uuid) {
this->match_by_ = MATCH_BY_SERVICE_UUID; this->match_by_ = MATCH_BY_SERVICE_UUID;
this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint16(uuid); this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint16(uuid);
@ -62,6 +76,13 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
return true; return true;
} }
break; break;
case MATCH_BY_IRK:
if (resolve_irk_(device.address_uint64(), this->irk_)) {
this->publish_state(true);
this->found_ = true;
return true;
}
break;
case MATCH_BY_SERVICE_UUID: case MATCH_BY_SERVICE_UUID:
for (auto uuid : device.get_service_uuids()) { for (auto uuid : device.get_service_uuids()) {
if (this->uuid_ == uuid) { if (this->uuid_ == uuid) {
@ -100,10 +121,11 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
float get_setup_priority() const override { return setup_priority::DATA; } float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID }; enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_IRK, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID };
MatchType match_by_; MatchType match_by_;
uint64_t address_; uint64_t address_;
uint8_t *irk_;
esp32_ble_tracker::ESPBTUUID uuid_; esp32_ble_tracker::ESPBTUUID uuid_;
@ -117,6 +139,43 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
bool check_ibeacon_minor_{false}; bool check_ibeacon_minor_{false};
bool check_minimum_rssi_{false}; bool check_minimum_rssi_{false};
bool resolve_irk_(uint64_t addr64, const uint8_t *irk) {
uint8_t ecb_key[16];
uint8_t ecb_plaintext[16];
uint8_t ecb_ciphertext[16];
memcpy(&ecb_key, irk, 16);
memset(&ecb_plaintext, 0, 16);
ecb_plaintext[13] = (addr64 >> 40) & 0xff;
ecb_plaintext[14] = (addr64 >> 32) & 0xff;
ecb_plaintext[15] = (addr64 >> 24) & 0xff;
mbedtls_aes_context ctx = {0, 0, {0}};
mbedtls_aes_init(&ctx);
if (mbedtls_aes_setkey_enc(&ctx, ecb_key, 128) != 0) {
mbedtls_aes_free(&ctx);
return false;
}
if (mbedtls_aes_crypt_ecb(&ctx,
#ifdef USE_ARDUINO
MBEDTLS_AES_ENCRYPT,
#elif defined(USE_ESP_IDF)
ESP_AES_ENCRYPT,
#endif
ecb_plaintext, ecb_ciphertext) != 0) {
mbedtls_aes_free(&ctx);
return false;
}
mbedtls_aes_free(&ctx);
return ecb_ciphertext[15] == (addr64 & 0xff) && ecb_ciphertext[14] == ((addr64 >> 8) & 0xff) &&
ecb_ciphertext[13] == ((addr64 >> 16) & 0xff);
}
bool found_{false}; bool found_{false};
}; };

View file

@ -18,3 +18,7 @@ binary_sensor:
ibeacon_major: 100 ibeacon_major: 100
ibeacon_minor: 1 ibeacon_minor: 1
name: BLE Test iBeacon Presence name: BLE Test iBeacon Presence
- platform: ble_presence
irk: 1234567890abcdef1234567890abcdef
name: "ESP32 BLE Tracker with Identity Resolving Key"

View file

@ -18,3 +18,7 @@ binary_sensor:
ibeacon_major: 100 ibeacon_major: 100
ibeacon_minor: 1 ibeacon_minor: 1
name: BLE Test iBeacon Presence name: BLE Test iBeacon Presence
- platform: ble_presence
irk: 1234567890abcdef1234567890abcdef
name: "ESP32 BLE Tracker with Identity Resolving Key"

View file

@ -18,3 +18,7 @@ binary_sensor:
ibeacon_major: 100 ibeacon_major: 100
ibeacon_minor: 1 ibeacon_minor: 1
name: BLE Test iBeacon Presence name: BLE Test iBeacon Presence
- platform: ble_presence
irk: 1234567890abcdef1234567890abcdef
name: "ESP32 BLE Tracker with Identity Resolving Key"

View file

@ -18,3 +18,7 @@ binary_sensor:
ibeacon_major: 100 ibeacon_major: 100
ibeacon_minor: 1 ibeacon_minor: 1
name: BLE Test iBeacon Presence name: BLE Test iBeacon Presence
- platform: ble_presence
irk: 1234567890abcdef1234567890abcdef
name: "ESP32 BLE Tracker with Identity Resolving Key"