This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to implement ECC functions on SDK v12.3.0 and nRF51822

Hello all.

few years ago, I made some product using nRF51822 on SDK v10.0.0

currently, I have to software update to use ECC(Elliptic Curve Cryptography) function on same hardware.

To implement ECC functions, I found several information as below

https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v12.0.0%2Fble_sdk_app_multirole_lesc.html

https://devzone.nordicsemi.com/f/nordic-q-a/10975/are-the-nrf51-devices-supporting-the-full-ble-4-2-features

In conclusion, above informations says that applications must include their own implementation of ECC

But recently I heard LESC specs are changed by Erratum 10734,

so I wonder the reference git hub source code for own implementation of ECC is valid.

of course I know, latest SDK version(SDK v15.x) adapted ECC functions and support API.but as I mentioned I can't change chipset or current hardware because of a number of important reason.

that means SDK v15.x doesn't support nRF51822. So now I have to use SDK v12.x  and apply the ECC functions

could someone help me on how to apply ECC function on SDK12.3.0

  • I found myself an answer to this question.

    I will close my question by myself.

  • Hi,

    The Relevant changes in nRF5 SDK v15.0.0 section in nWP031 - Security Threat in Bluetooth LESC Pairing describe the changes made for SDK 15, and you should do the same for older SDKs.

    Using the Experimental: BLE LE Secure Connections multirole example from SDK 12.3 as a reference, you should update the handling of the BLE_GAP_EVT_LESC_DHKEY_REQUEST request in main.c. There you should validate the remote peer public key and only calculate the shared secret if it is valid. If it is invalid, return a random shared secret to make pairing fail.

    I have made some modifications to the example main.c here, which uses uECC_valid_public_key() from micro-ecc via wrapper functions that I have added in the ECC interface module in the SDK (below).

    Diffs only:

    diff --git a/examples/ble_central_and_peripheral/experimental/ble_app_multirole_lesc/main.c b/examples/ble_central_and_peripheral/experimental/ble_app_multirole_lesc/main.c
    index 20d3c82..65cf2e3 100644
    --- a/examples/ble_central_and_peripheral/experimental/ble_app_multirole_lesc/main.c
    +++ b/examples/ble_central_and_peripheral/experimental/ble_app_multirole_lesc/main.c
    @@ -75,6 +75,8 @@
     #include "fstorage.h"
     #include "fds.h"
     #include "nrf_crypto.h"
    +#include "ecc.h"
    +#include "nrf_drv_rng.h"
     #define NRF_LOG_MODULE_NAME "APP"
     #include "nrf_log.h"
     #include "nrf_log_ctrl.h"
    @@ -678,8 +680,24 @@ static void on_ble_evt(uint16_t conn_handle, ble_evt_t * p_ble_evt)
                 NRF_LOG_INFO("%s: BLE_GAP_EVT_LESC_DHKEY_REQUEST\r\n", nrf_log_push(roles_str[role]));
                 peer_pk.p_le_data = &p_ble_evt->evt.gap_evt.params.lesc_dhkey_request.p_pk_peer->pk[0];
                 peer_pk.len = BLE_GAP_LESC_P256_PK_LEN;
    -            err_code = nrf_crypto_shared_secret_compute(NRF_CRYPTO_CURVE_SECP256R1, &m_crypto_key_sk, &peer_pk, &m_crypto_key_dhkey);
    -            APP_ERROR_CHECK(err_code);
    +
    +            // Validate remote peer public key
    +            err_code = ecc_p256_public_key_validate(peer_pk.p_le_data);
    +
    +            // Only calculate shared secret if public key is valid
    +            if (err_code == NRF_SUCCESS)
    +            {
    +                err_code = nrf_crypto_shared_secret_compute(
    +                    NRF_CRYPTO_CURVE_SECP256R1, &m_crypto_key_sk, &peer_pk, &m_crypto_key_dhkey);
    +            }
    +
    +            // Generate an invalid shared secret to make pairing fail in case of any error
    +            if (err_code != NRF_SUCCESS)
    +            {
    +                NRF_LOG_WARNING("Creating invalid shared secret to make LESC fail.");
    +                nrf_drv_rng_block_rand(m_crypto_key_dhkey.p_le_data, BLE_GAP_LESC_DHKEY_LEN);
    +            }
    +
                 err_code = sd_ble_gap_lesc_dhkey_reply(conn_handle, &m_lesc_dhkey);
                 APP_ERROR_CHECK(err_code);
                 break;
    @@ -1392,6 +1410,9 @@ int main(void)
         }
         ble_stack_init();
     
    +    err_code = nrf_drv_rng_init(NULL);
    +    APP_ERROR_CHECK(err_code);
    +
         peer_manager_init(erase_bonds);
     
         db_discovery_init();
    

    diff --git a/components/libraries/ecc/ecc.h b/components/libraries/ecc/ecc.h
    index 5b149d8..0b74866 100644
    --- a/components/libraries/ecc/ecc.h
    +++ b/components/libraries/ecc/ecc.h
    @@ -132,6 +132,17 @@ ret_code_t ecc_p256_sign(uint8_t const *p_le_sk, uint8_t const * p_le_hash, uint
      */
     ret_code_t ecc_p256_verify(uint8_t const *p_le_pk, uint8_t const * p_le_hash, uint32_t hlen, uint8_t const *p_le_sig);
     
    +/**@brief Validate a public key.
    + *
    + * @param[in]   p_le_pk   Public key. Pointer must be aligned to a 4-byte boundary.
    + *
    + * @retval     NRF_SUCCESS              Public key is valid.
    + * @retval     NRF_ERROR_INVALID_DATA   Public key is invalid.
    + * @retval     NRF_ERROR_NULL           NULL pointer provided.
    + * @retval     NRF_ERROR_INVALID_ADDR   Unaligned pointer provided.
    + */
    +ret_code_t ecc_p256_public_key_validate(uint8_t const *p_le_pk);
    +
     
     #ifdef __cplusplus
     }
    

    diff --git a/components/libraries/ecc/ecc.c b/components/libraries/ecc/ecc.c
    index c42cbf4..9c93302 100644
    --- a/components/libraries/ecc/ecc.c
    +++ b/components/libraries/ecc/ecc.c
    @@ -204,4 +204,30 @@ ret_code_t ecc_p256_verify(uint8_t const *p_le_pk, uint8_t const * p_le_hash, ui
     
     }
     
    +ret_code_t ecc_p256_public_key_validate(uint8_t const *p_le_pk)
    +{
    +    const struct uECC_Curve_t * p_curve;
    +
    +    if (!p_le_pk)
    +    {
    +        return NRF_ERROR_NULL;
    +    }
    +
    +    if (!is_word_aligned(p_le_pk))
    +    {
    +        return NRF_ERROR_INVALID_ADDR;
    +    }
    +
    +    p_curve = uECC_secp256r1();
    +
    +    //NRF_LOG_INFO("uECC_valid_public_key\r\n");
    +    int ret = uECC_valid_public_key((const uint8_t *) p_le_pk, p_curve);
    +    if (!ret)
    +    {
    +        return NRF_ERROR_INVALID_DATA;
    +    }
    +
    +    //NRF_LOG_INFO("uECC_valid_public_key complete: %d\r\n", ret);
    +    return NRF_SUCCESS;
    +}
     
    

    Complete source files: lesc_fix.zip

     

  • Very Thanks Einar.

    Your answer is very helpful to solve my problem.

Related