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.

LP-EM-CC2745R10-Q1: ECDH_open() return NULL

Part Number: LP-EM-CC2745R10-Q1
Other Parts Discussed in Thread: SYSCONFIG

Tool/software:

Hi,

Here are my software and hardware versions:

LP-EM-CC2745R10-Q1

simplelink_lowpower_f3_sdk_8_40_00_61

CCS Version: 20.0.2.5__1.6.2

I tested the HSM functionality in the f3 sdk based on the examples\rtos\LP_EM_CC2745R10_Q1\ble5stack\basic_ble routine, and I have tested that AES-CBC/AES-GCM can work properly. But when I add the ECDH test, I keep getting ECDH_open() return NULL. I have tried to find out relevant problems on the forum, and made modifications such as add the Predefined Symbols "DeviceFamily_CC27XX" and "USE_HSM", but they still haven't been solved. Can you help me see what's causing it?

Here is my function, I deleted the function inside the thread and just ran my own test function

static const char ecdh_msg[]  = "\n\n\rECDH Open fail";

static void ECDH_Test(void)
{
    ECDH_Handle ecdhHandle;
    ECDH_Params ecdhParams;
    CryptoKey myPrivateKey;
    CryptoKey myPublicKey;
    CryptoKey theirPublicKey;
    CryptoKey theirPrivateKey;
    CryptoKey mysharedSecret;
    CryptoKey theirsharedSecret;
    CryptoKey symmetricKey;

    int_fast16_t operationResult;
    ECDH_OperationGeneratePublicKey operationGeneratePublicKey;
    ECDH_OperationComputeSharedSecret operationComputeSharedSecret;

    ECDH_init();

    ECDH_Params_init(&ecdhParams);
    ecdhParams.returnBehavior = ECDH_RETURN_BEHAVIOR_BLOCKING;

    ecdhHandle = ECDH_open(CONFIG_ECDH0, &ecdhParams);

    if (!ecdhHandle) 
    {
        printMessage(uart, (char *)ecdh_msg, NULL, 0);
        while(1);
    }

    // CryptoKeyPlaintextHSM_initKey(&myPrivateKey, myPrivateKeyingMaterial, sizeof(myPrivateKeyingMaterial));
    // CryptoKeyPlaintextHSM_initBlankKey(&myPublicKey, myPublicKeyingMaterial, sizeof(myPublicKeyingMaterial));

    // ECDH_OperationGeneratePublicKey_init(&operationGeneratePublicKey);
    // operationGeneratePublicKey.curve                 = &ECCParams_Curve25519;
    // operationGeneratePublicKey.myPrivateKey          = &myPrivateKey;
    // operationGeneratePublicKey.myPublicKey           = &myPublicKey;
    // // If generating public key in little-endian format, we use the following format:
    // operationGeneratePublicKey.keyMaterialEndianness = ECDH_LITTLE_ENDIAN_KEY;

    // //generate my pub-key
    // operationResult = ECDH_generatePublicKey(ecdhHandle, &operationGeneratePublicKey);

    // if (operationResult != ECDH_STATUS_SUCCESS) 
    // {
    //     printMessage(uart, (char *)ecdh_msg2, NULL, 0);
    // // Handle error
    // }


    //  printMessage(uart, (char *)promptClearText, (char *)myPublicKeyingMaterial, sizeof(myPublicKeyingMaterial));
    //  printBanner(uart, (char *)"*");

}

void App_StackInitDoneHandler(gapDeviceInitDoneEvent_t *deviceInitDoneData)
{
    bStatus_t status = SUCCESS;

    GPIO_init();
    GPIO_setConfig(CONFIG_GPIO_LED_GREEN, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    GPIO_setConfig(CONFIG_GPIO_LED_RED, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);

    GPIO_write( CONFIG_GPIO_LED_GREEN, CONFIG_LED_ON );
    GPIO_write( CONFIG_GPIO_LED_RED, CONFIG_LED_ON );

    UART2_Params_init(&uartParams);
    uartParams.baudRate = 115200;

    uart = UART2_open(CONFIG_UART2_0, &uartParams);

    if (uart == NULL)
    {
        /* UART2_open() failed */
        while (1) {}
    }

    char array[] = "example start !! \r\n";
    printClearText(uart,array,NULL,0);

    // AES_CBC_Test();
    // AES_GCM_Test();
    ECDH_Test();
    
}

  • Hello Ethan, 

    A few things to start: 

    1. Do you have any other cryptographic functions open when opening the ECDH driver? If you do, and the cryptography function uses the HSM, you will see an error when opening ECDH as the HSM hardware is in use by the other function. 

    2. Where are you calling the ECDH_Test function within the Basic_BLE function? 

    3. What exactly do you mean when you say, "I deleted the function inside the thread"? Did you delete the ECDH instance already added to the Basic_BLE example project. 

    I tested your implementation within an empty project and saw no issues. Please provide answers to the questions above, and I will test your implementation within Basic_BLE. 

    I believe the problem you are seeing is caused by another cryptographic driver using the HSM when you are attempting to open the ECDH driver. I can debug further with the answers you provide. 

    Thanks, 
    Isaac

  • Hi Isaac,

    1. I didn't have multiple HSM encryption modules open at the same time.
    2.  ECDH_Test function runs in appMain() -> App_StackInitDoneHandler() -> ECDH_Test() 

    3. I mean I removed the Bluetooth-related functions from App_StackInitDoneHandler()

    Here is my complete app_main.c file:

    /******************************************************************************
    
    @file  app_main.c
    
    @brief This file contains the application main functionality
    
    Group: WCS, BTS
    Target Device: cc23xx
    
    ******************************************************************************
    
     Copyright (c) 2022-2024, Texas Instruments Incorporated
     All rights reserved.
    
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:
    
     *  Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
    
     *  Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
    
     *  Neither the name of Texas Instruments Incorporated nor the names of
        its contributors may be used to endorse or promote products derived
        from this software without specific prior written permission.
    
     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
    ******************************************************************************
    
    
    *****************************************************************************/
    
    //*****************************************************************************
    //! Includes
    //*****************************************************************************
    #include "ti_ble_config.h"
    #include <ti/bleapp/ble_app_util/inc/bleapputil_api.h>
    #include <ti/bleapp/menu_module/menu_module.h>
    #include <app_main.h>
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/UART2.h>
    #include <ti/drivers/ECDH.h>
    
    //*****************************************************************************
    //! Defines
    //*****************************************************************************
    
    //*****************************************************************************
    //! Globals
    //*****************************************************************************
    
    // Parameters that should be given as input to the BLEAppUtil_init function
    BLEAppUtil_GeneralParams_t appMainParams =
    {
        .taskPriority = 1,
        .taskStackSize = 1024,
        .profileRole = (BLEAppUtil_Profile_Roles_e)(HOST_CONFIG),
        .addressMode = DEFAULT_ADDRESS_MODE,
        .deviceNameAtt = attDeviceName,
        .pDeviceRandomAddress = pRandomAddress,
    };
    
    #if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( PERIPHERAL_CFG | CENTRAL_CFG ) )
    BLEAppUtil_PeriCentParams_t appMainPeriCentParams =
    {
    #if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( PERIPHERAL_CFG ) )
     .connParamUpdateDecision = DEFAULT_PARAM_UPDATE_REQ_DECISION,
    #endif //#if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( PERIPHERAL_CFG ) )
     .gapBondParams = &gapBondParams
    };
    #else //observer || broadcaster
    BLEAppUtil_PeriCentParams_t appMainPeriCentParams;
    #endif //#if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( PERIPHERAL_CFG | CENTRAL_CFG ) )
    
    UART2_Handle uart;
    UART2_Params uartParams;
    static const char ecdh_msg[]  = "\n\n\rECDH Open fail";
    
    //*****************************************************************************
    //! Functions
    //*****************************************************************************
    
    /*********************************************************************
     * @fn      criticalErrorHandler
     *
     * @brief   Application task entry point
     *
     * @return  none
     */
    void criticalErrorHandler(int32 errorCode , void* pInfo)
    {
    //    trace();
    //
    //#ifdef DEBUG_ERR_HANDLE
    //
    //    while (1);
    //#else
    //    SystemReset();
    //#endif
    
    }
    
    /*
     *  Print string message to console.
     *  Input params are expected to be characters.
     */
    void printClearText(UART2_Handle uartHandle, const char *msgTitle, const char *msgOut, uint8_t msgLen)
    {
        /* Print prompt */
        UART2_write(uartHandle, msgTitle, strlen(msgTitle), NULL);
    
        /* Print result */
        UART2_write(uartHandle, msgOut, msgLen, NULL);
    }
    
    static void ECDH_Test(void)
    {
        ECDH_Handle ecdhHandle;
        ECDH_Params ecdhParams;
    
        int_fast16_t operationResult;
        ECDH_OperationGeneratePublicKey operationGeneratePublicKey;
        ECDH_OperationComputeSharedSecret operationComputeSharedSecret;
    
        char array[] = "\r\nECDH Test\r\n";
        printClearText(uart,array,NULL,0);
    
        ECDH_init();
    
        ECDH_Params_init(&ecdhParams);
        ecdhParams.returnBehavior = ECDH_RETURN_BEHAVIOR_BLOCKING;
    
        ecdhHandle = ECDH_open(CONFIG_ECDH0, &ecdhParams);
    
        if (!ecdhHandle) 
        {
            printClearText(uart, (char *)ecdh_msg, NULL, 0);
            while(1);
        }
    }
    
    /*********************************************************************
     * @fn      App_StackInitDone
     *
     * @brief   This function will be called when the BLE stack init is
     *          done.
     *          It should call the applications modules start functions.
     *
     * @return  none
     */
    void App_StackInitDoneHandler(gapDeviceInitDoneEvent_t *deviceInitDoneData)
    {
        bStatus_t status = SUCCESS;
    
        GPIO_init();
        GPIO_setConfig(CONFIG_GPIO_LED_GREEN, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_setConfig(CONFIG_GPIO_LED_RED, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
        GPIO_write( CONFIG_GPIO_LED_GREEN, CONFIG_LED_ON );
        GPIO_write( CONFIG_GPIO_LED_RED, CONFIG_LED_ON );
    
    
       UART2_Params_init(&uartParams);
        uartParams.baudRate = 115200;
    
        uart = UART2_open(CONFIG_UART2_0, &uartParams);
    
        if (uart == NULL)
        {
            /* UART2_open() failed */
            while (1) {}
        }
    
        char array[] = "example start !! \r\n";
        printClearText(uart,array,NULL,0);
    
        ECDH_Test();
     
        // Menu
    //     Menu_start();
    
    
    //     // Print the device ID address
    //     MenuModule_printf(APP_MENU_DEVICE_ADDRESS, 0, "BLE ID Address: "
    //                       MENU_MODULE_COLOR_BOLD MENU_MODULE_COLOR_GREEN "%s" MENU_MODULE_COLOR_RESET,
    //                       BLEAppUtil_convertBdAddr2Str(deviceInitDoneData->devAddr));
    
    //     if ( appMainParams.addressMode > ADDRMODE_RANDOM)
    //     {
    //       // Print the RP address
    //         MenuModule_printf(APP_MENU_DEVICE_RP_ADDRESS, 0,
    //                      "BLE RP Address: "
    //                      MENU_MODULE_COLOR_BOLD MENU_MODULE_COLOR_GREEN "%s" MENU_MODULE_COLOR_RESET,
    //                      BLEAppUtil_convertBdAddr2Str(GAP_GetDevAddress(FALSE)));
    //     }
    
    // #if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( PERIPHERAL_CFG | CENTRAL_CFG ) )
    //     status = DevInfo_start();
    //     if(status != SUCCESS)
    //     {
    //         // TODO: Call Error Handler
    //     }
    //     status = SimpleGatt_start();
    //     if(status != SUCCESS)
    //     {
    //         // TODO: Call Error Handler
    //     }
    // #endif
    
    // #if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( PERIPHERAL_CFG | CENTRAL_CFG ))  &&  defined(OAD_CFG)
    //     status =  OAD_start();
    //     if(status != SUCCESS)
    //     {
    //         // TODO: Call Error Handler
    //     }
    // #endif
    
    // #if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( PERIPHERAL_CFG ) )
    //     // Any device that accepts the establishment of a link using
    //     // any of the connection establishment procedures referred to
    //     // as being in the Peripheral role.
    //     // A device operating in the Peripheral role will be in the
    //     // Peripheral role in the Link Layer Connection state.
    //     status = Peripheral_start();
    //     if(status != SUCCESS)
    //     {
    //         // TODO: Call Error Handler
    //     }
    // #endif
    
    // #if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( BROADCASTER_CFG ) )
    //     // A device operating in the Broadcaster role is a device that
    //     // sends advertising events or periodic advertising events
    //     status = Broadcaster_start();
    //     if(status != SUCCESS)
    //     {
    //         // TODO: Call Error Handler
    //     }
    // #endif
    
    // #if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( CENTRAL_CFG ) )
    //     // A device that supports the Central role initiates the establishment
    //     // of an active physical link. A device operating in the Central role will
    //     // be in the Central role in the Link Layer Connection state.
    //     // A device operating in the Central role is referred to as a Central.
    //     status = Central_start();
    //     if(status != SUCCESS)
    //     {
    //         // TODO: Call Error Handler
    //     }
    // #endif
    
    // #if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( OBSERVER_CFG ) )
    //     // A device operating in the Observer role is a device that
    //     // receives advertising events or periodic advertising events
    //     status = Observer_start();
    //     if(status != SUCCESS)
    //     {
    //         // TODO: Call Error Handler
    //     }
    // #endif
    
    // #if defined( HOST_CONFIG ) && ( HOST_CONFIG & ( PERIPHERAL_CFG | CENTRAL_CFG ) )
    //     status = Connection_start();
    //     if(status != SUCCESS)
    //     {
    //         // TODO: Call Error Handler
    //     }
    //     status = Pairing_start();
    //     if(status != SUCCESS)
    //     {
    //         // TODO: Call Error Handler
    //     }
    //     status = Data_start();
    //     if(status != SUCCESS)
    //     {
    //         // TODO: Call Error Handler
    //     }
    
    // #if defined (BLE_V41_FEATURES) && (BLE_V41_FEATURES & L2CAP_COC_CFG)
    //     /* L2CAP COC Init */
    //     status = L2CAPCOC_start();
    //     if ( status != SUCCESS )
    //     {
    //     // TODO: Call Error Handler
    //     }
    // #endif //(BLE_V41_FEATURES) && (BLE_V41_FEATURES & L2CAP_COC_CFG)
    
    // #endif
    }
    
    /*********************************************************************
     * @fn      appMain
     *
     * @brief   Application main function
     *
     * @return  none
     */
    void appMain(void)
    {
        // Call the BLEAppUtil module init function
        BLEAppUtil_init(&criticalErrorHandler, &App_StackInitDoneHandler,
                        &appMainParams, &appMainPeriCentParams);
    }
    

    You may need to modify the.syscfg file by closing "Dispaly" to open "UART2" and selecting Use Hardware: XDS110 UART.

    Thanks,

    Ethan

  • Hello Ethan, 

    I was able to debug your implementation further and was able to fix the problem. 

    The ECDH instance you are using is the instance used for encrypting connection events during a BLE connection. Even if the device is not in a connection, this ECDH instance will be initialized for connection events, and will cause an error if attempting to use the instance for other purposes. 

    To fix this, create another ECDH instance in SysConfig, and use this. Additionally, the code in appMain has no effect on the ECDH driver. I kept the code you commented out and added the ECDH_Test function to run after advertising was enabled in the Basic_BLE project. 

    Please let me know if you have any issues with this. 

    Thanks, 

    Isaac

  • Hi Isaac,

    Thanks for your help,when I added another ECDH to the.syscfg file, ECDH_open worked fine.But as I went on, I found a new problem: When I used ECDH_generatePublicKey () function to generate the public key, it generated an error, returning -38 without any explanation about it.

    static void ECDH_Test(void)
    {
        ECDH_Handle ecdhHandle;
        ECDH_Params ecdhParams;
        CryptoKey myPrivateKey;
        CryptoKey myPublicKey;
        CryptoKey theirPublicKey;
        CryptoKey theirPrivateKey;
        CryptoKey mysharedSecret;
        CryptoKey theirsharedSecret;
        CryptoKey symmetricKey;
    
        int_fast16_t operationResult;
        ECDH_OperationGeneratePublicKey operationGeneratePublicKey;
        ECDH_OperationComputeSharedSecret operationComputeSharedSecret;
    
        char array[] = "\r\nECDH Test\r\n";
        printClearText(uart,array,NULL,0);
    
        ECDH_init();
    
        ECDH_Params_init(&ecdhParams);
        ecdhParams.returnBehavior = ECDH_RETURN_BEHAVIOR_BLOCKING;
    
        ecdhHandle = ECDH_open(CONFIG_ECDH1, &ecdhParams);
    
        if (!ecdhHandle) 
        {
            printMessage(uart, (char *)ecdh_msg, NULL, 0);
            while(1);
        }
    
        CryptoKeyPlaintextHSM_initKey(&myPrivateKey, myPrivateKeyingMaterial, sizeof(myPrivateKeyingMaterial));
        CryptoKeyPlaintextHSM_initBlankKey(&myPublicKey, myPublicKeyingMaterial, sizeof(myPublicKeyingMaterial));
    
        ECDH_OperationGeneratePublicKey_init(&operationGeneratePublicKey);
        operationGeneratePublicKey.curveType             = ECDH_TYPE_SEC_P_256_R1;
        operationGeneratePublicKey.myPrivateKey          = &myPrivateKey;
        operationGeneratePublicKey.myPublicKey           = &myPublicKey;
        // If generating public key in little-endian format, we use the following format:
        operationGeneratePublicKey.keyMaterialEndianness = ECDH_LITTLE_ENDIAN_KEY;
    
        //generate my pub-key
        operationResult = ECDH_generatePublicKey(ecdhHandle, &operationGeneratePublicKey);
    
        if (operationResult != ECDH_STATUS_SUCCESS) 
        {
            tprintf("generate pub-key fail: %d \r\n",operationResult);
            while(1){};
        }
    
    
         printMessage(uart, (char *)promptClearText, (char *)myPublicKeyingMaterial, sizeof(myPublicKeyingMaterial));
         printBanner(uart, (char *)"*");
    
        CryptoKeyPlaintextHSM_initKey(&theirPrivateKey, theirPrivateKeyMaterial, sizeof(theirPrivateKeyMaterial));
        CryptoKeyPlaintextHSM_initBlankKey(&theirPublicKey, theirPublicKeyingMaterial, sizeof(theirPublicKeyingMaterial));
    
        ECDH_OperationGeneratePublicKey_init(&operationGeneratePublicKey);
        operationGeneratePublicKey.curveType             = ECDH_TYPE_SEC_P_256_R1;
        operationGeneratePublicKey.myPrivateKey          = &theirPrivateKey;
        operationGeneratePublicKey.myPublicKey           = &theirPublicKey;
        // If generating public key in little-endian format, we use the following format:
        operationGeneratePublicKey.keyMaterialEndianness = ECDH_LITTLE_ENDIAN_KEY;
    
        //generate their pub-key
        operationResult = ECDH_generatePublicKey(ecdhHandle, &operationGeneratePublicKey);
    
        if (operationResult != ECDH_STATUS_SUCCESS) 
        {
            tprintf("generate pub-key fail: %d \r\n",operationResult);
        // Handle error
        }
    
        printMessage(uart, (char *)promptClearText, (char *)theirPublicKeyingMaterial, sizeof(theirPublicKeyingMaterial));
        printBanner(uart, (char *)"*");
    }

    Could you take a look at this problem.

    Thanks,

    Ethan

  • Hello Ethan, 

    The error correlates with the invalid public key size error, see this link

    I am currently looking into the problem you are seeing, and will provide a response by end of day Monday (03/24). 

    Apologies for the delay. 

    Thanks, 
    Isaac

  • Hi Isaac,

    Here are the data structures for my public and private keys:

    #define CURVE_LENGTH         32
    
    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, 0xAA};
    uint8_t theirPrivateKeyMaterial[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, 0x55};
    
    /***************私钥注意加密****************************/
     uint8_t myPublicKeyingMaterial[2 * CURVE_LENGTH + 1] = {0};
     uint8_t theirPublicKeyingMaterial[2 * CURVE_LENGTH + 1] = {0};
     uint8_t sharedSecretKeyingMaterial1[2 * CURVE_LENGTH + 1] = {0};
     uint8_t sharedSecretKeyingMaterial2[2 * CURVE_LENGTH + 1] = {0};

    Although the error log indicates that it is caused by the wrong public key length,  things actually work fine when I block keyMaterialEndianness from using  ECDH_LITTLE_ENDIAN_KEY mode.

    Thanks,

    Ethan

  • Hello Ethan, 

    Glad you figured it out! The default is ECDH_BIG_ENDIAN_KEY mode, ECHD_LITTLE_ENDIAN_KEY mode if used for RFC 7748 style public keys. 

    My apologies for not catching that immediately! 

    Please let me know if you have any more questions. 

    Thanks, 

    Isaac