mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	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:
		| @@ -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))) | ||||||
|   | |||||||
| @@ -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}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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" | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user