From b8571b135847d6d6a5fd13495159086fd4123f6a Mon Sep 17 00:00:00 2001 From: luoxu Date: Thu, 25 Dec 2025 20:28:45 +0800 Subject: [PATCH] feat(ble_mesh): supported using little endian crypto components --- .../bt/esp_ble_mesh/common/crypto_mbedtls.c | 10 +- .../bt/esp_ble_mesh/common/crypto_psa.c | 10 +- components/bt/esp_ble_mesh/common/crypto_tc.c | 10 +- .../esp_ble_mesh/common/include/mesh/crypto.h | 187 ++++++++++++++++-- components/bt/esp_ble_mesh/core/prov_node.c | 13 +- components/bt/esp_ble_mesh/core/prov_pvnr.c | 12 +- 6 files changed, 203 insertions(+), 39 deletions(-) diff --git a/components/bt/esp_ble_mesh/common/crypto_mbedtls.c b/components/bt/esp_ble_mesh/common/crypto_mbedtls.c index 24b0b76308..5ff9670b5f 100644 --- a/components/bt/esp_ble_mesh/common/crypto_mbedtls.c +++ b/components/bt/esp_ble_mesh/common/crypto_mbedtls.c @@ -281,7 +281,7 @@ cleanup: return ret == 0 ? 0 : -EIO; } -const uint8_t *bt_mesh_pub_key_get(void) +const uint8_t *bt_mesh_pub_key_get_raw(void) { if (!dh_pair.is_ready) { if (bt_mesh_pub_key_gen() != 0) { @@ -292,7 +292,7 @@ const uint8_t *bt_mesh_pub_key_get(void) return dh_pair.public_key; } -void bt_mesh_set_private_key(const uint8_t pri_key[32]) +void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) { mbedtls_ecp_group grp; mbedtls_mpi d; @@ -343,7 +343,7 @@ cleanup: mbedtls_ecp_point_free(&Q); } -bool bt_mesh_check_public_key(const uint8_t key[64]) +bool bt_mesh_check_public_key_raw(const uint8_t key[64]) { mbedtls_ecp_group grp; mbedtls_ecp_point Q; @@ -382,8 +382,8 @@ cleanup: return ret == 0; } -int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, - uint8_t *dhkey) +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; diff --git a/components/bt/esp_ble_mesh/common/crypto_psa.c b/components/bt/esp_ble_mesh/common/crypto_psa.c index 9619700634..16dd15bca0 100644 --- a/components/bt/esp_ble_mesh/common/crypto_psa.c +++ b/components/bt/esp_ble_mesh/common/crypto_psa.c @@ -343,7 +343,7 @@ int bt_mesh_pub_key_gen(void) return 0; } -const uint8_t *bt_mesh_pub_key_get(void) +const uint8_t *bt_mesh_pub_key_get_raw(void) { if (!dh_pair.is_ready) { if (bt_mesh_pub_key_gen() != 0) { @@ -354,7 +354,7 @@ const uint8_t *bt_mesh_pub_key_get(void) return &dh_pair.public_key[1]; } -void bt_mesh_set_private_key(const uint8_t pri_key[32]) +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; @@ -396,7 +396,7 @@ void bt_mesh_set_private_key(const uint8_t pri_key[32]) psa_reset_key_attributes(&attributes); } -bool bt_mesh_check_public_key(const uint8_t key[64]) +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; @@ -425,8 +425,8 @@ bool bt_mesh_check_public_key(const uint8_t key[64]) return true; } -int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, - uint8_t *dhkey) +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]; diff --git a/components/bt/esp_ble_mesh/common/crypto_tc.c b/components/bt/esp_ble_mesh/common/crypto_tc.c index 9fd9e97b91..f4c780edd6 100644 --- a/components/bt/esp_ble_mesh/common/crypto_tc.c +++ b/components/bt/esp_ble_mesh/common/crypto_tc.c @@ -211,7 +211,7 @@ int bt_mesh_pub_key_gen(void) return 0; } -const uint8_t *bt_mesh_pub_key_get(void) +const uint8_t *bt_mesh_pub_key_get_raw(void) { if (!dh_pair.is_ready) { if (bt_mesh_pub_key_gen() != 0) { @@ -222,7 +222,7 @@ const uint8_t *bt_mesh_pub_key_get(void) return dh_pair.public_key; } -void bt_mesh_set_private_key(const uint8_t pri_key[32]) +void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) { int rc; @@ -239,13 +239,13 @@ void bt_mesh_set_private_key(const uint8_t pri_key[32]) dh_pair.is_ready = true; } -bool bt_mesh_check_public_key(const uint8_t key[64]) +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(const uint8_t *pub_key, const uint8_t *priv_key, - uint8_t *dhkey) +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"); diff --git a/components/bt/esp_ble_mesh/common/include/mesh/crypto.h b/components/bt/esp_ble_mesh/common/include/mesh/crypto.h index 38a8b3f208..806e84f479 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/crypto.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/crypto.h @@ -25,6 +25,87 @@ extern "C" { #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 */ @@ -214,6 +295,25 @@ static inline int bt_mesh_sha256_hmac_one(const uint8_t key[32], const void *m, 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 * @@ -225,41 +325,106 @@ static inline int bt_mesh_sha256_hmac_one(const uint8_t key[32], const void *m, int bt_mesh_pub_key_gen(void); /** - * @brief Get the current public key + * @brief Get the current public key (raw pointer) * - * @return Pointer to 64-byte public key (X || Y), or NULL if not ready + * 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 */ -const uint8_t *bt_mesh_pub_key_get(void); +#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[64]) +{ + const uint8_t *key = bt_mesh_pub_key_get_raw(); + + if (key == 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 + * @param pri_key 32-byte private key (big-endian, BLE Mesh format) */ -void bt_mesh_set_private_key(const uint8_t pri_key[32]); +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) + * @param key 64-byte public key (X || Y, big-endian, BLE Mesh format) * * @return true if valid, false otherwise */ -bool bt_mesh_check_public_key(const uint8_t key[64]); +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) + * @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 + * @param dhkey 32-byte output buffer for shared secret (big-endian output) * * @return 0 on success, negative error code otherwise */ -int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, - uint8_t *dhkey); +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) diff --git a/components/bt/esp_ble_mesh/core/prov_node.c b/components/bt/esp_ble_mesh/core/prov_node.c index 90ce7d9bde..dc550594df 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.c +++ b/components/bt/esp_ble_mesh/core/prov_node.c @@ -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); @@ -640,20 +640,19 @@ static void send_pub_key(void) 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 */ - memcpy(net_buf_simple_add(&buf, 32), key, 32); - memcpy(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); diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.c b/components/bt/esp_ble_mesh/core/prov_pvnr.c index 9e6beba21e..26fb72e167 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.c @@ -1847,22 +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); - memcpy(net_buf_simple_add(&buf, 32), key, 32); - memcpy(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);