179 std::vector<uint8_t> &payload)
const {
180 if (data.size() <= 1 + BTHOME_COUNTER_SIZE + BTHOME_MIC_SIZE) {
181 ESP_LOGVV(TAG,
"Encrypted BTHome payload too short: %zu", data.size());
185 const size_t ciphertext_size = data.size() - 1 - BTHOME_COUNTER_SIZE - BTHOME_MIC_SIZE;
186 payload.resize(ciphertext_size);
188 std::array<uint8_t, MAC_ADDRESS_SIZE> mac{};
189 for (
size_t i = 0; i < MAC_ADDRESS_SIZE; i++) {
190 mac[i] = (source_address >> ((MAC_ADDRESS_SIZE - 1 - i) * 8)) & 0xFF;
193 std::array<uint8_t, BTHOME_NONCE_SIZE> nonce{};
194 memcpy(nonce.data(), mac.data(), mac.size());
198 memcpy(nonce.data() + 9, &data[data.size() - BTHOME_COUNTER_SIZE - BTHOME_MIC_SIZE], BTHOME_COUNTER_SIZE);
200 const uint8_t *ciphertext = data.data() + 1;
201 const uint8_t *mic = data.data() + data.size() - BTHOME_MIC_SIZE;
203#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
206 static constexpr size_t MAX_CT_WITH_TAG = 32;
207 uint8_t ct_with_tag[MAX_CT_WITH_TAG];
208 size_t ct_with_tag_size = ciphertext_size + BTHOME_MIC_SIZE;
209 memcpy(ct_with_tag, ciphertext, ciphertext_size);
210 memcpy(ct_with_tag + ciphertext_size, mic, BTHOME_MIC_SIZE);
212 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
213 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
214 psa_set_key_bits(&attributes, BTHOME_BINDKEY_SIZE * 8);
215 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
216 psa_set_key_algorithm(&attributes, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, BTHOME_MIC_SIZE));
218 mbedtls_svc_key_id_t key_id;
219 if (psa_import_key(&attributes, this->
bindkey_, BTHOME_BINDKEY_SIZE, &key_id) != PSA_SUCCESS) {
220 ESP_LOGVV(TAG,
"psa_import_key() failed.");
224 size_t plaintext_length;
225 psa_status_t
status = psa_aead_decrypt(key_id, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, BTHOME_MIC_SIZE),
226 nonce.data(), nonce.size(),
nullptr, 0, ct_with_tag, ct_with_tag_size,
227 payload.data(), ciphertext_size, &plaintext_length);
228 psa_destroy_key(key_id);
229 if (
status != PSA_SUCCESS || plaintext_length != ciphertext_size) {
230 ESP_LOGVV(TAG,
"BTHome decryption failed.");
234 mbedtls_ccm_context ctx;
235 mbedtls_ccm_init(&ctx);
237 int ret = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, this->
bindkey_, BTHOME_BINDKEY_SIZE * 8);
239 ESP_LOGVV(TAG,
"mbedtls_ccm_setkey() failed.");
240 mbedtls_ccm_free(&ctx);
244 ret = mbedtls_ccm_auth_decrypt(&ctx, ciphertext_size, nonce.data(), nonce.size(),
nullptr, 0, ciphertext,
245 payload.data(), mic, BTHOME_MIC_SIZE);
246 mbedtls_ccm_free(&ctx);
248 ESP_LOGVV(TAG,
"BTHome decryption failed (ret=%d).", ret);
261 const auto &data = service_data.
data;
262 if (data.size() < 2) {
263 ESP_LOGVV(TAG,
"BTHome data too short: %zu", data.size());
267 const uint8_t adv_info = data[0];
268 const bool is_encrypted = adv_info & 0x01;
269 const bool mac_included = adv_info & 0x02;
270 const bool is_trigger_based = adv_info & 0x04;
271 const uint8_t version = (adv_info >> 5) & 0x07;
273 if (version != 0x02) {
274 ESP_LOGVV(TAG,
"Unsupported BTHome version %u", version);
279 bool address_matches = source_address == this->
address_;
280 if (!is_encrypted && mac_included && data.size() >= 7) {
281 uint64_t advertised_address = 0;
282 for (
int i = 5; i >= 0; i--) {
283 advertised_address = (advertised_address << 8) | data[1 + i];
285 address_matches = address_matches || advertised_address == this->
address_;
289 if (address_matches) {
290 char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
291 ESP_LOGE(TAG,
"Encrypted BTHome frame received but no bindkey configured for %s",
298 if (address_matches) {
299 char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
300 ESP_LOGE(TAG,
"Unencrypted BTHome frame received with bindkey configured for %s",
305 std::vector<uint8_t> decrypted_payload;
306 const uint8_t *payload =
nullptr;
311 char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
312 ESP_LOGVV(TAG,
"Failed to decrypt BTHome frame from %s", device.
address_str_to(addr_buf));
315 payload = decrypted_payload.data();
318 payload = data.data() + 1;
324 ESP_LOGVV(TAG,
"BTHome payload missing MAC address");
328 for (
int i = 5; i >= 0; i--) {
329 source_address = (source_address << 8) | payload[i];
335 char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
336 if (source_address != this->
address_) {
337 ESP_LOGVV(TAG,
"BTHome frame from unexpected device %s", format_mac_address(addr_buf, source_address));
342 ESP_LOGVV(TAG,
"BTHome payload empty after header");
346 bool reported =
false;
348 uint8_t last_type = 0;
351 const uint8_t obj_type = payload[offset++];
352 size_t value_length = 0;
353 bool has_length_byte = obj_type == 0x53;
355 if (has_length_byte) {
359 value_length = payload[offset++];
361 if (!get_bthome_value_length(obj_type, value_length)) {
362 ESP_LOGVV(TAG,
"Unknown BTHome object 0x%02X", obj_type);
367 if (value_length == 0) {
372 ESP_LOGVV(TAG,
"BTHome object length exceeds payload");
376 const uint8_t *value = &payload[offset];
377 offset += value_length;
379 if (obj_type < last_type) {
380 ESP_LOGVV(TAG,
"BTHome objects not in ascending order");
382 last_type = obj_type;
386 const uint8_t packet_id = value[0];
387 if (this->
last_packet_id_.has_value() && *this->last_packet_id_ == packet_id) {
430 ESP_LOGD(TAG,
"BTHome data%sfrom %s", is_trigger_based ?
" (triggered) " :
" ", device.
address_str_to(addr_buf));