diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index f0f48d1a51..acd4921700 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -29,7 +29,6 @@ set(common_include_dirs set(ble_mesh_include_dirs "esp_ble_mesh/common/include" - "esp_ble_mesh/common/tinycrypt/include" "esp_ble_mesh/core" "esp_ble_mesh/core/include" "esp_ble_mesh/core/storage" @@ -42,6 +41,10 @@ set(ble_mesh_include_dirs "esp_ble_mesh/api" ) +set(ble_mesh_tinycrypt_dirs + "esp_ble_mesh/common/tinycrypt/include" +) + set(ble_mesh_v11_include_dirs "esp_ble_mesh/lib/include" "esp_ble_mesh/v1.1/api/core/include" @@ -546,21 +549,6 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/btc/btc_ble_mesh_prov.c" "esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c" "esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c" - "esp_ble_mesh/common/tinycrypt/src/aes_decrypt.c" - "esp_ble_mesh/common/tinycrypt/src/aes_encrypt.c" - "esp_ble_mesh/common/tinycrypt/src/cbc_mode.c" - "esp_ble_mesh/common/tinycrypt/src/ccm_mode.c" - "esp_ble_mesh/common/tinycrypt/src/cmac_mode.c" - "esp_ble_mesh/common/tinycrypt/src/ctr_mode.c" - "esp_ble_mesh/common/tinycrypt/src/ctr_prng.c" - "esp_ble_mesh/common/tinycrypt/src/ecc_dh.c" - "esp_ble_mesh/common/tinycrypt/src/ecc_dsa.c" - "esp_ble_mesh/common/tinycrypt/src/ecc_platform_specific.c" - "esp_ble_mesh/common/tinycrypt/src/ecc.c" - "esp_ble_mesh/common/tinycrypt/src/hmac_prng.c" - "esp_ble_mesh/common/tinycrypt/src/hmac.c" - "esp_ble_mesh/common/tinycrypt/src/sha256.c" - "esp_ble_mesh/common/tinycrypt/src/utils.c" "esp_ble_mesh/common/atomic.c" "esp_ble_mesh/common/buf.c" "esp_ble_mesh/common/common.c" @@ -568,8 +556,21 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/common/mutex.c" "esp_ble_mesh/common/queue.c" "esp_ble_mesh/common/timer.c" - "esp_ble_mesh/common/utils.c" - "esp_ble_mesh/core/storage/settings_nvs.c" + "esp_ble_mesh/common/utils.c") + + # Select crypto implementation based on config + if(CONFIG_BT_SMP_CRYPTO_STACK_TINYCRYPT OR + CONFIG_BT_SMP_CRYPTO_STACK_NATIVE) + list(APPEND srcs "esp_ble_mesh/common/crypto_tc.c") + elseif(CONFIG_BT_SMP_CRYPTO_STACK_MBEDTLS) + if(CONFIG_MBEDTLS_VER_4_X_SUPPORT) + list(APPEND srcs "esp_ble_mesh/common/crypto_psa.c") + else() + list(APPEND srcs "esp_ble_mesh/common/crypto_mbedtls.c") + endif() + endif() + + list(APPEND srcs "esp_ble_mesh/core/storage/settings_nvs.c" "esp_ble_mesh/core/storage/settings_uid.c" "esp_ble_mesh/core/storage/settings.c" "esp_ble_mesh/core/access.c" @@ -610,6 +611,26 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/models/server/state_binding.c" "esp_ble_mesh/models/server/state_transition.c" "esp_ble_mesh/models/server/time_scene_server.c") + + if(CONFIG_BT_SMP_CRYPTO_STACK_NATIVE) + list(APPEND include_dirs ${ble_mesh_tinycrypt_dirs}) + list(APPEND srcs + "esp_ble_mesh/common/tinycrypt/src/aes_decrypt.c" + "esp_ble_mesh/common/tinycrypt/src/aes_encrypt.c" + "esp_ble_mesh/common/tinycrypt/src/cbc_mode.c" + "esp_ble_mesh/common/tinycrypt/src/ccm_mode.c" + "esp_ble_mesh/common/tinycrypt/src/cmac_mode.c" + "esp_ble_mesh/common/tinycrypt/src/ctr_mode.c" + "esp_ble_mesh/common/tinycrypt/src/ctr_prng.c" + "esp_ble_mesh/common/tinycrypt/src/ecc_dh.c" + "esp_ble_mesh/common/tinycrypt/src/ecc_dsa.c" + "esp_ble_mesh/common/tinycrypt/src/ecc_platform_specific.c" + "esp_ble_mesh/common/tinycrypt/src/ecc.c" + "esp_ble_mesh/common/tinycrypt/src/hmac_prng.c" + "esp_ble_mesh/common/tinycrypt/src/hmac.c" + "esp_ble_mesh/common/tinycrypt/src/sha256.c" + "esp_ble_mesh/common/tinycrypt/src/utils.c") + endif() if(CONFIG_BLE_MESH_V11_SUPPORT) list(APPEND include_dirs ${ble_mesh_v11_include_dirs}) diff --git a/components/bt/common/Kconfig.in b/components/bt/common/Kconfig.in index 0c0b040ab4..654e11b391 100644 --- a/components/bt/common/Kconfig.in +++ b/components/bt/common/Kconfig.in @@ -9,7 +9,7 @@ config BT_ALARM_MAX_NUM choice BT_SMP_CRYPTO_STACK prompt "SMP cryptographic stack" depends on (BT_BLE_SMP_ENABLE || BT_SMP_ENABLE || BT_NIMBLE_SECURITY_ENABLE) - default BT_SMP_CRYPTO_STACK_NATIVE + default BT_SMP_CRYPTO_STACK_TINYCRYPT help Select the cryptographic library to use for SMP operations (AES, AES-CMAC, ECDH P-256). diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index e6c19f0e45..896b3541c5 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -22,6 +22,15 @@ if BLE_MESH for mesh packets. And this could help avoid collision of advertising packets. + config BLE_MESH_USE_UNIFIED_CRYPTO + bool "Use the unified BLE tinycrypt implementation" + depends on !BT_LE_CRYPTO_STACK_MBEDTLS && !BT_NIMBLE_CRYPTO_STACK_MBEDTLS + default y if BT_SMP_CRYPTO_STACK_TINYCRYPT + default n + help + Enable this option to use the unified BLE tinycrypt solution + instead of the default one in BLE Mesh stack. + menuconfig BLE_MESH_USE_BLE_50 bool "Support using BLE 5.0 APIs for BLE Mesh" depends on BLE_MESH_EXPERIMENTAL diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h index 58ad280468..a603689769 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -67,9 +67,9 @@ esp_err_t esp_ble_mesh_node_prov_disable(esp_ble_mesh_prov_bearer_t bearers); * So as an unprovisioned device, it should use this function to input * the Public Key exchanged through the out-of-band mechanism. * - * @param[in] pub_key_x: Unprovisioned device's Public Key X - * @param[in] pub_key_y: Unprovisioned device's Public Key Y - * @param[in] private_key: Unprovisioned device's Private Key + * @param[in] pub_key_x: Unprovisioned device's Public Key X(Little Endian) + * @param[in] pub_key_y: Unprovisioned device's Public Key Y(Little Endian) + * @param[in] private_key: Unprovisioned device's Private Key(Little Endian) * * @return ESP_OK on success or error code otherwise. */ diff --git a/components/bt/esp_ble_mesh/common/crypto_mbedtls.c b/components/bt/esp_ble_mesh/common/crypto_mbedtls.c new file mode 100644 index 0000000000..45fe7a78bb --- /dev/null +++ b/components/bt/esp_ble_mesh/common/crypto_mbedtls.c @@ -0,0 +1,543 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_random.h" + +#include "mbedtls/aes.h" +#include "mbedtls/cmac.h" +#include "mbedtls/md.h" +#include "mbedtls/ecp.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/ccm.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" + +#include "mesh/common.h" +#include "mesh/crypto.h" +#include "mesh/trace.h" +#include "mesh/config.h" + +/* ECC key storage + * + * MbedTLS functions expect BIG-ENDIAN format. + */ +static struct { + bool is_ready; + uint8_t private_key[PRIV_KEY_SIZE]; /* Big-endian */ + uint8_t public_key[PUB_KEY_SIZE]; /* Big-endian */ +} dh_pair; + +int bt_mesh_crypto_init(void) +{ + memset(&dh_pair, 0, sizeof(dh_pair)); + dh_pair.is_ready = false; + return 0; +} + +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + mbedtls_aes_context ctx; + int ret; + + mbedtls_aes_init(&ctx); + + ret = mbedtls_aes_setkey_enc(&ctx, key->key, 128); + if (ret != 0) { + mbedtls_aes_free(&ctx); + return -EIO; + } + + ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, plaintext, enc_data); + mbedtls_aes_free(&ctx); + + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + mbedtls_ccm_context ctx; + int ret; + + mbedtls_ccm_init(&ctx); + + ret = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key->key, 128); + if (ret != 0) { + mbedtls_ccm_free(&ctx); + return -EIO; + } + + ret = mbedtls_ccm_encrypt_and_tag(&ctx, len, nonce, 13, aad, aad_len, + plaintext, enc_data, enc_data + len, mic_size); + + mbedtls_ccm_free(&ctx); + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + mbedtls_ccm_context ctx; + int ret; + + mbedtls_ccm_init(&ctx); + + ret = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key->key, 128); + if (ret != 0) { + mbedtls_ccm_free(&ctx); + return -EIO; + } + + ret = mbedtls_ccm_auth_decrypt(&ctx, len, nonce, 13, aad, aad_len, + enc_data, plaintext, enc_data + len, mic_size); + + mbedtls_ccm_free(&ctx); + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_ccm_encrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + + memcpy(mesh_key.key, key, 16); + return bt_mesh_ccm_encrypt(&mesh_key, nonce, plaintext, len, aad, aad_len, + enc_data, mic_size); +} + +int bt_mesh_ccm_decrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + + memcpy(mesh_key.key, key, 16); + return bt_mesh_ccm_decrypt(&mesh_key, nonce, enc_data, len, aad, aad_len, + plaintext, mic_size); +} + +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, + struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]) +{ + return bt_mesh_aes_cmac_raw_key(key->key, sg, sg_len, mac); +} + +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[16]) +{ + mbedtls_cipher_context_t ctx; + const mbedtls_cipher_info_t *info; + int ret; + + info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); + if (info == NULL) { + return -EIO; + } + + mbedtls_cipher_init(&ctx); + + ret = mbedtls_cipher_setup(&ctx, info); + if (ret != 0) { + mbedtls_cipher_free(&ctx); + return -EIO; + } + + ret = mbedtls_cipher_cmac_starts(&ctx, key, 128); + if (ret != 0) { + mbedtls_cipher_free(&ctx); + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + ret = mbedtls_cipher_cmac_update(&ctx, sg->data, sg->len); + if (ret != 0) { + mbedtls_cipher_free(&ctx); + return -EIO; + } + } + + ret = mbedtls_cipher_cmac_finish(&ctx, mac); + mbedtls_cipher_free(&ctx); + + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[32]) +{ + mbedtls_md_context_t ctx; + const mbedtls_md_info_t *info; + int ret; + + info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + if (info == NULL) { + return -EIO; + } + + mbedtls_md_init(&ctx); + + ret = mbedtls_md_setup(&ctx, info, 1); /* 1 = HMAC mode */ + if (ret != 0) { + mbedtls_md_free(&ctx); + return -EIO; + } + + ret = mbedtls_md_hmac_starts(&ctx, key, 32); + if (ret != 0) { + mbedtls_md_free(&ctx); + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + ret = mbedtls_md_hmac_update(&ctx, sg->data, sg->len); + if (ret != 0) { + mbedtls_md_free(&ctx); + return -EIO; + } + } + + ret = mbedtls_md_hmac_finish(&ctx, mac); + mbedtls_md_free(&ctx); + + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_pub_key_gen(void) +{ + mbedtls_ecp_group grp; + mbedtls_mpi d; + mbedtls_ecp_point Q; + uint8_t private_key_be[PRIV_KEY_SIZE]; + uint8_t public_key_be[PUB_KEY_SIZE]; + int ret; + int err; + + dh_pair.is_ready = false; + + do { + err = bt_mesh_rand(dh_pair.private_key, sizeof(dh_pair.private_key)); + if (err) { + BT_ERR("Failed to generate random private key"); + return err; + } + /* Ensure the private key is valid (non-zero last bytes in LE) */ + } while (dh_pair.private_key[0] == 0 && + dh_pair.private_key[1] == 0); + + mbedtls_ecp_group_init(&grp); + mbedtls_mpi_init(&d); + mbedtls_ecp_point_init(&Q); + + ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + if (ret != 0) { + goto cleanup; + } + + /* Read private key into MPI (MbedTLS expects big-endian) */ + ret = mbedtls_mpi_read_binary(&d, dh_pair.private_key, PRIV_KEY_SIZE); + if (ret != 0) { + goto cleanup; + } + + /* Compute public key: Q = d * G */ + ret = mbedtls_ecp_mul(&grp, &Q, &d, &grp.G, NULL, NULL); + if (ret != 0) { + goto cleanup; + } + + /* Export public key point in big-endian */ + ret = mbedtls_mpi_write_binary(&Q.MBEDTLS_PRIVATE(X), dh_pair.public_key, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_write_binary(&Q.MBEDTLS_PRIVATE(Y), dh_pair.public_key + 32, 32); + if (ret != 0) { + goto cleanup; + } + + dh_pair.is_ready = true; + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_mpi_free(&d); + mbedtls_ecp_point_free(&Q); + + return ret == 0 ? 0 : -EIO; +} + +const uint8_t *bt_mesh_pub_key_get_raw(void) +{ + if (!dh_pair.is_ready) { + if (bt_mesh_pub_key_gen() != 0) { + return NULL; + } + } + + return dh_pair.public_key; +} + +void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) +{ + mbedtls_ecp_group grp; + mbedtls_mpi d; + mbedtls_ecp_point Q; + int ret; + + dh_pair.is_ready = false; + + memcpy(dh_pair.private_key, pri_key, PRIV_KEY_SIZE); + + /* Compute public key from private key */ + mbedtls_ecp_group_init(&grp); + mbedtls_mpi_init(&d); + mbedtls_ecp_point_init(&Q); + + ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_read_binary(&d, pri_key, PRIV_KEY_SIZE); + if (ret != 0) { + goto cleanup; + } + + /* Compute public key: Q = d * G (no RNG needed for deterministic computation) */ + ret = mbedtls_ecp_mul(&grp, &Q, &d, &grp.G, NULL, NULL); + if (ret != 0) { + goto cleanup; + } + + /* Export public key point in big-endian */ + ret = mbedtls_mpi_write_binary(&Q.MBEDTLS_PRIVATE(X), dh_pair.public_key, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_write_binary(&Q.MBEDTLS_PRIVATE(Y), dh_pair.public_key + 32, 32); + if (ret != 0) { + goto cleanup; + } + + BT_DBG("Pubkey:%s", bt_hex(dh_pair.public_key, PUB_KEY_SIZE)); + BT_DBG("Privkey:%s", bt_hex(dh_pair.private_key, PRIV_KEY_SIZE)); + dh_pair.is_ready = true; + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_mpi_free(&d); + mbedtls_ecp_point_free(&Q); +} + +bool bt_mesh_check_public_key_raw(const uint8_t key[64]) +{ + mbedtls_ecp_group grp; + mbedtls_ecp_point Q; + uint8_t pub_key_be[PUB_KEY_SIZE]; + int ret; + + mbedtls_ecp_group_init(&grp); + mbedtls_ecp_point_init(&Q); + + ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_read_binary(&Q.MBEDTLS_PRIVATE(X), dh_pair.public_key, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_read_binary(&Q.MBEDTLS_PRIVATE(Y), dh_pair.public_key + 32, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_lset(&Q.MBEDTLS_PRIVATE(Z), 1); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_ecp_check_pubkey(&grp, &Q); + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_ecp_point_free(&Q); + + return ret == 0; +} + +int bt_mesh_dhkey_gen_raw(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) +{ + mbedtls_ecp_group grp; + mbedtls_mpi d; + mbedtls_ecp_point Q; + mbedtls_ecp_point result; + int ret; + + mbedtls_ecp_group_init(&grp); + mbedtls_mpi_init(&d); + mbedtls_ecp_point_init(&Q); + mbedtls_ecp_point_init(&result); + + ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_read_binary(&d, priv_key ? priv_key : dh_pair.private_key, PRIV_KEY_SIZE); + if (ret != 0) { + goto cleanup; + } + + /* Load public key point */ + ret = mbedtls_mpi_read_binary(&Q.MBEDTLS_PRIVATE(X), dh_pair.public_key, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_read_binary(&Q.MBEDTLS_PRIVATE(Y), dh_pair.public_key + 32, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_lset(&Q.MBEDTLS_PRIVATE(Z), 1); + if (ret != 0) { + goto cleanup; + } + + /* Check the peer's public key */ + ret = mbedtls_ecp_check_pubkey(&grp, &Q); + if (ret != 0) { + goto cleanup; + } + + /* Calculate shared secret: result = d * Q (no RNG needed for deterministic computation) */ + ret = mbedtls_ecp_mul(&grp, &result, &d, &Q, NULL, NULL); + if (ret != 0) { + goto cleanup; + } + + /* Export X coordinate as DH key (big-endian) */ + ret = mbedtls_mpi_write_binary(&result.MBEDTLS_PRIVATE(X), dhkey, DH_KEY_SIZE); + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_mpi_free(&d); + mbedtls_ecp_point_free(&Q); + mbedtls_ecp_point_free(&result); + + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], + struct bt_mesh_key *out) +{ + (void)type; /* Not used for non-PSA implementation */ + memcpy(out->key, in, 16); + return 0; +} + +int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in) +{ + memcpy(out, in->key, 16); + return 0; +} + +void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src) +{ + memcpy(dst, src, sizeof(struct bt_mesh_key)); +} + +int bt_mesh_key_destroy(const struct bt_mesh_key *key) +{ + (void)key; /* No cleanup needed for non-PSA implementation */ + return 0; +} + +int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key) +{ + return memcmp(raw_key, key->key, 16); +} + +int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + mbedtls_aes_context ctx; + uint8_t tmp[16]; + int ret; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + mbedtls_aes_init(&ctx); + + /* Swap key bytes (LE to BE) */ + sys_memcpy_swap(tmp, key, 16); + + ret = mbedtls_aes_setkey_enc(&ctx, tmp, 128); + if (ret != 0) { + mbedtls_aes_free(&ctx); + return -EINVAL; + } + + /* Swap plaintext bytes and encrypt */ + sys_memcpy_swap(tmp, plaintext, 16); + + ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, tmp, enc_data); + mbedtls_aes_free(&ctx); + + if (ret != 0) { + return -EINVAL; + } + + /* Swap result bytes (BE to LE) */ + sys_mem_swap(enc_data, 16); + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} + +int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + mbedtls_aes_context ctx; + int ret; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + mbedtls_aes_init(&ctx); + + ret = mbedtls_aes_setkey_enc(&ctx, key, 128); + if (ret != 0) { + mbedtls_aes_free(&ctx); + return -EINVAL; + } + + ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, plaintext, enc_data); + mbedtls_aes_free(&ctx); + + if (ret != 0) { + return -EINVAL; + } + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} diff --git a/components/bt/esp_ble_mesh/common/crypto_psa.c b/components/bt/esp_ble_mesh/common/crypto_psa.c new file mode 100644 index 0000000000..3655c48cb6 --- /dev/null +++ b/components/bt/esp_ble_mesh/common/crypto_psa.c @@ -0,0 +1,713 @@ +/* + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_random.h" +#include "psa/crypto.h" + +#include "mesh/common.h" +#include "mesh/crypto.h" +#include "mesh/trace.h" +#include "mesh/config.h" + +/* PSA Key ID range for BLE Mesh */ +#define BT_MESH_PSA_KEY_ID_MIN 0x0001A000 +#define BT_MESH_PSA_KEY_ID_RANGE_SIZE \ + (2 * CONFIG_BLE_MESH_SUBNET_COUNT + 2 * CONFIG_BLE_MESH_APP_KEY_COUNT + 2) + +/* Internal DH key pair storage + * + * PSA functions expect BIG-ENDIAN format. + */ +static struct { + bool is_ready; + psa_key_id_t priv_key_id; + uint8_t public_key[PUB_KEY_SIZE + 1]; /* Big-endian, PSA format: 0x04 + X + Y */ +} dh_pair; + +/* Bitmap for tracking allocated key IDs */ +static uint32_t pst_keys[(BT_MESH_PSA_KEY_ID_RANGE_SIZE + 31) / 32]; + +static psa_key_id_t keyid_alloc(void) +{ + for (int i = 0; i < BT_MESH_PSA_KEY_ID_RANGE_SIZE; i++) { + int word = i / 32; + int bit = i % 32; + if (!(pst_keys[word] & (1U << bit))) { + pst_keys[word] |= (1U << bit); + return BT_MESH_PSA_KEY_ID_MIN + i; + } + } + return PSA_KEY_ID_NULL; +} + +static int keyid_free(psa_key_id_t key_id) +{ + if (key_id >= BT_MESH_PSA_KEY_ID_MIN && + key_id < BT_MESH_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE) { + int idx = key_id - BT_MESH_PSA_KEY_ID_MIN; + int word = idx / 32; + int bit = idx % 32; + pst_keys[word] &= ~(1U << bit); + return 0; + } + return -EIO; +} + +static void keyid_assign(psa_key_id_t key_id) +{ + if (key_id >= BT_MESH_PSA_KEY_ID_MIN && + key_id < BT_MESH_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE) { + int idx = key_id - BT_MESH_PSA_KEY_ID_MIN; + int word = idx / 32; + int bit = idx % 32; + pst_keys[word] |= (1U << bit); + } +} + +int bt_mesh_crypto_init(void) +{ + psa_status_t status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + BT_ERR("PSA crypto init failed: %d", status); + return -EIO; + } + + dh_pair.is_ready = false; + dh_pair.priv_key_id = PSA_KEY_ID_NULL; + memset(pst_keys, 0, sizeof(pst_keys)); + + return 0; +} + +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + size_t output_len; + psa_status_t status; + + status = psa_cipher_encrypt(key->key, PSA_ALG_ECB_NO_PADDING, + plaintext, 16, enc_data, 16, &output_len); + + if (status != PSA_SUCCESS || output_len != 16) { + BT_ERR("PSA cipher encrypt failed: %d", status); + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + size_t output_len; + psa_status_t status; + psa_algorithm_t alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, mic_size); + + status = psa_aead_encrypt(key->key, alg, nonce, 13, aad, aad_len, + plaintext, len, enc_data, len + mic_size, &output_len); + + if (status != PSA_SUCCESS || output_len != len + mic_size) { + BT_ERR("PSA AEAD encrypt failed: %d", status); + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + size_t output_len; + psa_status_t status; + psa_algorithm_t alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, mic_size); + + status = psa_aead_decrypt(key->key, alg, nonce, 13, aad, aad_len, + enc_data, len + mic_size, plaintext, len, &output_len); + + if (status != PSA_SUCCESS || output_len != len) { + BT_ERR("PSA AEAD decrypt failed: %d", status); + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_encrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + int err; + + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CCM, key, &mesh_key); + if (err) { + return err; + } + + err = bt_mesh_ccm_encrypt(&mesh_key, nonce, plaintext, len, aad, aad_len, + enc_data, mic_size); + + psa_destroy_key(mesh_key.key); + return err; +} + +int bt_mesh_ccm_decrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + int err; + + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CCM, key, &mesh_key); + if (err) { + return err; + } + + err = bt_mesh_ccm_decrypt(&mesh_key, nonce, enc_data, len, aad, aad_len, + plaintext, mic_size); + + psa_destroy_key(mesh_key.key); + return err; +} + +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, + struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]) +{ + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; + psa_status_t status; + size_t mac_len; + + status = psa_mac_sign_setup(&operation, key->key, PSA_ALG_CMAC); + if (status != PSA_SUCCESS) { + BT_ERR("PSA MAC setup failed: %d", status); + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + status = psa_mac_update(&operation, sg->data, sg->len); + if (status != PSA_SUCCESS) { + psa_mac_abort(&operation); + BT_ERR("PSA MAC update failed: %d", status); + return -EIO; + } + } + + status = psa_mac_sign_finish(&operation, mac, 16, &mac_len); + if (status != PSA_SUCCESS || mac_len != 16) { + BT_ERR("PSA MAC finish failed: %d", status); + return -EIO; + } + + return 0; +} + +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[16]) +{ + struct bt_mesh_key key_id; + int err; + + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CMAC, key, &key_id); + if (err) { + return err; + } + + err = bt_mesh_aes_cmac_mesh_key(&key_id, sg, sg_len, mac); + + psa_destroy_key(key_id.key); + + return err; +} + +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[32]) +{ + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id; + psa_status_t status; + size_t mac_len; + int err = 0; + + /* Import HMAC key */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&attributes, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attributes, 256); + + status = psa_import_key(&attributes, key, 32, &key_id); + if (status != PSA_SUCCESS) { + BT_ERR("PSA import HMAC key failed: %d", status); + return -EIO; + } + psa_reset_key_attributes(&attributes); + + status = psa_mac_sign_setup(&operation, key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + if (status != PSA_SUCCESS) { + BT_ERR("PSA HMAC setup failed: %d", status); + err = -EIO; + goto end; + } + + for (; sg_len; sg_len--, sg++) { + status = psa_mac_update(&operation, sg->data, sg->len); + if (status != PSA_SUCCESS) { + psa_mac_abort(&operation); + BT_ERR("PSA HMAC update failed: %d", status); + err = -EIO; + goto end; + } + } + + status = psa_mac_sign_finish(&operation, mac, 32, &mac_len); + if (status != PSA_SUCCESS || mac_len != 32) { + BT_ERR("PSA HMAC finish failed: %d", status); + err = -EIO; + } + +end: + psa_destroy_key(key_id); + return err; +} + +int bt_mesh_pub_key_gen(void) +{ + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + uint8_t private_key[PRIV_KEY_SIZE]; + size_t key_len; + int err; + + /* Destroy any existing key */ + if (dh_pair.priv_key_id != PSA_KEY_ID_NULL) { + psa_destroy_key(dh_pair.priv_key_id); + dh_pair.priv_key_id = PSA_KEY_ID_NULL; + } + dh_pair.is_ready = false; + + /* Generate a random private key (in little-endian format for storage) */ + do { + err = bt_mesh_rand(private_key, sizeof(private_key)); + if (err) { + BT_ERR("Failed to generate random private key"); + return err; + } + /* Ensure the private key is valid (non-zero first bytes in BE) */ + } while (private_key[0] == 0 && private_key[1] == 0); + + /* Configure key attributes for ECDH with P-256 */ + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDH); + psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&key_attributes, 256); + + /* Import the private key */ + status = psa_import_key(&key_attributes, private_key, sizeof(private_key), + &dh_pair.priv_key_id); + if (status != PSA_SUCCESS) { + BT_ERR("PSA import private key failed: %d", status); + psa_reset_key_attributes(&key_attributes); + return -EIO; + } + + /* Export public key (PSA computes it from the private key) */ + status = psa_export_public_key(dh_pair.priv_key_id, dh_pair.public_key, + sizeof(dh_pair.public_key), &key_len); + if (status != PSA_SUCCESS || key_len != PUB_KEY_SIZE + 1) { + BT_ERR("PSA export public key failed: %d", status); + psa_destroy_key(dh_pair.priv_key_id); + dh_pair.priv_key_id = PSA_KEY_ID_NULL; + psa_reset_key_attributes(&key_attributes); + return -EIO; + } + + dh_pair.is_ready = true; + psa_reset_key_attributes(&key_attributes); + + return 0; +} + +const uint8_t *bt_mesh_pub_key_get_raw(void) +{ + if (!dh_pair.is_ready) { + if (bt_mesh_pub_key_gen() != 0) { + return NULL; + } + } + + return &dh_pair.public_key[1]; +} + +void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + size_t key_len; + + /* Destroy any existing key */ + if (dh_pair.priv_key_id != PSA_KEY_ID_NULL) { + psa_destroy_key(dh_pair.priv_key_id); + dh_pair.priv_key_id = PSA_KEY_ID_NULL; + } + dh_pair.is_ready = false; + + /* Import the provided private key */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDH); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, 256); + + status = psa_import_key(&attributes, pri_key, PRIV_KEY_SIZE, &dh_pair.priv_key_id); + if (status != PSA_SUCCESS) { + BT_ERR("PSA import private key failed: %d", status); + psa_reset_key_attributes(&attributes); + return; + } + + /* Export public key (PSA computes it from the private key) */ + status = psa_export_public_key(dh_pair.priv_key_id, dh_pair.public_key, + sizeof(dh_pair.public_key), &key_len); + if (status != PSA_SUCCESS || key_len != PUB_KEY_SIZE + 1) { + BT_ERR("PSA export public key failed: %d", status); + psa_destroy_key(dh_pair.priv_key_id); + dh_pair.priv_key_id = PSA_KEY_ID_NULL; + psa_reset_key_attributes(&attributes); + return; + } + + BT_DBG("Pubkey:%s", bt_hex(&dh_pair.public_key[1], PUB_KEY_SIZE)); + BT_DBG("Privkey:%s", bt_hex(pri_key, PRIV_KEY_SIZE)); + dh_pair.is_ready = true; + psa_reset_key_attributes(&attributes); +} + +bool bt_mesh_check_public_key_raw(const uint8_t key[64]) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id; + psa_status_t status; + uint8_t pub_be[PUB_KEY_SIZE + 1]; + + /* PSA requires 0x04 prefix for uncompressed point */ + pub_be[0] = 0x04; + /* Convert from little-endian to big-endian */ + memcpy(&pub_be[1], key, 32); + memcpy(&pub_be[33], key + 32, 32); + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, 256); + + status = psa_import_key(&attributes, pub_be, sizeof(pub_be), &key_id); + psa_reset_key_attributes(&attributes); + + if (status != PSA_SUCCESS) { + return false; + } + + psa_destroy_key(key_id); + return true; +} + +int bt_mesh_dhkey_gen_raw(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) +{ + psa_key_id_t priv_key_id = PSA_KEY_ID_NULL; + uint8_t public_key_be[PUB_KEY_SIZE + 1]; + psa_status_t status; + size_t dh_key_len; + int err = 0; + + if (priv_key) { + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + + /* Import custom private key */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDH); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, 256); + + status = psa_import_key(&attributes, priv_key, PRIV_KEY_SIZE, &priv_key_id); + psa_reset_key_attributes(&attributes); + + if (status != PSA_SUCCESS) { + BT_ERR("PSA import private key failed: %d", status); + return -EIO; + } + } else { + priv_key_id = dh_pair.priv_key_id; + } + + /* Prepare public key with 0x04 prefix in big-endian format */ + public_key_be[0] = 0x04; + /* Convert from little-endian to big-endian */ + memcpy(public_key_be + 1, pub_key, 32); + memcpy(public_key_be + 33, pub_key + 32, 32); + + /* Calculate shared secret */ + status = psa_raw_key_agreement(PSA_ALG_ECDH, priv_key_id, public_key_be, + PUB_KEY_SIZE + 1, dhkey, DH_KEY_SIZE, &dh_key_len); + + if (status != PSA_SUCCESS || dh_key_len != DH_KEY_SIZE) { + BT_ERR("PSA ECDH failed: %d", status); + err = -EIO; + } + + if (priv_key && priv_key_id != PSA_KEY_ID_NULL) { + psa_destroy_key(priv_key_id); + } + + return err; +} + +int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], + struct bt_mesh_key *out) +{ + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + psa_key_id_t key_id = PSA_KEY_ID_NULL; + + switch (type) { + case BT_MESH_KEY_TYPE_ECB: + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_usage_flags(&key_attributes, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&key_attributes, PSA_ALG_ECB_NO_PADDING); + break; + case BT_MESH_KEY_TYPE_CCM: + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_usage_flags(&key_attributes, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&key_attributes, + PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 4)); + break; + case BT_MESH_KEY_TYPE_CMAC: + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_MESSAGE); + psa_set_key_algorithm(&key_attributes, PSA_ALG_CMAC); + break; + case BT_MESH_KEY_TYPE_NET: +#if CONFIG_BT_SETTINGS + key_id = keyid_alloc(); + if (key_id == PSA_KEY_ID_NULL) { + return -ENOMEM; + } + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&key_attributes, key_id); +#else + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); +#endif + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_EXPORT); + break; + case BT_MESH_KEY_TYPE_APP: + case BT_MESH_KEY_TYPE_DEV: +#if CONFIG_BT_SETTINGS + key_id = keyid_alloc(); + if (key_id == PSA_KEY_ID_NULL) { + return -ENOMEM; + } + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&key_attributes, key_id); +#else + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); +#endif + psa_set_key_usage_flags(&key_attributes, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_EXPORT); + psa_set_key_algorithm(&key_attributes, + PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 4)); + break; + default: + return -EINVAL; + } + + psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&key_attributes, 128); + + status = psa_import_key(&key_attributes, in, 16, &out->key); + if (status == PSA_ERROR_ALREADY_EXISTS) { + BT_WARN("Key 0x%04x already exists, destroying and reimporting", key_id); + psa_destroy_key(key_id); + status = psa_import_key(&key_attributes, in, 16, &out->key); + } + + psa_reset_key_attributes(&key_attributes); + + if (status != PSA_SUCCESS) { + BT_ERR("PSA import key failed: %d", status); + if (key_id != PSA_KEY_ID_NULL) { + keyid_free(key_id); + } + return -EIO; + } + + return 0; +} + +int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in) +{ + size_t data_length; + psa_status_t status; + + status = psa_export_key(in->key, out, 16, &data_length); + if (status != PSA_SUCCESS || data_length != 16) { + BT_ERR("PSA export key failed: %d", status); + return -EIO; + } + + return 0; +} + +void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src) +{ + memcpy(dst, src, sizeof(struct bt_mesh_key)); +#if CONFIG_BT_SETTINGS + keyid_assign(dst->key); +#endif +} + +int bt_mesh_key_destroy(const struct bt_mesh_key *key) +{ + psa_status_t status; + + status = psa_destroy_key(key->key); + if (status != PSA_SUCCESS) { + BT_ERR("PSA destroy key failed: %d", status); + return -EIO; + } + +#if CONFIG_BT_SETTINGS + return keyid_free(key->key); +#else + return 0; +#endif +} + +int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key) +{ + uint8_t out[16]; + int err; + + err = bt_mesh_key_export(out, key); + if (err) { + return err; + } + + return memcmp(out, raw_key, 16); +} + +int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id; + psa_status_t status; + uint8_t tmp[16]; + size_t output_len; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + /* Swap key bytes (LE to BE) */ + sys_memcpy_swap(tmp, key, 16); + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_ECB_NO_PADDING); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + + status = psa_import_key(&attributes, tmp, 16, &key_id); + psa_reset_key_attributes(&attributes); + + if (status != PSA_SUCCESS) { + BT_ERR("PSA import key failed: %d", status); + return -EINVAL; + } + + /* Swap plaintext bytes and encrypt */ + sys_memcpy_swap(tmp, plaintext, 16); + + status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, + tmp, 16, enc_data, 16, &output_len); + + psa_destroy_key(key_id); + + if (status != PSA_SUCCESS || output_len != 16) { + BT_ERR("PSA encrypt failed: %d", status); + return -EINVAL; + } + + /* Swap result bytes (BE to LE) */ + sys_mem_swap(enc_data, 16); + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} + +int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id; + psa_status_t status; + size_t output_len; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_ECB_NO_PADDING); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + + status = psa_import_key(&attributes, key, 16, &key_id); + psa_reset_key_attributes(&attributes); + + if (status != PSA_SUCCESS) { + BT_ERR("PSA import key failed: %d", status); + return -EINVAL; + } + + status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, + plaintext, 16, enc_data, 16, &output_len); + + psa_destroy_key(key_id); + + if (status != PSA_SUCCESS || output_len != 16) { + BT_ERR("PSA encrypt failed: %d", status); + return -EINVAL; + } + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} + +#if 0 +int bt_mesh_rand(void *buf, size_t len) +{ + psa_status_t status; + + if (buf == NULL || len == 0) { + return -EINVAL; + } + + status = psa_generate_random(buf, len); + return status == PSA_SUCCESS ? 0 : -EIO; +} +#endif diff --git a/components/bt/esp_ble_mesh/common/crypto_tc.c b/components/bt/esp_ble_mesh/common/crypto_tc.c new file mode 100644 index 0000000000..2c4d39499b --- /dev/null +++ b/components/bt/esp_ble_mesh/common/crypto_tc.c @@ -0,0 +1,342 @@ +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_random.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "mesh/common.h" +#include "mesh/crypto.h" +#include "mesh/trace.h" + +/* Internal DH key pair storage + * + * TinyCrypt's uECC functions expect BIG-ENDIAN format. + */ +static struct { + bool is_ready; + uint8_t private_key[PRIV_KEY_SIZE]; /* Big-endian */ + uint8_t public_key[PUB_KEY_SIZE]; /* Big-endian */ +} dh_pair; + +int bt_mesh_crypto_init(void) +{ + memset(&dh_pair, 0, sizeof(dh_pair)); + dh_pair.is_ready = false; + return 0; +} + +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + struct tc_aes_key_sched_struct sched; + + if (tc_aes128_set_encrypt_key(&sched, key->key) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_aes_encrypt(enc_data, plaintext, &sched) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + struct tc_ccm_mode_struct ccm; + struct tc_aes_key_sched_struct sched; + + if (tc_aes128_set_encrypt_key(&sched, key->key) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_ccm_config(&ccm, &sched, nonce, 13, mic_size) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_ccm_generation_encryption(enc_data, len + mic_size, aad, aad_len, + plaintext, len, &ccm) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + struct tc_ccm_mode_struct ccm; + struct tc_aes_key_sched_struct sched; + + if (tc_aes128_set_encrypt_key(&sched, key->key) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_ccm_config(&ccm, &sched, nonce, 13, mic_size) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_ccm_decryption_verification(plaintext, len, aad, aad_len, + enc_data, len + mic_size, &ccm) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_encrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + + memcpy(mesh_key.key, key, 16); + return bt_mesh_ccm_encrypt(&mesh_key, nonce, plaintext, len, aad, aad_len, + enc_data, mic_size); +} + +int bt_mesh_ccm_decrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + + memcpy(mesh_key.key, key, 16); + return bt_mesh_ccm_decrypt(&mesh_key, nonce, enc_data, len, aad, aad_len, + plaintext, mic_size); +} + +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[16]) +{ + struct tc_aes_key_sched_struct sched; + struct tc_cmac_struct state; + + if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + if (tc_cmac_update(&state, sg->data, sg->len) == TC_CRYPTO_FAIL) { + return -EIO; + } + } + + if (tc_cmac_final(mac, &state) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, + struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]) +{ + return bt_mesh_aes_cmac_raw_key(key->key, sg, sg_len, mac); +} + +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[32]) +{ + struct tc_hmac_state_struct h; + + if (tc_hmac_set_key(&h, key, 32) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_hmac_init(&h) == TC_CRYPTO_FAIL) { + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + if (tc_hmac_update(&h, sg->data, sg->len) == TC_CRYPTO_FAIL) { + return -EIO; + } + } + + if (tc_hmac_final(mac, 32, &h) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_pub_key_gen(void) +{ + int rc; + + /* Generate a random private key */ + do { + rc = bt_mesh_rand(dh_pair.private_key, sizeof(dh_pair.private_key)); + if (rc) { + BT_ERR("Failed to generate random private key"); + return rc; + } + /* Ensure the private key is valid (first bytes in BE shall be non-zero) */ + } while (dh_pair.private_key[0] == 0 && + dh_pair.private_key[1] == 0); + + /* Compute the public key from the private key */ + rc = uECC_compute_public_key(dh_pair.private_key, dh_pair.public_key, uECC_secp256r1()); + if (rc != TC_CRYPTO_SUCCESS) { + dh_pair.is_ready = false; + BT_ERR("Failed to compute public key"); + return -EIO; + } + + dh_pair.is_ready = true; + return 0; +} + +const uint8_t *bt_mesh_pub_key_get_raw(void) +{ + if (!dh_pair.is_ready) { + if (bt_mesh_pub_key_gen() != 0) { + return NULL; + } + } + + return dh_pair.public_key; +} + +void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) +{ + int rc; + + memcpy(dh_pair.private_key, pri_key, PRIV_KEY_SIZE); + + /* Compute the public key from the provided private key */ + rc = uECC_compute_public_key(dh_pair.private_key, dh_pair.public_key, uECC_secp256r1()); + if (rc != TC_CRYPTO_SUCCESS) { + dh_pair.is_ready = false; + BT_ERR("Failed to compute public key from private key"); + return; + } + + BT_DBG("Pubkey:%s", bt_hex(dh_pair.public_key, PUB_KEY_SIZE)); + BT_DBG("Privkey:%s", bt_hex(dh_pair.private_key, PRIV_KEY_SIZE)); + dh_pair.is_ready = true; +} + +bool bt_mesh_check_public_key_raw(const uint8_t key[64]) +{ + return uECC_valid_public_key(key, uECC_secp256r1()) == 0; +} + +int bt_mesh_dhkey_gen_raw(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) +{ + if (uECC_valid_public_key(pub_key, uECC_secp256r1()) != 0) { + BT_ERR("Public key is not valid"); + return -EIO; + } + + if (uECC_shared_secret(pub_key, priv_key ? priv_key : dh_pair.private_key, + dhkey, uECC_secp256r1()) != TC_CRYPTO_SUCCESS) { + BT_ERR("DHKey generation failed"); + return -EIO; + } + + return 0; +} + +int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], + struct bt_mesh_key *out) +{ + (void)type; /* Type is not used for TinyCrypt, just store raw key */ + memcpy(out->key, in, 16); + return 0; +} + +int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in) +{ + memcpy(out, in->key, 16); + return 0; +} + +void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src) +{ + memcpy(dst->key, src->key, 16); +} + +int bt_mesh_key_destroy(const struct bt_mesh_key *key) +{ + (void)key; /* Nothing to destroy for TinyCrypt */ + return 0; +} + +int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key) +{ + return memcmp(raw_key, key->key, 16); +} + +int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + struct tc_aes_key_sched_struct sched; + uint8_t tmp[16]; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + /* Swap key bytes (LE to BE) */ + sys_memcpy_swap(tmp, key, 16); + + if (tc_aes128_set_encrypt_key(&sched, tmp) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + /* Swap plaintext bytes (LE to BE) */ + sys_memcpy_swap(tmp, plaintext, 16); + + if (tc_aes_encrypt(enc_data, tmp, &sched) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + /* Swap result bytes (BE to LE) */ + sys_mem_swap(enc_data, 16); + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} + +int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + struct tc_aes_key_sched_struct sched; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + if (tc_aes128_set_encrypt_key(&sched, key) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + if (tc_aes_encrypt(enc_data, plaintext, &sched) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} diff --git a/components/bt/esp_ble_mesh/common/include/mesh/common.h b/components/bt/esp_ble_mesh/common/include/mesh/common.h index a1cfa673a2..8be5e40d06 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/common.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/common.h @@ -22,6 +22,7 @@ #include "mesh/trace.h" #include "mesh/mutex.h" #include "mesh/access.h" +#include "mesh/crypto.h" #ifdef __cplusplus extern "C" { diff --git a/components/bt/esp_ble_mesh/common/include/mesh/crypto.h b/components/bt/esp_ble_mesh/common/include/mesh/crypto.h new file mode 100644 index 0000000000..0ae0cad1cb --- /dev/null +++ b/components/bt/esp_ble_mesh/common/include/mesh/crypto.h @@ -0,0 +1,514 @@ +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_CRYPTO_H_ +#define _BLE_MESH_CRYPTO_H_ + +#include +#include +#include + +#include "sdkconfig.h" + +#include "mesh/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Key sizes */ +#define PRIV_KEY_SIZE 32 +#define PUB_KEY_SIZE 64 +#define DH_KEY_SIZE 32 + +/** + * @brief Crypto module endianness definitions + * + * BLE Mesh protocol uses big-endian format for ECC operations. + * These macros define whether the underlying crypto implementation + * expects big-endian or little-endian input. + * + * - BT_MESH_CRYPTO_ENDIAN_BIG: Module expects big-endian (TinyCrypt, MbedTLS, PSA) + * - BT_MESH_CRYPTO_ENDIAN_LITTLE: Module expects little-endian (future implementations) + */ +#define BT_MESH_CRYPTO_ENDIAN_BIG 0 +#define BT_MESH_CRYPTO_ENDIAN_LITTLE 1 + +/** + * @brief Current crypto module endianness + * + * This macro should be defined by the crypto implementation. + * Default is big-endian (matching TinyCrypt, MbedTLS, PSA). + */ +#ifndef BT_MESH_CRYPTO_ENDIAN +#define BT_MESH_CRYPTO_ENDIAN BT_MESH_CRYPTO_ENDIAN_BIG +#endif + +/** + * @brief Parameter conversion macros for endianness handling + * + * These macros automatically handle byte order conversion between + * BLE Mesh's big-endian format and the crypto module's expected format. + * + * For public keys (64 bytes = X + Y), the X and Y coordinates must be + * swapped separately, not as a single 64-byte block. + */ +#if (BT_MESH_CRYPTO_ENDIAN == BT_MESH_CRYPTO_ENDIAN_LITTLE) + +/* Little-endian mode: need byte order conversion */ +#define CRYPTO_PARAM_DECLARE(name, size) \ + uint8_t _##name[size] + +#define CRYPTO_PARAM_IN(name, size) \ + sys_memcpy_swap(_##name, name, size) + +#define CRYPTO_PARAM_OUT(name, size) \ + sys_memcpy_swap((uint8_t *)(name), _##name, size) + +#define CRYPTO_PARAM(name) (_##name) + +/* Public key (64 bytes) needs special handling: swap X and Y separately */ +#define CRYPTO_PARAM_PUBKEY_IN(name) \ + do { \ + sys_memcpy_swap(_##name, name, 32); \ + sys_memcpy_swap(_##name + 32, (name) + 32, 32); \ + } while (0) + +#define CRYPTO_PARAM_PUBKEY_OUT(name) \ + do { \ + sys_memcpy_swap((uint8_t *)(name), _##name, 32); \ + sys_memcpy_swap((uint8_t *)(name) + 32, _##name + 32, 32); \ + } while (0) + +#else /* BT_MESH_CRYPTO_ENDIAN_BIG */ + +/* Big-endian mode: no conversion needed, use original parameters directly */ +#define CRYPTO_PARAM_DECLARE(name, size) \ + (void)0 + +#define CRYPTO_PARAM_IN(name, size) \ + (void)0 + +#define CRYPTO_PARAM_OUT(name, size) \ + (void)0 + +#define CRYPTO_PARAM(name) (name) + +#define CRYPTO_PARAM_PUBKEY_IN(name) \ + (void)0 + +#define CRYPTO_PARAM_PUBKEY_OUT(name) \ + (void)0 + +#endif /* BT_MESH_CRYPTO_ENDIAN */ + +/** + * @brief Scatter-Gather data structure for cryptographic operations + */ +struct bt_mesh_sg { + const void *data; + size_t len; +}; + +/** + * @brief Mesh key type enumeration + */ +enum bt_mesh_key_type { + BT_MESH_KEY_TYPE_ECB, /**< AES-ECB encryption/decryption */ + BT_MESH_KEY_TYPE_CCM, /**< AES-CCM AEAD */ + BT_MESH_KEY_TYPE_CMAC, /**< AES-CMAC */ + BT_MESH_KEY_TYPE_NET, /**< Network key */ + BT_MESH_KEY_TYPE_APP, /**< Application key */ + BT_MESH_KEY_TYPE_DEV, /**< Device key */ +}; + +/** + * @brief Mesh key structure + * + * For TinyCrypt/MbedTLS: stores raw key bytes + * For PSA: stores PSA key ID + */ +struct bt_mesh_key { +#if CONFIG_BT_SMP_CRYPTO_STACK_MBEDTLS && CONFIG_MBEDTLS_VER_4_X_SUPPORT + uint32_t key; /* PSA key ID */ +#else + uint8_t key[16]; /* Raw key bytes */ +#endif +}; + +/** + * @brief Initialize the cryptographic subsystem + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_crypto_init(void); + +/** + * @brief AES-ECB encryption (big-endian) + * + * @param key Pointer to mesh key structure + * @param plaintext 16-byte plaintext + * @param enc_data 16-byte output buffer for encrypted data + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]); + +/** + * @brief AES-CCM encryption + * + * @param key Pointer to mesh key structure + * @param nonce 13-byte nonce + * @param plaintext Input plaintext + * @param len Length of plaintext + * @param aad Additional authenticated data + * @param aad_len Length of AAD + * @param enc_data Output buffer (must be len + mic_size bytes) + * @param mic_size Size of MIC (4, 8, or 16 bytes) + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size); + +/** + * @brief AES-CCM decryption + * + * @param key Pointer to mesh key structure + * @param nonce 13-byte nonce + * @param enc_data Encrypted data with MIC + * @param len Length of plaintext (without MIC) + * @param aad Additional authenticated data + * @param aad_len Length of AAD + * @param plaintext Output buffer for plaintext + * @param mic_size Size of MIC (4, 8, or 16 bytes) + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size); + +/** + * @brief AES-CCM encryption using raw key bytes + * + * @param key 16-byte raw key + * @param nonce 13-byte nonce + * @param plaintext Input plaintext + * @param len Length of plaintext + * @param aad Additional authenticated data + * @param aad_len Length of AAD + * @param enc_data Output buffer (must be len + mic_size bytes) + * @param mic_size Size of MIC (4, 8, or 16 bytes) + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_ccm_encrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size); + +/** + * @brief AES-CCM decryption using raw key bytes + * + * @param key 16-byte raw key + * @param nonce 13-byte nonce + * @param enc_data Encrypted data with MIC + * @param len Length of plaintext (without MIC) + * @param aad Additional authenticated data + * @param aad_len Length of AAD + * @param plaintext Output buffer for plaintext + * @param mic_size Size of MIC (4, 8, or 16 bytes) + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_ccm_decrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size); + +/** + * @brief AES-CMAC using mesh key structure + * + * @param key Pointer to mesh key structure + * @param sg Scatter-gather list of input data + * @param sg_len Number of scatter-gather entries + * @param mac 16-byte output buffer for MAC + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, + struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]); + +/** + * @brief AES-CMAC using raw key bytes + * + * @param key 16-byte raw key + * @param sg Scatter-gather list of input data + * @param sg_len Number of scatter-gather entries + * @param mac 16-byte output buffer for MAC + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[16]); + +/** + * @brief AES-CMAC with single data input (convenience wrapper) + */ +static inline int bt_mesh_aes_cmac_one(const uint8_t key[16], const void *m, + size_t len, uint8_t mac[16]) +{ + struct bt_mesh_sg sg = { m, len }; + return bt_mesh_aes_cmac_raw_key(key, &sg, 1, mac); +} + +/** + * @brief HMAC-SHA256 using raw key bytes + * + * @param key 32-byte raw key + * @param sg Scatter-gather list of input data + * @param sg_len Number of scatter-gather entries + * @param mac 32-byte output buffer for MAC + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[32]); + +/** + * @brief HMAC-SHA256 with single data input (convenience wrapper) + */ +static inline int bt_mesh_sha256_hmac_one(const uint8_t key[32], const void *m, + size_t len, uint8_t mac[32]) +{ + struct bt_mesh_sg sg = { m, len }; + return bt_mesh_sha256_hmac_raw_key(key, &sg, 1, mac); +} + +/* ============================================================================ + * Internal Low-Level ECC APIs + * ============================================================================ + * These functions operate in the crypto module's native byte order. + * Do NOT call these directly - use the public wrapper functions below. + */ +const uint8_t *bt_mesh_pub_key_get_raw(void); +void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]); +bool bt_mesh_check_public_key_raw(const uint8_t key[64]); +int bt_mesh_dhkey_gen_raw(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey); + +/* ============================================================================ + * Public ECC APIs (with automatic endianness conversion) + * ============================================================================ + * All public key and DHKey parameters use big-endian format (BLE Mesh protocol). + * For little-endian crypto modules, conversion is handled automatically. + */ + +/** + * @brief Generate a new ECC public key pair + * + * Generates a new P-256 key pair for ECDH operations. + * The private key is stored internally. + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_pub_key_gen(void); + +/** + * @brief Get the current public key (raw pointer) + * + * Returns pointer to the internal public key storage. + * Note: The byte order depends on crypto module's native format. + * Use bt_mesh_pub_key_copy() to get big-endian format. + * + * @return Pointer to 64-byte public key, or NULL if not ready + */ +#define bt_mesh_pub_key_get() bt_mesh_pub_key_get_raw() + +/** + * @brief Copy current public key to user buffer (big-endian output) + * + * Copies the public key to the provided buffer, converting to big-endian + * format (BLE Mesh protocol format) if necessary. + * + * @param buf 64-byte output buffer for public key (big-endian output) + * + * @return 0 on success, -EAGAIN if public key not ready + */ +static inline int bt_mesh_pub_key_copy(uint8_t *buf) +{ + const uint8_t *key = bt_mesh_pub_key_get_raw(); + + if (key == NULL || buf == NULL) { + return -EAGAIN; + } + +#if (BT_MESH_CRYPTO_ENDIAN == BT_MESH_CRYPTO_ENDIAN_LITTLE) + /* Swap X and Y coordinates separately to big-endian */ + sys_memcpy_swap(buf, key, 32); + sys_memcpy_swap(buf + 32, key + 32, 32); +#else + memcpy(buf, key, PUB_KEY_SIZE); +#endif + + return 0; +} + +/** + * @brief Set a custom private key + * + * @param pri_key 32-byte private key (big-endian, BLE Mesh format) + */ +static inline void bt_mesh_set_private_key(const uint8_t pri_key[32]) +{ + CRYPTO_PARAM_DECLARE(pri_key, PRIV_KEY_SIZE); + CRYPTO_PARAM_IN(pri_key, PRIV_KEY_SIZE); + bt_mesh_set_private_key_raw(CRYPTO_PARAM(pri_key)); +} + +/** + * @brief Check if a public key is valid + * + * Verifies that the given public key is a valid point on the P-256 curve. + * + * @param key 64-byte public key (X || Y, big-endian, BLE Mesh format) + * + * @return true if valid, false otherwise + */ +static inline bool bt_mesh_check_public_key(const uint8_t key[64]) +{ + CRYPTO_PARAM_DECLARE(key, PUB_KEY_SIZE); + CRYPTO_PARAM_PUBKEY_IN(key); + return bt_mesh_check_public_key_raw(CRYPTO_PARAM(key)); +} + +/** + * @brief Generate ECDH shared secret (DHKey) + * + * @param pub_key 64-byte remote public key (X || Y, big-endian, BLE Mesh format) + * @param priv_key 32-byte private key (NULL to use internal key) + * @param dhkey 32-byte output buffer for shared secret (big-endian output) + * + * @return 0 on success, negative error code otherwise + */ +static inline int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) +{ + int rc; + CRYPTO_PARAM_DECLARE(pub_key, PUB_KEY_SIZE); + CRYPTO_PARAM_DECLARE(priv_key, PRIV_KEY_SIZE); + CRYPTO_PARAM_DECLARE(dhkey, DH_KEY_SIZE); + + /* Public key: swap X and Y coordinates separately */ + CRYPTO_PARAM_PUBKEY_IN(pub_key); + if (priv_key != NULL) { + CRYPTO_PARAM_IN(priv_key, PRIV_KEY_SIZE); + } + + rc = bt_mesh_dhkey_gen_raw(CRYPTO_PARAM(pub_key), + priv_key ? CRYPTO_PARAM(priv_key) : NULL, + CRYPTO_PARAM(dhkey)); + if (rc) { + return rc; + } + + CRYPTO_PARAM_OUT(dhkey, DH_KEY_SIZE); + return rc; +} + +#define bt_mesh_dh_key_gen(pubkey, dhkey) bt_mesh_dhkey_gen(pubkey, NULL, dhkey) + +/** + * @brief Import a raw key into mesh key structure + * + * @param type Key type (determines key usage) + * @param in 16-byte raw key + * @param out Output mesh key structure + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], + struct bt_mesh_key *out); + +/** + * @brief Export raw key bytes from mesh key structure + * + * @param out 16-byte output buffer + * @param in Input mesh key structure + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in); + +/** + * @brief Assign (copy) a mesh key + * + * @param dst Destination mesh key + * @param src Source mesh key + */ +void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src); + +/** + * @brief Destroy a mesh key + * + * Releases any resources associated with the key. + * + * @param key Mesh key to destroy + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_key_destroy(const struct bt_mesh_key *key); + +/** + * @brief Compare a raw key with a mesh key + * + * @param raw_key 16-byte raw key + * @param key Mesh key structure to compare + * + * @return 0 if equal, non-zero otherwise + */ +int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key); + +/** + * @brief AES encryption (little-endian byte order) + * + * The key and plaintext are byte-swapped before encryption, + * and the result is byte-swapped after encryption. + * + * @param key 16-byte key + * @param plaintext 16-byte plaintext + * @param enc_data 16-byte output buffer + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]); + +/** + * @brief AES encryption (big-endian byte order) + * + * Standard AES-ECB encryption without byte swapping. + * + * @param key 16-byte key + * @param plaintext 16-byte plaintext + * @param enc_data 16-byte output buffer + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]); +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_CRYPTO_H_ */ diff --git a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c index a322c0ab86..3826ca5c25 100644 --- a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-2016 Intel Corporation - * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,14 +17,6 @@ #include "p_256_ecc_pp.h" #include "osi/future.h" #include "device/controller.h" - -#if CONFIG_MBEDTLS_HARDWARE_AES -#include "mbedtls/aes.h" -#endif - -#include -#include - #include "mesh/hci.h" #include "mesh/adapter.h" #include "mesh/common.h" @@ -56,10 +48,6 @@ struct bt_mesh_dev bt_mesh_dev; */ #define BLE_MESH_DEV 0 -/* P-256 Variables */ -static uint8_t bt_mesh_public_key[64]; -static uint8_t bt_mesh_private_key[32]; - /* Scan related functions */ static bt_mesh_scan_cb_t *bt_mesh_scan_dev_found_cb; @@ -2481,185 +2469,9 @@ void bt_mesh_gatt_deinit(void) void bt_mesh_adapt_init(void) { - /* initialization of P-256 parameters */ - p_256_init_curve(KEY_LENGTH_DWORDS_P256); - - /* Set "bt_mesh_dev.flags" to 0 (only the "BLE_MESH_DEV_HAS_PUB_KEY" - * flag is used) here, because we need to make sure each time after - * the private key is initialized, a corresponding public key must - * be generated. - */ + /* Use unified crypto module initialization */ + bt_mesh_crypto_init(); bt_mesh_atomic_set(bt_mesh_dev.flags, 0); - bt_mesh_rand(bt_mesh_private_key, sizeof(bt_mesh_private_key)); -} - -void bt_mesh_set_private_key(const uint8_t pri_key[32]) -{ - memcpy(bt_mesh_private_key, pri_key, 32); -} - -const uint8_t *bt_mesh_pub_key_get(void) -{ - uint8_t private_key[32] = {0}; - Point public_key = {0}; - - if (bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY)) { - return bt_mesh_public_key; - } - - /* BLE Mesh BQB test case MESH/NODE/PROV/UPD/BV-12-C requires - * different public key for each provisioning procedure. - * Note: if enabled, when Provisioner provision multiple devices - * at the same time, this may cause invalid confirmation value. - * - * Use the following code for generating different private key - * for each provisioning procedure. - * - * if (bt_mesh_rand(bt_mesh_private_key, BT_OCTET32_LEN)) { - * BT_ERR("%s, Unable to generate bt_mesh_private_key", __func__); - * return NULL; - * } - */ - - memcpy(private_key, bt_mesh_private_key, BT_OCTET32_LEN); - ECC_PointMult(&public_key, &(curve_p256.G), (DWORD *)private_key, KEY_LENGTH_DWORDS_P256); - - memcpy(bt_mesh_public_key, public_key.x, BT_OCTET32_LEN); - memcpy(bt_mesh_public_key + BT_OCTET32_LEN, public_key.y, BT_OCTET32_LEN); - - bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY); - - BT_DBG("Public Key %s", bt_hex(bt_mesh_public_key, sizeof(bt_mesh_public_key))); - - return bt_mesh_public_key; -} - -bool bt_mesh_check_public_key(const uint8_t key[64]) -{ - struct p256_pub_key { - uint8_t x[32]; - uint8_t y[32]; - } check = {0}; - - sys_memcpy_swap(check.x, key, 32); - sys_memcpy_swap(check.y, key + 32, 32); - - return ECC_CheckPointIsInElliCur_P256((Point *)&check); -} - -int bt_mesh_dh_key_gen(const uint8_t remote_pub_key[64], uint8_t dhkey[32]) -{ - uint8_t private_key[32] = {0}; - Point peer_pub_key = {0}; - Point new_pub_key = {0}; - - BT_DBG("private key = %s", bt_hex(bt_mesh_private_key, BT_OCTET32_LEN)); - - memcpy(private_key, bt_mesh_private_key, BT_OCTET32_LEN); - memcpy(peer_pub_key.x, remote_pub_key, BT_OCTET32_LEN); - memcpy(peer_pub_key.y, &remote_pub_key[BT_OCTET32_LEN], BT_OCTET32_LEN); - - BT_DBG("remote public key x = %s", bt_hex(peer_pub_key.x, BT_OCTET32_LEN)); - BT_DBG("remote public key y = %s", bt_hex(peer_pub_key.y, BT_OCTET32_LEN)); - - ECC_PointMult(&new_pub_key, &peer_pub_key, (DWORD *)private_key, KEY_LENGTH_DWORDS_P256); - - BT_DBG("new public key x = %s", bt_hex(new_pub_key.x, 32)); - BT_DBG("new public key y = %s", bt_hex(new_pub_key.y, 32)); - - memcpy(dhkey, new_pub_key.x, 32); - - return 0; -} - -int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]) -{ - uint8_t tmp[16] = {0}; - - BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); - -#if CONFIG_MBEDTLS_HARDWARE_AES - mbedtls_aes_context ctx = {0}; - - mbedtls_aes_init(&ctx); - - sys_memcpy_swap(tmp, key, 16); - - if (mbedtls_aes_setkey_enc(&ctx, tmp, 128) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - sys_memcpy_swap(tmp, plaintext, 16); - - if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, - tmp, enc_data) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - mbedtls_aes_free(&ctx); -#else /* CONFIG_MBEDTLS_HARDWARE_AES */ - struct tc_aes_key_sched_struct s = {0}; - - sys_memcpy_swap(tmp, key, 16); - - if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) { - return -EINVAL; - } - - sys_memcpy_swap(tmp, plaintext, 16); - - if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) { - return -EINVAL; - } -#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ - - sys_mem_swap(enc_data, 16); - - BT_DBG("enc_data %s", bt_hex(enc_data, 16)); - - return 0; -} - -int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]) -{ - BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); - -#if CONFIG_MBEDTLS_HARDWARE_AES - mbedtls_aes_context ctx = {0}; - - mbedtls_aes_init(&ctx); - - if (mbedtls_aes_setkey_enc(&ctx, key, 128) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, - plaintext, enc_data) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - mbedtls_aes_free(&ctx); -#else /* CONFIG_MBEDTLS_HARDWARE_AES */ - struct tc_aes_key_sched_struct s = {0}; - - if (tc_aes128_set_encrypt_key(&s, key) == TC_CRYPTO_FAIL) { - return -EINVAL; - } - - if (tc_aes_encrypt(enc_data, plaintext, &s) == TC_CRYPTO_FAIL) { - return -EINVAL; - } -#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ - - BT_DBG("enc_data %s", bt_hex(enc_data, 16)); - - return 0; } #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN diff --git a/components/bt/esp_ble_mesh/core/crypto.c b/components/bt/esp_ble_mesh/core/crypto.c index 3adba0be1f..37102ae6ef 100644 --- a/components/bt/esp_ble_mesh/core/crypto.c +++ b/components/bt/esp_ble_mesh/core/crypto.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,12 +11,6 @@ #include #include -#include -#include -#include -#include -#include - #include "crypto.h" #include "mesh/config.h" #include "mesh/common.h" @@ -29,29 +23,7 @@ #define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4) #define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4) -int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, - size_t sg_len, uint8_t mac[16]) -{ - struct tc_aes_key_sched_struct sched = {0}; - struct tc_cmac_struct state = {0}; - - if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { - return -EIO; - } - - for (; sg_len; sg_len--, sg++) { - if (tc_cmac_update(&state, sg->data, - sg->len) == TC_CRYPTO_FAIL) { - return -EIO; - } - } - - if (tc_cmac_final(mac, &state) == TC_CRYPTO_FAIL) { - return -EIO; - } - - return 0; -} +/* bt_mesh_aes_cmac is now mapped to bt_mesh_aes_cmac_raw_key from common crypto module */ int bt_mesh_k1(const uint8_t *ikm, size_t ikm_len, const uint8_t salt[16], const char *info, uint8_t okm[16]) @@ -199,326 +171,9 @@ int bt_mesh_id128(const uint8_t n[16], const char *s, uint8_t out[16]) return bt_mesh_k1(n, 16, salt, id128, out); } -static int bt_mesh_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], - const uint8_t *enc_msg, size_t msg_len, - const uint8_t *aad, size_t aad_len, - uint8_t *out_msg, size_t mic_size) -{ - uint8_t msg[16] = {0}, pmsg[16] = {0}, cmic[16] = {0}, - cmsg[16] = {0}, Xn[16] = {0}, mic[16] = {0}; - uint16_t last_blk = 0U, blk_cnt = 0U; - size_t i = 0U, j = 0U; - int err = 0; - - if (msg_len < 1 || aad_len >= 0xff00) { - return -EINVAL; - } - - /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(0x0000, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmic); - if (err) { - return err; - } - - /* X_0 = e(AppKey, 0x09 || nonce || length) */ - if (mic_size == sizeof(uint64_t)) { - pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00); - } else { - pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00); - } - - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(msg_len, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* If AAD is being used to authenticate, include it here */ - if (aad_len) { - sys_put_be16(aad_len, pmsg); - - for (i = 0; i < sizeof(uint16_t); i++) { - pmsg[i] = Xn[i] ^ pmsg[i]; - } - - j = 0; - aad_len += sizeof(uint16_t); - while (aad_len > 16) { - do { - pmsg[i] = Xn[i] ^ aad[j]; - i++, j++; - } while (i < 16); - - aad_len -= 16; - i = 0; - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - - for (; i < aad_len; i++, j++) { - pmsg[i] = Xn[i] ^ aad[j]; - } - - for (i = aad_len; i < 16; i++) { - pmsg[i] = Xn[i]; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - - last_blk = msg_len % 16; - blk_cnt = (msg_len + 15) / 16; - if (!last_blk) { - last_blk = 16U; - } - - for (j = 0; j < blk_cnt; j++) { - if (j + 1 == blk_cnt) { - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_1 */ - for (i = 0; i < last_blk; i++) { - msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i]; - } - - memcpy(out_msg + (j * 16), msg, last_blk); - - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < last_blk; i++) { - pmsg[i] = Xn[i] ^ msg[i]; - } - - for (i = last_blk; i < 16; i++) { - pmsg[i] = Xn[i] ^ 0x00; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* MIC = C_mic ^ X_1 */ - for (i = 0; i < sizeof(mic); i++) { - mic[i] = cmic[i] ^ Xn[i]; - } - } else { - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_1 */ - for (i = 0; i < 16; i++) { - msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i]; - } - - memcpy(out_msg + (j * 16), msg, 16); - - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < 16; i++) { - pmsg[i] = Xn[i] ^ msg[i]; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - } - - if (memcmp(mic, enc_msg + msg_len, mic_size)) { - return -EBADMSG; - } - - return 0; -} - -static int bt_mesh_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], - const uint8_t *msg, size_t msg_len, - const uint8_t *aad, size_t aad_len, - uint8_t *out_msg, size_t mic_size) -{ - uint8_t pmsg[16] = {0}, cmic[16] = {0}, cmsg[16] = {0}, - mic[16] = {0}, Xn[16] = {0}; - uint16_t blk_cnt = 0U, last_blk = 0U; - size_t i = 0U, j = 0U; - int err = 0; - - BT_DBG("CCMEncrypt"); - BT_DBG("Key %s", bt_hex(key, 16)); - BT_DBG("Nonce %s", bt_hex(nonce, 13)); - BT_DBG("Len %u: %s", msg_len, bt_hex(msg, msg_len)); - BT_DBG("AADLen %u MicSize %u", aad_len, mic_size); - - /* Unsupported AAD size */ - if (aad_len >= 0xff00) { - return -EINVAL; - } - - /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(0x0000, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmic); - if (err) { - return err; - } - - /* X_0 = e(AppKey, 0x09 || nonce || length) */ - if (mic_size == sizeof(uint64_t)) { - pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00); - } else { - pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00); - } - - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(msg_len, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* If AAD is being used to authenticate, include it here */ - if (aad_len) { - sys_put_be16(aad_len, pmsg); - - for (i = 0; i < sizeof(uint16_t); i++) { - pmsg[i] = Xn[i] ^ pmsg[i]; - } - - j = 0; - aad_len += sizeof(uint16_t); - while (aad_len > 16) { - do { - pmsg[i] = Xn[i] ^ aad[j]; - i++, j++; - } while (i < 16); - - aad_len -= 16; - i = 0; - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - - for (; i < aad_len; i++, j++) { - pmsg[i] = Xn[i] ^ aad[j]; - } - - for (i = aad_len; i < 16; i++) { - pmsg[i] = Xn[i]; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - - last_blk = msg_len % 16; - blk_cnt = (msg_len + 15) / 16; - if (!last_blk) { - last_blk = 16U; - } - - for (j = 0; j < blk_cnt; j++) { - if (j + 1 == blk_cnt) { - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < last_blk; i++) { - pmsg[i] = Xn[i] ^ msg[(j * 16) + i]; - } - for (i = last_blk; i < 16; i++) { - pmsg[i] = Xn[i] ^ 0x00; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* MIC = C_mic ^ X_1 */ - for (i = 0; i < sizeof(mic); i++) { - mic[i] = cmic[i] ^ Xn[i]; - } - - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_1 */ - for (i = 0; i < last_blk; i++) { - out_msg[(j * 16) + i] = - msg[(j * 16) + i] ^ cmsg[i]; - } - } else { - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < 16; i++) { - pmsg[i] = Xn[i] ^ msg[(j * 16) + i]; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_N */ - for (i = 0; i < 16; i++) { - out_msg[(j * 16) + i] = - msg[(j * 16) + i] ^ cmsg[i]; - } - - } - } - - memcpy(out_msg + msg_len, mic, mic_size); - - return 0; -} +/* Use the unified crypto module for CCM operations */ +#define bt_mesh_ccm_decrypt bt_mesh_ccm_decrypt_raw_key +#define bt_mesh_ccm_encrypt bt_mesh_ccm_encrypt_raw_key #if CONFIG_BLE_MESH_PROXY static void create_proxy_nonce(uint8_t nonce[13], const uint8_t *pdu, diff --git a/components/bt/esp_ble_mesh/core/crypto.h b/components/bt/esp_ble_mesh/core/crypto.h index 69627c956b..5d5ecbc375 100644 --- a/components/bt/esp_ble_mesh/core/crypto.h +++ b/components/bt/esp_ble_mesh/core/crypto.h @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,26 +12,17 @@ #include #include "mesh/buf.h" +#include "mesh/crypto.h" /* Include common crypto API */ #ifdef __cplusplus extern "C" { #endif -struct bt_mesh_sg { - const void *data; - size_t len; -}; +/* Map bt_mesh_aes_cmac to bt_mesh_aes_cmac_raw_key from common crypto module. + * struct bt_mesh_sg is defined in mesh/crypto.h */ +#define bt_mesh_aes_cmac bt_mesh_aes_cmac_raw_key -int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, - size_t sg_len, uint8_t mac[16]); - -static inline int bt_mesh_aes_cmac_one(const uint8_t key[16], const void *m, - size_t len, uint8_t mac[16]) -{ - struct bt_mesh_sg sg = { m, len }; - - return bt_mesh_aes_cmac(key, &sg, 1, mac); -} +/* bt_mesh_aes_cmac_one is defined as inline in mesh/crypto.h */ static inline bool bt_mesh_s1(const char *m, uint8_t salt[16]) { diff --git a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h index 20c656e690..ee06bff7f8 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-2017 Intel Corporation - * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ #include "mesh/utils.h" #include "mesh/uuid.h" #include "mesh/buf.h" +#include "mesh/crypto.h" #ifdef __cplusplus extern "C" { @@ -932,20 +933,6 @@ void bt_mesh_gatt_deinit(void); void bt_mesh_adapt_init(void); -void bt_mesh_set_private_key(const uint8_t pri_key[32]); - -const uint8_t *bt_mesh_pub_key_get(void); - -bool bt_mesh_check_public_key(const uint8_t key[64]); - -int bt_mesh_dh_key_gen(const uint8_t remote_pub_key[64], uint8_t dhkey[32]); - -int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]); - -int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]); - enum { BLE_MESH_EXCEP_LIST_SUB_CODE_ADD = 0, BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, diff --git a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c index 1992fb87b3..5b7c82e567 100644 --- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-2016 Intel Corporation - * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,20 +10,12 @@ #include "btc/btc_task.h" #include "osi/alarm.h" - -#include "mbedtls/aes.h" -#include "mbedtls/ecp.h" - #include "host/ble_hs.h" #include "host/ble_uuid.h" #include "host/ble_att.h" #include "host/ble_gatt.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" - -#include -#include - #include "mesh/hci.h" #include "mesh/common.h" #include "prov_pvnr.h" @@ -65,10 +57,6 @@ static uint16_t proxy_svc_start_handle, prov_svc_start_handle; struct bt_mesh_dev bt_mesh_dev; -/* P-256 Variables */ -static uint8_t bt_mesh_public_key[64]; -static uint8_t bt_mesh_private_key[32]; - /* Scan related functions */ static bt_mesh_scan_cb_t *bt_mesh_scan_dev_found_cb; #if CONFIG_BLE_MESH_NODE @@ -2606,199 +2594,11 @@ void bt_mesh_gatt_deinit(void) } #endif /* CONFIG_BLE_MESH_DEINIT */ -void ble_sm_alg_ecc_init(void); - void bt_mesh_adapt_init(void) { - /* initialization of P-256 parameters */ - ble_sm_alg_ecc_init(); - - /* Set "bt_mesh_dev.flags" to 0 (only the "BLE_MESH_DEV_HAS_PUB_KEY" - * flag is used) here, because we need to make sure each time after - * the private key is initialized, a corresponding public key must - * be generated. - */ + /* Use unified crypto module initialization */ + bt_mesh_crypto_init(); bt_mesh_atomic_set(bt_mesh_dev.flags, 0); - bt_mesh_rand(bt_mesh_private_key, sizeof(bt_mesh_private_key)); -} - -void bt_mesh_set_private_key(const uint8_t pri_key[32]) -{ - memcpy(bt_mesh_private_key, pri_key, 32); -} - -int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); - -const uint8_t *bt_mesh_pub_key_get(void) -{ - uint8_t pri_key[32] = {0}; - -#if 1 - if (bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY)) { - return bt_mesh_public_key; - } -#else - /* BLE Mesh BQB test case MESH/NODE/PROV/UPD/BV-12-C requires - * different public key for each provisioning procedure. - * Note: if enabled, when Provisioner provision multiple devices - * at the same time, this may cause invalid confirmation value. - */ - if (bt_mesh_rand(bt_mesh_private_key, 32)) { - BT_ERR("%s, Unable to generate bt_mesh_private_key", __func__); - return NULL; - } -#endif - - int rc = ble_sm_alg_gen_key_pair(bt_mesh_public_key, pri_key); - if (rc != 0) { - BT_ERR("Failed to generate the key pair"); - return NULL; - } - memcpy(bt_mesh_private_key, pri_key, 32); - - bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY); - - BT_DBG("Public Key %s", bt_hex(bt_mesh_public_key, sizeof(bt_mesh_public_key))); - - return bt_mesh_public_key; -} - -bool bt_mesh_check_public_key(const uint8_t key[64]) -{ - struct mbedtls_ecp_point pt = {0}; - mbedtls_ecp_group grp = {0}; - bool rc = false; - - uint8_t pub[65] = {0}; - /* Hardcoded first byte of pub key for MBEDTLS_ECP_PF_UNCOMPRESSED */ - pub[0] = 0x04; - memcpy(&pub[1], key, 64); - - /* Initialize the required structures here */ - mbedtls_ecp_point_init(&pt); - mbedtls_ecp_group_init(&grp); - - /* Below 3 steps are to validate public key on curve secp256r1 */ - if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) != 0) { - goto exit; - } - - if (mbedtls_ecp_point_read_binary(&grp, &pt, pub, 65) != 0) { - goto exit; - } - - if (mbedtls_ecp_check_pubkey(&grp, &pt) != 0) { - goto exit; - } - - rc = true; - -exit: - mbedtls_ecp_point_free(&pt); - mbedtls_ecp_group_free(&grp); - return rc; - -} - -int ble_sm_alg_gen_dhkey(uint8_t *peer_pub_key_x, uint8_t *peer_pub_key_y, - uint8_t *our_priv_key, uint8_t *out_dhkey); - -int bt_mesh_dh_key_gen(const uint8_t remote_pub_key[64], uint8_t dhkey[32]) -{ - BT_DBG("private key = %s", bt_hex(bt_mesh_private_key, 32)); - - return ble_sm_alg_gen_dhkey((uint8_t *)&remote_pub_key[0], (uint8_t *)&remote_pub_key[32], - bt_mesh_private_key, dhkey); -} - -int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]) -{ - uint8_t tmp[16] = {0}; - - BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); - -#if CONFIG_MBEDTLS_HARDWARE_AES - mbedtls_aes_context ctx = {0}; - - mbedtls_aes_init(&ctx); - - sys_memcpy_swap(tmp, key, 16); - - if (mbedtls_aes_setkey_enc(&ctx, tmp, 128) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - sys_memcpy_swap(tmp, plaintext, 16); - - if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, - tmp, enc_data) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - mbedtls_aes_free(&ctx); -#else /* CONFIG_MBEDTLS_HARDWARE_AES */ - struct tc_aes_key_sched_struct s = {0}; - - sys_memcpy_swap(tmp, key, 16); - - if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) { - return -EINVAL; - } - - sys_memcpy_swap(tmp, plaintext, 16); - - if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) { - return -EINVAL; - } -#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ - - sys_mem_swap(enc_data, 16); - - BT_DBG("enc_data %s", bt_hex(enc_data, 16)); - - return 0; -} - -int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]) -{ - BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); - -#if CONFIG_MBEDTLS_HARDWARE_AES - mbedtls_aes_context ctx = {0}; - - mbedtls_aes_init(&ctx); - - if (mbedtls_aes_setkey_enc(&ctx, key, 128) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, - plaintext, enc_data) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - mbedtls_aes_free(&ctx); -#else /* CONFIG_MBEDTLS_HARDWARE_AES */ - struct tc_aes_key_sched_struct s = {0}; - - if (tc_aes128_set_encrypt_key(&s, key) == TC_CRYPTO_FAIL) { - return -EINVAL; - } - - if (tc_aes_encrypt(enc_data, plaintext, &s) == TC_CRYPTO_FAIL) { - return -EINVAL; - } -#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ - - BT_DBG("enc_data %s", bt_hex(enc_data, 16)); - - return 0; } #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN diff --git a/components/bt/esp_ble_mesh/core/prov_node.c b/components/bt/esp_ble_mesh/core/prov_node.c index 973239097d..15f24bf3d6 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.c +++ b/components/bt/esp_ble_mesh/core/prov_node.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -616,7 +616,7 @@ int bt_mesh_input_string(const char *str) static void send_pub_key(void) { - const uint8_t *key = NULL; + uint8_t pub_key[64] = {0}; uint8_t dhkey[32] = {0}; PROV_BUF(buf, 65); @@ -625,8 +625,8 @@ static void send_pub_key(void) * buffer as a temporary storage location. The validating * of the remote public key is finished when it is received. */ - sys_memcpy_swap(buf.data, &prov_link.conf_inputs[17], 32); - sys_memcpy_swap(&buf.data[32], &prov_link.conf_inputs[49], 32); + memcpy(buf.data, &prov_link.conf_inputs[17], 32); + memcpy(&buf.data[32], &prov_link.conf_inputs[49], 32); if (bt_mesh_dh_key_gen(buf.data, dhkey)) { BT_ERR("Unable to generate DHKey"); @@ -634,26 +634,25 @@ static void send_pub_key(void) return; } - sys_memcpy_swap(prov_link.dhkey, dhkey, 32); + memcpy(prov_link.dhkey, dhkey, 32); BT_DBG("DHkey: %s", bt_hex(prov_link.dhkey, 32)); bt_mesh_atomic_set_bit(prov_link.flags, HAVE_DHKEY); - key = bt_mesh_pub_key_get(); - if (!key) { + if (bt_mesh_pub_key_copy(pub_key)) { BT_ERR("No public key available"); close_link(PROV_ERR_UNEXP_ERR); return; } - BT_DBG("Local Public Key: %s", bt_hex(key, 64)); + BT_DBG("Local Public Key: %s", bt_hex(pub_key, 64)); bt_mesh_prov_buf_init(&buf, PROV_PUB_KEY); - /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(net_buf_simple_add(&buf, 32), key, 32); - sys_memcpy_swap(net_buf_simple_add(&buf, 32), &key[32], 32); + /* Public key is already in big-endian format from bt_mesh_pub_key_copy() */ + memcpy(net_buf_simple_add(&buf, 32), pub_key, 32); + memcpy(net_buf_simple_add(&buf, 32), &pub_key[32], 32); memcpy(&prov_link.conf_inputs[81], &buf.data[1], 64); @@ -673,8 +672,8 @@ static int bt_mesh_calc_dh_key(void) /* Copy remote key in little-endian for generating DHKey. * X and Y halves are swapped independently. */ - sys_memcpy_swap(&pub_key[0], &prov_link.conf_inputs[17], 32); - sys_memcpy_swap(&pub_key[32], &prov_link.conf_inputs[49], 32); + memcpy(&pub_key[0], &prov_link.conf_inputs[17], 32); + memcpy(&pub_key[32], &prov_link.conf_inputs[49], 32); if (bt_mesh_dh_key_gen(pub_key, dhkey)) { BT_ERR("Unable to generate DHKey"); @@ -682,7 +681,7 @@ static int bt_mesh_calc_dh_key(void) return -EIO; } - sys_memcpy_swap(prov_link.dhkey, dhkey, 32); + memcpy(prov_link.dhkey, dhkey, 32); BT_DBG("DHkey: %s", bt_hex(prov_link.dhkey, 32)); @@ -704,6 +703,8 @@ int bt_mesh_set_oob_pub_key(const uint8_t pub_key_x[32], const uint8_t pub_key_y[32], const uint8_t pri_key[32]) { + uint8_t privkey[32] = {0}; + if (!pub_key_x || !pub_key_y || !pri_key) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -715,7 +716,8 @@ int bt_mesh_set_oob_pub_key(const uint8_t pub_key_x[32], */ sys_memcpy_swap(&prov_link.conf_inputs[81], pub_key_x, 32); sys_memcpy_swap(&prov_link.conf_inputs[81] + 32, pub_key_y, 32); - bt_mesh_set_private_key(pri_key); + sys_memcpy_swap(privkey, pri_key, 32); + bt_mesh_set_private_key(privkey); bt_mesh_atomic_set_bit(prov_link.flags, OOB_PUB_KEY); @@ -1558,8 +1560,6 @@ static void protocol_timeout(struct k_work *work) int bt_mesh_prov_init(void) { - const uint8_t *key = NULL; - if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return -EINVAL; @@ -1574,8 +1574,7 @@ int bt_mesh_prov_init(void) __ASSERT(bt_mesh_prov_get()->uuid, "Device UUID not initialized"); - key = bt_mesh_pub_key_get(); - if (!key) { + if (bt_mesh_pub_key_gen()) { BT_ERR("Failed to generate public key"); return -EIO; } diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.c b/components/bt/esp_ble_mesh/core/prov_pvnr.c index d1df4a69e1..26fb72e167 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -1764,8 +1764,8 @@ static void prov_gen_dh_key(struct bt_mesh_prov_link *link) /* Copy public key in little-endian for generating DHKey. * X and Y halves are swapped independently. */ - sys_memcpy_swap(&pub_key[0], &link->conf_inputs[81], 32); - sys_memcpy_swap(&pub_key[32], &link->conf_inputs[113], 32); + memcpy(&pub_key[0], &link->conf_inputs[81], 32); + memcpy(&pub_key[32], &link->conf_inputs[113], 32); if (bt_mesh_dh_key_gen(pub_key, dhkey)) { BT_ERR("Failed to generate DHKey"); @@ -1773,7 +1773,7 @@ static void prov_gen_dh_key(struct bt_mesh_prov_link *link) return; } - sys_memcpy_swap(link->dhkey, dhkey, 32); + memcpy(link->dhkey, dhkey, 32); BT_DBG("DHKey: %s", bt_hex(link->dhkey, 32)); @@ -1847,23 +1847,22 @@ static void prov_gen_dh_key(struct bt_mesh_prov_link *link) static void send_pub_key(struct bt_mesh_prov_link *link) { - const uint8_t *key = NULL; + uint8_t pub_key[64] = {0}; PROV_BUF(buf, 65); - key = bt_mesh_pub_key_get(); - if (!key) { + if (bt_mesh_pub_key_copy(pub_key)) { BT_ERR("No public key available"); close_link(link, CLOSE_REASON_FAILED); return; } - BT_DBG("Local Public Key: %s", bt_hex(key, 64)); + BT_DBG("Local Public Key: %s", bt_hex(pub_key, 64)); bt_mesh_prov_buf_init(&buf, PROV_PUB_KEY); - /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(net_buf_simple_add(&buf, 32), key, 32); - sys_memcpy_swap(net_buf_simple_add(&buf, 32), &key[32], 32); + /* Public key is already in big-endian format from bt_mesh_pub_key_copy() */ + memcpy(net_buf_simple_add(&buf, 32), pub_key, 32); + memcpy(net_buf_simple_add(&buf, 32), &pub_key[32], 32); /* Store provisioner public key value in conf_inputs */ memcpy(&link->conf_inputs[17], &buf.data[1], 64); @@ -2819,7 +2818,6 @@ static void protocol_timeout(struct k_work *work) int bt_mesh_provisioner_prov_init(void) { - const uint8_t *key = NULL; int i; if (bt_mesh_prov_get() == NULL) { @@ -2827,8 +2825,7 @@ int bt_mesh_provisioner_prov_init(void) return -EINVAL; } - key = bt_mesh_pub_key_get(); - if (!key) { + if (bt_mesh_pub_key_gen()) { BT_ERR("Failed to generate Public Key"); return -EIO; } diff --git a/components/bt/esp_ble_mesh/lib/ext.c b/components/bt/esp_ble_mesh/lib/ext.c index db62c25c49..0eadd4ac1e 100644 --- a/components/bt/esp_ble_mesh/lib/ext.c +++ b/components/bt/esp_ble_mesh/lib/ext.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,8 +39,6 @@ #include "lpn.h" #include "rpl.h" #include "foundation.h" -#include -#include #include "mesh/buf.h" #include "mesh/slist.h" #include "mesh/config.h" @@ -566,24 +564,9 @@ int bt_mesh_ext_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, return bt_mesh_net_decrypt(key, buf, iv_index, proxy, proxy_solic); } -int bt_mesh_ext_tc_hmac_set_key(void *ctx, const uint8_t *key, unsigned int key_size) +int bt_mesh_ext_hmac_sha_256(const uint8_t key[32], struct bt_mesh_sg *sg, size_t sg_len, uint8_t mac[32]) { - return tc_hmac_set_key(ctx, key, key_size); -} - -int bt_mesh_ext_tc_hmac_init(void *ctx) -{ - return tc_hmac_init(ctx); -} - -int bt_mesh_ext_tc_hmac_update(void *ctx, const void *data, unsigned int data_length) -{ - return tc_hmac_update(ctx, data, data_length); -} - -int bt_mesh_ext_tc_hmac_final(uint8_t *tag, unsigned int taglen, void *ctx) -{ - return tc_hmac_final(tag, taglen, ctx); + return bt_mesh_sha256_hmac_raw_key(key, sg, sg_len, mac); } /* Mutex */ @@ -4278,12 +4261,6 @@ static const bt_mesh_ext_config_t bt_mesh_ext_cfg = { .struct_addr_off_val = offsetof(bt_mesh_addr_t, val), .struct_sg_size = sizeof(struct bt_mesh_sg), .struct_sg_off_len = offsetof(struct bt_mesh_sg, len), - .struct_tc_sha256_state = sizeof(struct tc_sha256_state_struct), - .struct_tc_sha256_off_bits_hashed = offsetof(struct tc_sha256_state_struct, bits_hashed), - .struct_tc_sha256_off_leftover = offsetof(struct tc_sha256_state_struct, leftover), - .struct_tc_sha256_off_leftover_offset = offsetof(struct tc_sha256_state_struct, leftover_offset), - .struct_tc_hmac_state_size = sizeof(struct tc_hmac_state_struct), - .struct_tc_hmac_state_off_key = offsetof(struct tc_hmac_state_struct, key), .btc_ble_mesh_evt_agg_client_send_timeout = BTC_BLE_MESH_EVT_AGG_CLIENT_SEND_TIMEOUT, .btc_ble_mesh_evt_agg_client_recv_rsp = BTC_BLE_MESH_EVT_AGG_CLIENT_RECV_RSP, diff --git a/components/bt/esp_ble_mesh/lib/lib b/components/bt/esp_ble_mesh/lib/lib index 85e64e61f8..e44762384e 160000 --- a/components/bt/esp_ble_mesh/lib/lib +++ b/components/bt/esp_ble_mesh/lib/lib @@ -1 +1 @@ -Subproject commit 85e64e61f8471f34bd940e1fe1bdc92f58ed6bef +Subproject commit e44762384ed104a0ebc78f134eeba5f3ab648ddc diff --git a/components/bt/test_apps/basic_unit_test/main/CMakeLists.txt b/components/bt/test_apps/basic_unit_test/main/CMakeLists.txt index 6aecb24e3d..d873380d2b 100644 --- a/components/bt/test_apps/basic_unit_test/main/CMakeLists.txt +++ b/components/bt/test_apps/basic_unit_test/main/CMakeLists.txt @@ -4,3 +4,10 @@ idf_component_register(SRCS "test_bt_main.c" INCLUDE_DIRS "." PRIV_REQUIRES unity bt WHOLE_ARCHIVE) + +# Add private include directories from bt component to access internal headers +idf_component_get_property(bt_dir bt COMPONENT_DIR) +target_include_directories(${COMPONENT_LIB} PRIVATE ${bt_dir}/host/bluedroid/stack/smp/include) +target_include_directories(${COMPONENT_LIB} PRIVATE ${bt_dir}/host/bluedroid/common/include) +target_include_directories(${COMPONENT_LIB} PRIVATE ${bt_dir}/host/bluedroid/stack/include) +target_include_directories(${COMPONENT_LIB} PRIVATE ${bt_dir}/common/include) diff --git a/components/bt/test_apps/basic_unit_test/main/test_smp.c b/components/bt/test_apps/basic_unit_test/main/test_smp.c index ea89ec261b..01bbc5b64c 100644 --- a/components/bt/test_apps/basic_unit_test/main/test_smp.c +++ b/components/bt/test_apps/basic_unit_test/main/test_smp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -18,42 +18,14 @@ #include "esp_bt_main.h" #include "esp_bt_device.h" #include "esp_gap_ble_api.h" +#include "sdkconfig.h" + +#if defined(CONFIG_BT_SMP_CRYPTO_STACK_NATIVE) && CONFIG_BT_SMP_CRYPTO_STACK_NATIVE +/* Native Bluedroid crypto implementation tests */ +#include "p_256_ecc_pp.h" #define KEY_LENGTH_DWORDS_P256 8 -typedef unsigned long DWORD; -typedef uint32_t UINT32; - -typedef struct { - DWORD x[KEY_LENGTH_DWORDS_P256]; - DWORD y[KEY_LENGTH_DWORDS_P256]; - DWORD z[KEY_LENGTH_DWORDS_P256]; -} Point; - -typedef struct { - // curve's coefficients - DWORD a[KEY_LENGTH_DWORDS_P256]; - DWORD b[KEY_LENGTH_DWORDS_P256]; - - //whether a is -3 - int a_minus3; - - // prime modulus - DWORD p[KEY_LENGTH_DWORDS_P256]; - - // Omega, p = 2^m -omega - DWORD omega[KEY_LENGTH_DWORDS_P256]; - - // base point, a point on E of order r - Point G; - -} elliptic_curve_t; - -extern void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength); -extern bool ECC_CheckPointIsInElliCur_P256(Point *p); -extern void p_256_init_curve(UINT32 keyLength); -extern elliptic_curve_t curve_p256; - static void bt_rand(void *buf, size_t len) { if (!len) { @@ -70,7 +42,17 @@ static void bt_rand(void *buf, size_t len) return; } -TEST_CASE("ble_smp_public_key_check", "[ble_smp]") +/** + * @brief Test ECC public key validation for native Bluedroid crypto implementation + * + * This test is only compiled when SMP_CRYPTO_STACK_NATIVE is enabled. + * It tests the native Bluedroid ECC implementation including: + * - Public key generation from private key + * - Public key validation on elliptic curve + * - Attack simulation (invalid public key detection) + * - Random key generation and validation + */ +TEST_CASE("ble_smp_public_key_check", "[ble_smp][native_crypto]") { /* We wait init finish 200ms here */ vTaskDelay(200 / portTICK_PERIOD_MS); @@ -96,7 +78,14 @@ TEST_CASE("ble_smp_public_key_check", "[ble_smp]") TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&public_key)); } } +#endif /* CONFIG_BT_SMP_CRYPTO_STACK_NATIVE */ +/** + * @brief Test static passkey set/clear functionality + * + * This test is applicable to all crypto stack implementations (Native, TinyCrypt, mbedTLS). + * It tests the SMP security parameter API for setting and clearing static passkeys. + */ TEST_CASE("ble_smp_set_clear_static_passkey", "[ble_smp]") { /* We wait init finish 200ms here */