This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2745P10-Q1: Cryptographic operations of ECDH

Part Number: CC2745P10-Q1
Other Parts Discussed in Thread: SYSCONFIG, CC2745R10-Q1

Tool/software:

To use the ECDH_generatePublicKey() function, I wrote the following code based on the documentation.

However, this code returns ECDH_STATUS_RESOURCE_UNAVAILABLE (-2) as the return value of the function.

The same result is returned when I change the value to the value of the secret key, which should be able to generate other key pairs. Is there a problem with the usage?

"""

void ecdhGenPubCallback(ECDH_Handle handle, int_fast16_t returnStatus, ECDH_Operation operation, ECDH_OperationType operationType)
{
/* LED OFF */
ECDH_close(handle);
}

void *mainThread(void *arg0)
{

uint8_t myPrivateKeyingMaterial[CURVE_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
uint8_t myPublicKeyingMaterial[2 * CURVE_LENGTH + 1] = {0};

GPIO_init();

/* LED ON */
GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);

// Since we are using default ECDH_Params, we just pass in NULL for that parameter.
ECDH_Params_init(&Params);
Params.returnBehavior = ECDH_RETURN_BEHAVIOR_CALLBACK;
Params.callbackFxn = ecdhGenPubCallback;
ecdhHandle = ECDH_open(0, &Params);
if (!ecdhHandle) {
// Handle error
}

// Initialize myPrivateKey and myPublicKey
CryptoKeyPlaintext_initKey(&myPrivateKey, myPrivateKeyingMaterial, sizeof(myPrivateKeyingMaterial));
CryptoKeyPlaintext_initBlankKey(&myPublicKey, myPublicKeyingMaterial, sizeof(myPublicKeyingMaterial));
ECDH_OperationGeneratePublicKey_init(&operationGeneratePublicKey);

operationGeneratePublicKey.curve = &ECCParams_NISTP256;
operationGeneratePublicKey.myPrivateKey = &myPrivateKey;
operationGeneratePublicKey.myPublicKey = &myPublicKey;
// Generate the keying material for myPublicKey and store it in myPublicKeyingMaterial
operationResult = ECDH_generatePublicKey(ecdhHandle, &operationGeneratePublicKey);

while (1)
{
sleep(100);
}

}

  • Hello Kaichi, 

    To start, are you using any other cryptography computations? The error you are mentioning (See ECDH_STATUS_RESOURCE_UNAVAILABLE for more details), indicates that the hardware is not available at the moment you are attempting to compute ECDH. 

    Additionally, I do not see you using ECDH_OperationComputeSharedSecret() after the ECDH_generatePublicKey() function. Computing the shared secret is a post condition for the ECDH_generatePublicKey() function (to learn more please see ECDH_generatePublicKey and ECDH_OperationComputeSharedSecret).

    Let me know!

    Thanks, 
    Isaac

  • Hello Isaac,

    The code in this question is an excerpt of the relevant section. 
    The software actually running is a rewritten empty.c of empty provided as an exsample in simplelink_lowpower_f3_sdk_8_30_00_11_ea, with the following code, and the sysconfig changed.
    Therefore, I think no other cryptographic operations are in use.

    """

    #include <unistd.h>
    #include <stdint.h>
    #include <stddef.h>

    /* Driver Header files */
    #include <ti/drivers/GPIO.h>
    // #include <ti/drivers/I2C.h>
    // #include <ti/drivers/SPI.h>
    // #include <ti/drivers/Watchdog.h>

    #include <ti/drivers/ECDH.h>
    #include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h>

    /* Driver configuration */
    #include "ti_drivers_config.h"


    #define CURVE_LENGTH 32

    static uint8_t u1s_GenPubFlag = 0;
    static uint8_t u1s_ComputeShareSecFlag = 0;

    void ecdhGenPubCallback(ECDH_Handle handle, int_fast16_t returnStatus, ECDH_Operation operation, ECDH_OperationType operationType)
    {
        /* LED OFF */
        ECDH_close(handle);
        GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_OFF);

        u1s_GenPubFlag = 1;
    }

    void ecdhComputeShareSecCallback(ECDH_Handle handle, int_fast16_t returnStatus, ECDH_Operation operation, ECDH_OperationType operationType)
    {
        /* LED ON */
        GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
        u1s_ComputeShareSecFlag = 1;
    }


    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        uint8_t myPrivateKeyingMaterial[CURVE_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
        uint8_t myPublicKeyingMaterial[2 * CURVE_LENGTH + 1] = {0};
        uint8_t theirPublicKeyingMaterial[2 * CURVE_LENGTH + 1] = {0};
        uint8_t sharedSecretKeyingMaterial[2 * CURVE_LENGTH + 1] = {0};
        uint8_t symmetricKeyingMaterial[16] = {0};
        CryptoKey myPrivateKey;
        CryptoKey myPublicKey;
        CryptoKey theirPublicKey;
        CryptoKey sharedSecret;
        CryptoKey symmetricKey;
        ECDH_Handle ecdhHandle;
        ECDH_Params Params;
        int_fast16_t operationResult;
        ECDH_OperationGeneratePublicKey operationGeneratePublicKey;
        ECDH_OperationComputeSharedSecret operationComputeSharedSecret;
        uint8_t errFlag = 0;

        GPIO_init();

        /* LED ON */
        GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);

        // Since we are using default ECDH_Params, we just pass in NULL for that parameter.
        ECDH_Params_init(&Params);
        Params.returnBehavior       = ECDH_RETURN_BEHAVIOR_CALLBACK;
        Params.callbackFxn          = ecdhGenPubCallback;
        ecdhHandle = ECDH_open(0, &Params);
        if (!ecdhHandle) {
            // Handle error
        }

        // Initialize myPrivateKey and myPublicKey
        CryptoKeyPlaintext_initKey(&myPrivateKey, myPrivateKeyingMaterial, sizeof(myPrivateKeyingMaterial));
        CryptoKeyPlaintext_initBlankKey(&myPublicKey, myPublicKeyingMaterial, sizeof(myPublicKeyingMaterial));
        ECDH_OperationGeneratePublicKey_init(&operationGeneratePublicKey);

        operationGeneratePublicKey.curve                 = &ECCParams_NISTP256;
        operationGeneratePublicKey.myPrivateKey          = &myPrivateKey;
        operationGeneratePublicKey.myPublicKey           =  &myPublicKey;
        // Generate the keying material for myPublicKey and store it in myPublicKeyingMaterial
        operationResult = ECDH_generatePublicKey(ecdhHandle, &operationGeneratePublicKey);
        if(operationResult != 0) {
            errFlag = 1;
        }
        while (0 == u1s_GenPubFlag)
        {
            sleep(100);
        }

        ECDH_Params_init(&Params);
        Params.returnBehavior       = ECDH_RETURN_BEHAVIOR_CALLBACK;
        Params.callbackFxn          = ecdhComputeShareSecCallback;
        ecdhHandle = ECDH_open(0, NULL);
        if (!ecdhHandle) {
            errFlag = 1;
        }

        CryptoKeyPlaintext_initKey(&theirPublicKey, theirPublicKeyingMaterial, sizeof(theirPublicKeyingMaterial));
        CryptoKeyPlaintext_initBlankKey(&sharedSecret, sharedSecretKeyingMaterial, sizeof(sharedSecretKeyingMaterial));
        // The ECC_NISTP256 struct is provided in ti/drivers/types/EccParams.h and the corresponding device-specific implementation
        ECDH_OperationComputeSharedSecret_init(&operationComputeSharedSecret);
        operationComputeSharedSecret.curve                      = &ECCParams_NISTP256;
        operationComputeSharedSecret.myPrivateKey               = &myPrivateKey;
        operationComputeSharedSecret.theirPublicKey             = &theirPublicKey;
        operationComputeSharedSecret.sharedSecret               = &sharedSecret;
        // Compute the shared secret and copy it to sharedSecretKeyingMaterial
        operationResult = ECDH_computeSharedSecret(ecdhHandle, &operationComputeSharedSecret);
        if (operationResult != ECDH_STATUS_SUCCESS) {
            errFlag = 1;
        }    
       
        while (0 == u1s_ComputeShareSecFlag)
        {
            sleep(100);
        }
        CryptoKeyPlaintext_initBlankKey(&symmetricKey, symmetricKeyingMaterial, sizeof(symmetricKeyingMaterial));

        while (1)
        {
            sleep(100);
        }

    }
  • Hello Kaichi, 

    I apologize for the delay in response. I will respond by the end of this week (12/06). 

    Thanks, 

    Isaac

  • Hello Kaichi, 

    The ECDH driver is required to use the HSM module for CC2745R10-Q1. Please see the attached images: 

    More information can be found in the SDK release notes, and within the HSM documentation included in the doc's folder of the SDK. 

    Please replace the CryptoKeyPlaintext_initKey, with CryptoKeyPlaintextHSM_initKey, and let me know if that helps!

    Thanks, 

    Isaac

  • I changed CryptoKeyPlaintext_initKey to CryptoKeyPlaintextHSM_initKey, but the result did not change. 
    Furthermore, I changed CryptoKeyPlaintext_initBlankKey to CryptoKeyPlaintextHSM_initBlankKey as well. 

    Are you getting the correct results with this change in your environment? 
    If so, is it not the code but something wrong with the sysconfig settings, etc.?
    My sysconfig settings are as shown in the following image.

  • Hello Kaichi, 

    Apologies for the late response. 

    Please add the Predefined Symbols "DeviceFamily_CC27XX" and "USE_HSM". To do this, right click on the project -> properties -> Build -> Arm Compiler -> Predefined Symbols. 

    Additionally, add ECDH_init() before calling ECDH_open(). I am able to run your code successfully when making these changes. 

    Thanks, 

    Isaac

  • Hello Isaac,

    Thanks for the reply. I have added

    ECDH_init() and was able to confirm the Callback is returned.
    However, the value of returnStatus is ECDH_STATUS_ERROR (-1) and the operation is not successful.

    Adding "DeviceFamily_CC27XX" and "USE_HSM" to Predefined Symbols, is it correct as shown in the image below?
    I think I am wrong because I am getting a warning during the build, but how can I set it up correctly?

    Sorry for the repetitive questions, but please respond.

  • Hello Kaichi, 

    My apologies, I should've been more descriptive. When entering the predefines, ${} is not needed. Please see the image below: 

    Let me know if this works for you!

    Thanks, 

    Isaac

  • Hello Kaichi, 

    Also, another point of clarification. I added ECDH_init before ECDH_Params_init, and ECDH_open. See the image below: 

    Thanks, 

    Isaac

  • I was able to add "DeviceFamily_CC27XX" and "USE_HSM" to Predefined Symbols, but still the returnStatus value is ECDH_STATUS_ERROR (-1) and the operation is not successful.  

    I have also added ECDH_init(). 

     I am running the following code, but in your environment, the value of returnStatus in the callback function is ECDH_STATUS_SUCCESS(0) and I am getting correct results?


    ---


    #include
    <unistd.h>
    #include <stdint.h>
    #include <stddef.h>

    /* Driver Header files */
    #include <ti/drivers/GPIO.h>
    // #include <ti/drivers/I2C.h>
    // #include <ti/drivers/SPI.h>
    // #include <ti/drivers/Watchdog.h>

    #include <ti/drivers/ECDH.h>
    #include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h>

    /* Driver configuration */
    #include "ti_drivers_config.h"


    #define CURVE_LENGTH 32

    static uint8_t u1s_GenPubFlag = 0;
    static uint8_t u1s_ComputeShareSecFlag = 0;


    static uint8_t myPrivateKeyingMaterial[CURVE_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
    static uint8_t myPublicKeyingMaterial[2 * CURVE_LENGTH + 1] = {0};
    static uint8_t theirPublicKeyingMaterial[2 * CURVE_LENGTH + 1] = {0};
    static uint8_t sharedSecretKeyingMaterial[2 * CURVE_LENGTH + 1] = {0};
    static uint8_t symmetricKeyingMaterial[16] = {0};
    static CryptoKey myPrivateKey;
    static CryptoKey myPublicKey;
    static CryptoKey theirPublicKey;
    static CryptoKey sharedSecret;
    static CryptoKey symmetricKey;
    static ECDH_Handle ecdhHandle;
    static ECDH_Params Params;
    static int_fast16_t operationResult;
    static ECDH_OperationGeneratePublicKey operationGeneratePublicKey;
    static ECDH_OperationComputeSharedSecret operationComputeSharedSecret;
    static uint8_t errFlag = 0;

    void ecdhGenPubCallback(ECDH_Handle handle, int_fast16_t returnStatus, ECDH_Operation operation, ECDH_OperationType operationType)
    {
        /* LED OFF */
        GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_OFF);
        ECDH_close(handle);
        u1s_GenPubFlag = 1;
    }

    void ecdhComputeShareSecCallback(ECDH_Handle handle, int_fast16_t returnStatus, ECDH_Operation operation, ECDH_OperationType operationType)
    {
        /* LED OFF */
        GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_OFF);
        u1s_ComputeShareSecFlag = 1;
    }


    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        GPIO_init();
        ECDH_init();
        /* LED ON */
        GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);

        // Since we are using default ECDH_Params, we just pass in NULL for that parameter.
        ECDH_Params_init(&Params);
        Params.returnBehavior       = ECDH_RETURN_BEHAVIOR_CALLBACK;
        Params.callbackFxn          = ecdhGenPubCallback;

        ecdhHandle = ECDH_open(0, &Params);
        if (!ecdhHandle) {
            // Handle error
        }

        // Initialize myPrivateKey and myPublicKey
        CryptoKeyPlaintextHSM_initKey(&myPrivateKey, myPrivateKeyingMaterial, sizeof(myPrivateKeyingMaterial));
        CryptoKeyPlaintextHSM_initBlankKey(&myPublicKey, myPublicKeyingMaterial, sizeof(myPublicKeyingMaterial));
        ECDH_OperationGeneratePublicKey_init(&operationGeneratePublicKey);

        operationGeneratePublicKey.curve                 = &ECCParams_NISTP256;
        operationGeneratePublicKey.myPrivateKey          = &myPrivateKey;
        operationGeneratePublicKey.myPublicKey           =  &myPublicKey;
        // Generate the keying material for myPublicKey and store it in myPublicKeyingMaterial
        operationResult = ECDH_generatePublicKey(ecdhHandle, &operationGeneratePublicKey);
        if(operationResult != 0) {
            errFlag = 1;
        }
        while (0 == u1s_GenPubFlag)
        {
            sleep(1);
        }
        GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
        ECDH_Params_init(&Params);
        Params.returnBehavior       = ECDH_RETURN_BEHAVIOR_CALLBACK;
        Params.callbackFxn          = ecdhComputeShareSecCallback;
        ECDH_init();
        ecdhHandle = ECDH_open(0, &Params);
        if (!ecdhHandle) {
            errFlag = 1;
        }

        CryptoKeyPlaintextHSM_initKey(&theirPublicKey, theirPublicKeyingMaterial, sizeof(theirPublicKeyingMaterial));
        CryptoKeyPlaintextHSM_initBlankKey(&sharedSecret, sharedSecretKeyingMaterial, sizeof(sharedSecretKeyingMaterial));
        // The ECC_NISTP256 struct is provided in ti/drivers/types/EccParams.h and the corresponding device-specific implementation
        ECDH_OperationComputeSharedSecret_init(&operationComputeSharedSecret);
        operationComputeSharedSecret.curve                      = &ECCParams_NISTP256;
        operationComputeSharedSecret.myPrivateKey               = &myPrivateKey;
        operationComputeSharedSecret.theirPublicKey             = &theirPublicKey;
        operationComputeSharedSecret.sharedSecret               = &sharedSecret;
        // Compute the shared secret and copy it to sharedSecretKeyingMaterial
        operationResult = ECDH_computeSharedSecret(ecdhHandle, &operationComputeSharedSecret);
        if (operationResult != ECDH_STATUS_SUCCESS) {
            errFlag = 1;
        }    
        while (0 == u1s_ComputeShareSecFlag)
        {
            sleep(1);
        }
        CryptoKeyPlaintextHSM_initBlankKey(&symmetricKey, symmetricKeyingMaterial, sizeof(symmetricKeyingMaterial));

        while (1)
        {
            sleep(1);
        }

    }
  • Hello Kaichi, 

    Yes, I am running your code in my environment and not receiving any error flags. The errFlag, and operationResult flag remain zero throughout duration of the code. I changed the errFlag and operationResults flag to globals so I could follow throughout the code. 

    You are seeing error -1 now, correct? If you set breakpoints on the ECDH_generatePubKey and ECDH_computeSharedSecret, what happens? Can you please set some breakpoints, and watch the operationResult and errFlag variables and communicate to me what you see? 

    Thanks, 
    Isaac

  • Hello Isaac,

    As for the value of operationResult at the completion of ECDH_generatePublicKey(), there is no problem in my environment.

     

    When the Callback function ecdhGenPubCallback() is called, the value of the argument returnStatus is -1.

     

    The operationResult at the completion of ECDH_computeSharedSecret() has a value of -41.

     

    The callback function of ecdhComputeShareSecCallback() is not called

     

    Please let me know if there is any other information I am missing.

  • Hello Kaichi, 

    I will provide a response tomorrow (12/17). Apologies for the delay. 

    Thanks, 

    Isaac

  • Hello Kaichi, 

    I am seeing the same error code on my end. This is quite peculiar as I do cannot find any reference to the error code -41. On a side note, I did not see ECDHGenPubCallBack() return a -1 status. 

    I am currently still debugging the problem. I appreciate your patience with me! 

    I will provide a response by the end of the day Friday (12/20). 

    Thanks, 

    Isaac

  • Hello Kaichi, 

    I am still debugging the matter. I still do not have any problem with the public key. I still receive -41 for the shared secret. The issue with the shared secret at the moment has something to do with the octet of the public key. I am thinking that 

    1. Something is wrong with the public key. I am not seeing any issue, but you are. I am thinking maybe there is a problem, but I am not observing the issue. 

    2. The private keying material is incorrect. 

    3. A larger problem with the ECDH driver. 

    Apologies for the delay. 

    Thanks, 

    Isaac

  • Hello Isaac,

    Thank you for your reply. 
    Please let me know if there is any additional information needed to resolve the issue. 
    Sorry, we appreciate your cooperation in resolving the issue.

  • Hello Kaichi, 

    Due to the holidays, responses have been delayed. 

    The error is occurring due to the public key (theirPublicKey). Within your code, no Public Key is being received from the recipient. Additionally, the first byte of theirPublicKey will need to be set to 0x04. Since this has not been done, the error -41 occurs. The status occurs when an invalid public key is seen. Meaning that the public key does not begin with 0x04. If you add 0x04 to byte 0 in theirPublicKey, you will receive a -40 error. The status occurs when the public key is an invalid size. 

    Do you have a device that you can receive a public key from? If so, please populate theirPublicKey pointer, and set the first byte (byte 0) to 0x04. 

    Again, I apologize for the delay and appreciate your patience. 

    Thanks, 
    Isaac

  • Hello Kaichi, 

    Just to add, ECDH is used in the pairing process between two devices. ECDH is used to safely share the public key between the two devices. To truly test if the ECDH driver is working correctly, it will need to be configured in this use case. As mentioned, prior, the ECDH driver must receive a public key from the recipient device in order to produce the shared secret. 

    For more information on the pairing process, please refer to the LE Legacy vs. LE Secure Connections Pairing section of the Security Fundamentals SimpleLink Academy. 

    Thanks, 
    Isaac

  • Hello Isaac,

    I solved the problem by entering a point on the elliptic curve in theirPublicKeyMaterial.
    Thank you so much for your continued support over the long term. I truly appreciate it.