180 std::vector<uint8_t> &payload)
const {
181 if (data.size() <= 1 + BTHOME_COUNTER_SIZE + BTHOME_MIC_SIZE) {
182 ESP_LOGVV(TAG,
"Encrypted BTHome payload too short: %zu", data.size());
186 const size_t ciphertext_size = data.size() - 1 - BTHOME_COUNTER_SIZE - BTHOME_MIC_SIZE;
187 payload.resize(ciphertext_size);
189 std::array<uint8_t, MAC_ADDRESS_SIZE> mac{};
190 for (
size_t i = 0; i < MAC_ADDRESS_SIZE; i++) {
191 mac[i] = (source_address >> ((MAC_ADDRESS_SIZE - 1 - i) * 8)) & 0xFF;
194 std::array<uint8_t, BTHOME_NONCE_SIZE> nonce{};
195 memcpy(nonce.data(), mac.data(), mac.size());
199 memcpy(nonce.data() + 9, &data[data.size() - BTHOME_COUNTER_SIZE - BTHOME_MIC_SIZE], BTHOME_COUNTER_SIZE);
201 const uint8_t *ciphertext = data.data() + 1;
202 const uint8_t *mic = data.data() + data.size() - BTHOME_MIC_SIZE;
204#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
207 static constexpr size_t MAX_CT_WITH_TAG = 32;
208 uint8_t ct_with_tag[MAX_CT_WITH_TAG];
209 size_t ct_with_tag_size = ciphertext_size + BTHOME_MIC_SIZE;
210 memcpy(ct_with_tag, ciphertext, ciphertext_size);
211 memcpy(ct_with_tag + ciphertext_size, mic, BTHOME_MIC_SIZE);
213 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
214 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
215 psa_set_key_bits(&attributes, BTHOME_BINDKEY_SIZE * 8);
216 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
217 psa_set_key_algorithm(&attributes, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, BTHOME_MIC_SIZE));
219 mbedtls_svc_key_id_t key_id;
220 if (psa_import_key(&attributes, this->
bindkey_, BTHOME_BINDKEY_SIZE, &key_id) != PSA_SUCCESS) {
221 ESP_LOGVV(TAG,
"psa_import_key() failed.");
225 size_t plaintext_length;
226 psa_status_t
status = psa_aead_decrypt(key_id, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, BTHOME_MIC_SIZE),
227 nonce.data(), nonce.size(),
nullptr, 0, ct_with_tag, ct_with_tag_size,
228 payload.data(), ciphertext_size, &plaintext_length);
229 psa_destroy_key(key_id);
230 if (
status != PSA_SUCCESS || plaintext_length != ciphertext_size) {
231 ESP_LOGVV(TAG,
"BTHome decryption failed.");
235 mbedtls_ccm_context ctx;
236 mbedtls_ccm_init(&ctx);
238 int ret = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, this->
bindkey_, BTHOME_BINDKEY_SIZE * 8);
240 ESP_LOGVV(TAG,
"mbedtls_ccm_setkey() failed.");
241 mbedtls_ccm_free(&ctx);
245 ret = mbedtls_ccm_auth_decrypt(&ctx, ciphertext_size, nonce.data(), nonce.size(),
nullptr, 0, ciphertext,
246 payload.data(), mic, BTHOME_MIC_SIZE);
247 mbedtls_ccm_free(&ctx);
249 ESP_LOGVV(TAG,
"BTHome decryption failed (ret=%d).", ret);
262 const auto &data = service_data.
data;
263 if (data.size() < 2) {
264 ESP_LOGVV(TAG,
"BTHome data too short: %zu", data.size());
268 const uint8_t adv_info = data[0];
269 const bool is_encrypted = adv_info & 0x01;
270 const bool mac_included = adv_info & 0x02;
271 const bool is_trigger_based = adv_info & 0x04;
272 const uint8_t version = (adv_info >> 5) & 0x07;
274 if (version != 0x02) {
275 ESP_LOGVV(TAG,
"Unsupported BTHome version %u", version);
280 bool address_matches = source_address == this->
address_;
281 if (!is_encrypted && mac_included && data.size() >= 7) {
282 uint64_t advertised_address = 0;
283 for (
int i = 5; i >= 0; i--) {
284 advertised_address = (advertised_address << 8) | data[1 + i];
286 address_matches = address_matches || advertised_address == this->
address_;
290 if (address_matches) {
291 char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
292 ESP_LOGE(TAG,
"Encrypted BTHome frame received but no bindkey configured for %s",
299 if (address_matches) {
300 char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
301 ESP_LOGE(TAG,
"Unencrypted BTHome frame received with bindkey configured for %s",
306 std::vector<uint8_t> decrypted_payload;
307 const uint8_t *payload =
nullptr;
312 char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
313 ESP_LOGVV(TAG,
"Failed to decrypt BTHome frame from %s", device.
address_str_to(addr_buf));
316 payload = decrypted_payload.data();
319 payload = data.data() + 1;
325 ESP_LOGVV(TAG,
"BTHome payload missing MAC address");
329 for (
int i = 5; i >= 0; i--) {
330 source_address = (source_address << 8) | payload[i];
336 char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
337 if (source_address != this->
address_) {
338 ESP_LOGVV(TAG,
"BTHome frame from unexpected device %s", format_mac_address(addr_buf, source_address));
343 ESP_LOGVV(TAG,
"BTHome payload empty after header");
347 bool reported =
false;
349 uint8_t last_type = 0;
352 const uint8_t obj_type = payload[offset++];
353 size_t value_length = 0;
354 bool has_length_byte = obj_type == 0x53;
356 if (has_length_byte) {
360 value_length = payload[offset++];
362 if (!get_bthome_value_length(obj_type, value_length)) {
363 ESP_LOGVV(TAG,
"Unknown BTHome object 0x%02X", obj_type);
368 if (value_length == 0) {
373 ESP_LOGVV(TAG,
"BTHome object length exceeds payload");
377 const uint8_t *value = &payload[offset];
378 offset += value_length;
380 if (obj_type < last_type) {
381 ESP_LOGVV(TAG,
"BTHome objects not in ascending order");
383 last_type = obj_type;
387 const uint8_t packet_id = value[0];
388 if (this->
last_packet_id_.has_value() && *this->last_packet_id_ == packet_id) {
431 ESP_LOGD(TAG,
"BTHome data%sfrom %s", is_trigger_based ?
" (triggered) " :
" ", device.
address_str_to(addr_buf));