AM263P4: AM263P4 The CMAC streaming mode fails to run successfully on the HSM (M4 core) side, and this issue persists.

Part Number: AM263P4


To implement the CMAC streaming mode functionality, it is necessary to add this feature to the HSM firmware. However, TI does not officially provide this function or a demo running on the HSM side. Therefore, the crypto_aes_stream example from the SDK was adopted (mcu_plus_sdk_am263px_11_00_00_19\examples\security\crypto\dthe_aes\crypto_aes_stream).

This function has been successfully ported to the R5 core and runs correctly. However, when I ported the corresponding program to the M4 core, it failed to operate normally. I have already passed the relevant information such as the original text and CMAC key to the M4 core via SIPC in the form of a service request. Meanwhile, in single‑step mode, the M4 core can run properly (referring to the example: tifs_am263px_11_00_00_01\examples\dthe\aes\crypto_aes_cmac_128).

image.png

My question is: What modifications are required to successfully port the CMAC streaming mode program—which works on the R5 core—to the M4 core? Especially regarding the following programs, which are the ones I modified to run on the M4 core but are currently experiencing abnormal operation.

static int32_t app_aes_cmac_dthe_stream_start(uint8_t *Key, uint32_t Key_Len, uint8_t *K1, uint8_t *K2)

{

    DTHE_AES_Return_t   status = DTHE_AES_RETURN_FAILURE;

    DTHE_AES_Params     aesParams;

 

    /* Initialize the AES Parameters: */

    (void)memset ((void *)&aesParams, 0, sizeof(DTHE_AES_Params));

 

    /* Initialize the encryption parameters: */

    aesParams.algoType          = DTHE_AES_CMAC_MODE;

    aesParams.opType            = DTHE_AES_ENCRYPT;

    aesParams.useKEKMode        = FALSE;

    aesParams.ptrKey            = (uint32_t*)&Key[0];

    aesParams.ptrKey1           = (uint32_t*)&K1[0];

    aesParams.ptrKey2           = (uint32_t*)&K2[0];

    aesParams.keyLen            = Key_Len;

    aesParams.ptrPlainTextData  = (uint32_t*)NULL;

    aesParams.dataLenBytes      = 0U;

    aesParams.ptrTag            = (uint32_t*)NULL;

    aesParams.streamState       = DTHE_AES_STREAM_INIT;

    aesParams.streamSize        = 0U;

 

    /* Start Call */

    status = DTHE_AES_execute(gShaHandle, &aesParams);

    // DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);

 

    return (status);

}

 

static int32_t app_aes_cmac_dthe_stream_update(uint8_t **input, uint32_t ilen)

{

    DTHE_AES_Return_t   status = DTHE_AES_RETURN_SUCCESS;

    DTHE_AES_Params     aesParams;

    uint32_t n = 0;

    if((gCmac_unprocessed_len > 0) &&(ilen > (APP_CRYPTO_AES_BLOCK_LENGTH - gCmac_unprocessed_len )))

    {

        /* fill the unprocessed buffer */

        memcpy(&gCmac_unprocessed_block[gCmac_unprocessed_len], *input, APP_CRYPTO_AES_BLOCK_LENGTH - gCmac_unprocessed_len );

 

        /* Initialize the AES Parameters: */

        (void)memset ((void *)&aesParams, 0, sizeof(DTHE_AES_Params));

 

        /* Initialize the encryption parameters: */

        aesParams.algoType          = DTHE_AES_CMAC_MODE;

        aesParams.opType            = DTHE_AES_ENCRYPT;

        aesParams.ptrKey            = (uint32_t*)NULL;

        aesParams.ptrKey1           = (uint32_t*)NULL;

        aesParams.ptrKey2           = (uint32_t*)NULL;

     

        aesParams.ptrPlainTextData  = (uint32_t*)&gCmac_unprocessed_block[0U];

        aesParams.ptrTag            = (uint32_t*)NULL;

        aesParams.streamState       = DTHE_AES_STREAM_UPDATE;

        aesParams.streamSize        = APP_CRYPTO_AES_BLOCK_LENGTH;

 

        /* Update Call */

        status = DTHE_AES_execute(gShaHandle, &aesParams);

        // DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);

 

        if(status != DTHE_AES_RETURN_SUCCESS)

        {

            return status;

        }

 

        *input += APP_CRYPTO_AES_BLOCK_LENGTH - gCmac_unprocessed_len;

        ilen -= APP_CRYPTO_AES_BLOCK_LENGTH - gCmac_unprocessed_len;

        gCmac_unprocessed_len = 0;

    }

 

    /* n is the number of blocks including any final partial block */

    n = ( ilen + APP_CRYPTO_AES_BLOCK_LENGTH - 1 ) / APP_CRYPTO_AES_BLOCK_LENGTH;

 

    if(n>1)

    {

        /* Initialize the AES Parameters: */

        (void)memset ((void *)&aesParams, 0, sizeof(DTHE_AES_Params));

 

        /* Initialize the encryption parameters: */

        aesParams.algoType          = DTHE_AES_CMAC_MODE;

        aesParams.opType            = DTHE_AES_ENCRYPT;

        aesParams.ptrKey            = (uint32_t*)NULL;

        aesParams.ptrKey1           = (uint32_t*)NULL;

        aesParams.ptrKey2           = (uint32_t*)NULL;

        aesParams.ptrPlainTextData  = (uint32_t*)(*input);

        aesParams.ptrTag            = (uint32_t*)NULL;

        aesParams.streamState       = DTHE_AES_STREAM_UPDATE;

        aesParams.streamSize        = (n-1)*APP_CRYPTO_AES_BLOCK_LENGTH;

 

        /* Update Call */

        status = DTHE_AES_execute(gShaHandle, &aesParams);

        // DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);

 

        *input += (n-1)*APP_CRYPTO_AES_BLOCK_LENGTH;

        ilen -= (n-1)*APP_CRYPTO_AES_BLOCK_LENGTH;

    }

 

    /* If there is data left over that wasn't aligned to a block */

    if( ilen > 0 )

    {

        memcpy( &gCmac_unprocessed_block[gCmac_unprocessed_len], *input, ilen);

        gCmac_unprocessed_len += ilen;

    }

 

    return (status);

}

 

static int32_t app_aes_cmac_dthe_stream_finish(uint8_t *tag)

{

    DTHE_AES_Return_t   status = DTHE_AES_RETURN_FAILURE;

    DTHE_AES_Params     aesParams;

 

    /* Initialize the AES Parameters: */

    (void)memset ((void *)&aesParams, 0, sizeof(DTHE_AES_Params));

 

    /* Initialize the encryption parameters: */

    aesParams.algoType          = DTHE_AES_CMAC_MODE;

    aesParams.opType            = DTHE_AES_ENCRYPT;

    aesParams.ptrKey            = (uint32_t*)NULL;

    aesParams.ptrKey1           = (uint32_t*)NULL;

    aesParams.ptrKey2           = (uint32_t*)NULL;

    aesParams.ptrPlainTextData  = (uint32_t*)&gCmac_unprocessed_block[0U];

    aesParams.dataLenBytes      = 0U;

    aesParams.ptrTag            = (uint32_t*)SOC_virtToPhy((void *)tag);

    aesParams.streamState       = DTHE_AES_STREAM_FINISH;

    aesParams.streamSize        = gCmac_unprocessed_len;

 

    /* Start Call */

    status = DTHE_AES_execute(gShaHandle, &aesParams);

    // DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);

 

    memset(gCmac_unprocessed_block, 0U, APP_CRYPTO_AES_BLOCK_LENGTH);

    gCmac_unprocessed_len = 0;

 

    return (status);

}


Thank you for your responses, experts

  • Hi,

    Great that the application you have is working on R5 Core. 

    Would like to know your current status

    1. Is the device HS_FS or HS-SE?

    2. If HS-SE, have you created a service on the HSM TIFS side for CMAC (or reusing any service)

    3. If yes, are you send the original text and CMAC key using this service? or just using the SIPC as standalone?

    4. If using service, could you unlock JTAG on M4 (if HS-SE device)  and check where is M4 core hanging or crashed?

    Thanks and Regards,

    Nikhil Dasan

  • Thank you for your reply

    1、HS_SE

    2-4:I can now open JTAG on M4 The M4 program is running normally

    My basic process is to initiate a request on the R5 core side, as follows:

    Status_t AES_CMAC_Algo_HSM(hsmKeyHandle_t KeyHandle, uint32_t Key_Base_Addr, uint32_t Key_Len, uint8_t *Input, uint32_t Input_Len, uint8_t *CMAC, uint8_t StreamState)

    {

        HsmClient_t client;

        HsmCMAC_t HsmCMAC;

        int32_t status = SystemP_FAILURE;

        Status_t Status = STATUS_ERROR;

     

        HsmCMAC.KeyHandle = KeyHandle;

        HsmCMAC.Key_Base_Addr = Key_Base_Addr;

        HsmCMAC.Key_Len = Key_Len;

        HsmCMAC.Input = Input;

        HsmCMAC.Input_Len = Input_Len;

        HsmCMAC.CMAC = CMAC;

        HsmCMAC.StreamState = StreamState;

        HsmCMAC.Response = HSM_SRV_RSP_OPT_FAILURE;

     

        status = HsmClient_register(&client, APP_CLIENT_ID);

        status = HsmClient_AES_CMAC_Algo(&client, &HsmCMAC, SystemP_WAIT_FOREVER);

        if((status == SystemP_SUCCESS)&&(HsmCMAC.Response == HSM_SRV_RSP_OK))

        {

            Status = STATUS_SUCCESS;

        }

        else

        {

            return STATUS_ERROR;

        }

        HsmClient_unregister(&client, APP_CLIENT_ID);

        return Status;

    }

     

    int32_t HsmClient_AES_CMAC_Algo(HsmClient_t *HsmClient, HsmCMAC_t * HsmCMAC, uint32_t timeout)

    {

        int32_t status = SystemP_FAILURE;

        uint16_t crcArgs;

        timeout = SystemP_WAIT_FOREVER;

        HsmClient->ReqMsg.destClientId = HSM_CLIENT_ID_1;

        HsmClient->ReqMsg.srcClientId = HsmClient->ClientId;

        HsmClient->ReqMsg.flags = HSM_FLAG_AOP;

        HsmClient->ReqMsg.serType = HSM_MSG_AES_CMAC_ALGO;

        HsmClient->ReqMsg.args = (void *)(uintptr_t)SOC_virtToPhy(HsmCMAC);

        HsmCMAC->Input = (uint8_t *)(uintptr_t)SOC_virtToPhy(HsmCMAC->Input);

        HsmCMAC->CMAC = (uint8_t *)(uintptr_t)SOC_virtToPhy(HsmCMAC->CMAC);

        HsmClient->ReqMsg.crcArgs = crc16_ccit((uint8_t *)HsmCMAC, sizeof(HsmCMAC_t));

        CacheP_wbInv(HsmCMAC, GET_CACHE_ALIGNED_SIZE(sizeof(HsmCMAC_t)), CacheP_TYPE_ALL);

        CacheP_wbInv(HsmCMAC->Input, GET_CACHE_ALIGNED_SIZE(sizeof(uint8_t)), CacheP_TYPE_ALL);

        CacheP_wbInv(HsmCMAC->CMAC, GET_CACHE_ALIGNED_SIZE(sizeof(uint8_t)), CacheP_TYPE_ALL);

        status = HsmClient_SendAndRecv(HsmClient, timeout);

        if (status == SystemP_SUCCESS)

        {

            if (HsmClient->RespFlag == HSM_FLAG_NACK)

            {

                status = SystemP_FAILURE;

            }

            else

            {

                HsmClient->RespMsg.args = (void *)SOC_phyToVirt((uint64_t)HsmClient->RespMsg.args);

                CacheP_inv((void *)HsmClient->RespMsg.args, GET_CACHE_ALIGNED_SIZE(sizeof(HsmCMAC_t)), CacheP_TYPE_ALL);

                crcArgs = crc16_ccit((uint8_t *)HsmClient->RespMsg.args, sizeof(HsmCMAC_t));

                ((HsmCMAC_t *)HsmClient->RespMsg.args)->CMAC = (uint8_t *)SOC_phyToVirt((uint64_t)(((HsmCMAC_t *)HsmClient->RespMsg.args)->CMAC));

                CacheP_inv((void *)((HsmCMAC_t *)HsmClient->RespMsg.args)->CMAC, GET_CACHE_ALIGNED_SIZE(((uint8_t)*(((HsmCMAC_t *)HsmClient->RespMsg.args)->CMAC))), CacheP_TYPE_ALL);

     

                if (crcArgs == HsmClient->RespMsg.crcArgs)

                {

                    status = SystemP_SUCCESS;

                }

                else

                {

                    DebugP_log("\r\n [HSM_CLIENT] CRC check for AES CMAC Algo response failed \r\n");

                    status = SystemP_FAILURE;

                }

            }

        }

        /* If failure occur due to some reason */

        else if (status == SystemP_FAILURE)

        {

            status = SystemP_FAILURE;

        }

        /* Indicate timeout error */

        else

        {

            status = SystemP_TIMEOUT;

        }

        return status;

    Then create a new service handler in M4

    as follows:

    void HsmServer_AES_CMAC_Algo_Handler(uint8_t remoteCoreId, uint8_t localClientId, uint8_t remoteClientId,uint8_t *msgValue)

    {

        HsmMsg_t* message = (HsmMsg_t*) (void*)msgValue;

        HsmCMAC_t* HsmCMAC = NULL;

        uint16_t crcArgs ;

        hsmSrvResponse_t Response = HSM_SRV_RSP_OPT_FAILURE;

        uint8_t AES_CMAC_Key[32] =

        {

            0x1C,0x47,0xA8,0x11,0xB4,0x1E,0x22,0x33,0x33

            0xBA,0x8E,0xF0,0x39,0x4C,0x09,0x34

        };

        crcArgs = HsmServer_crc16_ccit((uint8_t*) message->args, sizeof(HsmCMAC_t));

        if(crcArgs == message->crcArgs)

        {

            HsmCMAC = message->args ;

                Response = AES_CMAC_Algo(AES_CMAC_Key, HsmCMAC->Key_Len, HsmCMAC->Input, HsmCMAC->Input_Len, HsmCMAC->CMAC, HsmCMAC->StreamState);

            HsmCMAC->Response = Response;

            if(message->flags == HSM_FLAG_AOP)

            {

                gHsmServer.RespMsg.serType = HSM_MSG_AES_CMAC_ALGO;

                gHsmServer.RespMsg.flags = HSM_FLAG_ACK ;

                gHsmServer.RespMsg.destClientId = remoteClientId ;

                gHsmServer.RespMsg.srcClientId = localClientId ;

                gHsmServer.RespMsg.args = (void*)HsmCMAC;

                HsmServer_calCRC(&gHsmServer.RespMsg,sizeof(HsmCMAC_t));

           SIPC_sendMsg(remoteCoreId,remoteClientId,localClientId,(uint8_t*)&gHsmServer.RespMsg,WAIT_IF_FIFO_FULL);

            }

            else

            {

            }

        }

        else

        {

            if(message->flags == HSM_FLAG_AOP)

            {

                gHsmServer.RespMsg.serType = HSM_MSG_AES_CMAC_ALGO;

                gHsmServer.RespMsg.flags = HSM_FLAG_NACK ;

                gHsmServer.RespMsg.args = message->args ;

                gHsmServer.RespMsg.destClientId = remoteClientId ;

                gHsmServer.RespMsg.srcClientId = localClientId ;

                HsmServer_calCRC(&gHsmServer.RespMsg,sizeof(HsmCMAC_t));

    SIPC_sendMsg(remoteCoreId,remoteClientId,localClientId,(uint8_t*)&gHsmServer.RespMsg,WAIT_IF_FIFO_FULL);

            }

            else

            {

            }

        }

    }

    The algorithm of AES_CMAC_Algo is as follows:

    hsmSrvResponse_t AES_CMAC_Algo(uint8_t *Key, uint32_t Key_Len, uint8_t *Input, uint32_t Input_Len, uint8_t *CMAC, uint8_t StreamState)

    {

        Crypto_Params       params;

        DTHE_AES_Return_t   status = DTHE_AES_RETURN_FAILURE;

        /* All zero buffer used while processing key1 and key2*/

        uint8_t gCryptoAesCmacZerosInput[16] =

        {

            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

        };

             if((Key == NULL) || ((Input == NULL)&&(StreamState == AES_STREAM_MODE_UPDATE)) || (CMAC == NULL) )

             {

                       return HSM_SRV_RSP_OPT_FAILURE;

             }

        if((StreamState == AES_STREAM_MODE_ONESHOT)||(StreamState == AES_STREAM_MODE_START))

        {

            status = DTHE_AES_open(gShaHandle);

            if(status != DTHE_AES_RETURN_SUCCESS)

            {

                return HSM_SRV_RSP_OPT_FAILURE;

            }

     

            /*生成K1和K2*/

            /* Subkeys Key1 and Key2 are derived from K through the subkey generation algorithm */

            /* AES-256 with key is applied to an all-zero input block. */

            status = app_aes_ecb(gCryptoAesCmacZerosInput, Key, Key_Len, 16, params.aesWithKeyAppliedToZeroInput);

            if(status != DTHE_AES_RETURN_SUCCESS)

            {

                return HSM_SRV_RSP_OPT_FAILURE;

            }

            DTHE_AES_close(gShaHandle);

            /* Subkey generation algorithm */

            status = app_cmacGenSubKeys(&params);

            if(status != SystemP_SUCCESS)

            {

                return HSM_SRV_RSP_OPT_FAILURE;

            }

        }

        if(StreamState == AES_STREAM_MODE_ONESHOT)

        {

            if(Input_Len > 0)

            {

                status = app_aes_cmac_dthe(Input, Key, Key_Len, &params.key1[0], &params.key2[0], Input_Len, CMAC);

                if(status != DTHE_AES_RETURN_SUCCESS)

                {

                    return HSM_SRV_RSP_OPT_FAILURE;

                }

            }

            /*针对空消息 填充0x80*/

            else

            {

                Input[0] |= 0x80;

                app_xor_128(Input, &params.key2[0], Input);

                status = app_aes_ecb(Input, Key, Key_Len, 16, CMAC);

                if(status != DTHE_AES_RETURN_SUCCESS)

                {

                    return HSM_SRV_RSP_OPT_FAILURE;

                }

            }

            if(status != DTHE_AES_RETURN_SUCCESS)

            {

                return HSM_SRV_RSP_OPT_FAILURE;

            }

        }

        else if(StreamState == AES_STREAM_MODE_START)

        {

            status = app_aes_cmac_dthe_stream_start(Key, Key_Len, &params.key1[0], &params.key2[0]);

            if(status != DTHE_AES_RETURN_SUCCESS)

            {

                return HSM_SRV_RSP_OPT_FAILURE;

            }

        }

        else if(StreamState == AES_STREAM_MODE_UPDATE)

        {

            status = app_aes_cmac_dthe_stream_update(&Input, Input_Len);

            if(status != DTHE_AES_RETURN_SUCCESS)

            {

                return HSM_SRV_RSP_OPT_FAILURE;

            }       

        }

        else if(StreamState == AES_STREAM_MODE_FINISH)

        {

            status = app_aes_cmac_dthe_stream_finish(CMAC);

            if(status != DTHE_AES_RETURN_SUCCESS)

            {

                return HSM_SRV_RSP_OPT_FAILURE;

            }

            status = DTHE_AES_close(gShaHandle);

            if(status != DTHE_AES_RETURN_SUCCESS)

            {

                return HSM_SRV_RSP_OPT_FAILURE;

            }

        }

        else

        {

            return HSM_SRV_RSP_OPT_FAILURE;

        }

        return HSM_SRV_RSP_OK;

    }

    static DTHE_AES_Return_t app_aes_cmac_dthe(uint8_t *input, uint8_t *key, uint32_t Key_Len, uint8_t *k1, uint8_t *k2, uint32_t inputLen, uint8_t *tag)

    {

        DTHE_AES_Return_t   status = DTHE_AES_RETURN_FAILURE;

        DTHE_AES_Params     aesParams;

        /* Initialize the AES Parameters: */

        (void)memset ((void *)&aesParams, 0, sizeof(DTHE_AES_Params));

     

        aesParams.algoType          = DTHE_AES_CMAC_MODE;

        aesParams.opType            = DTHE_AES_ENCRYPT;

        aesParams.useKEKMode        = FALSE;

        aesParams.ptrKey            = (uint32_t*)&key[0];

        aesParams.ptrKey1           = (uint32_t*)&k1[0];

        aesParams.ptrKey2           = (uint32_t*)&k2[0];

        aesParams.keyLen            = Key_Len;             

        aesParams.ptrPlainTextData  = (uint32_t*)SOC_virtToPhy((void *)&input[0]);

        aesParams.dataLenBytes      = inputLen;

        aesParams.ptrTag            = (uint32_t*)SOC_virtToPhy((void *)&tag[0]);

        /* opens aes driver */

        // status = DTHE_AES_open(gShaHandle);

        // DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);

     

        /* Encryption */

        status = DTHE_AES_execute(gShaHandle, &aesParams);

        // DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);

     

        /* Closing aes driver */

        // DTHE_AES_close(gShaHandle);

        return status;

    }

    app_aes_cmac_dthe_stream_start、app_aes_cmac_dthe_stream_update、app_aes_cmac_dthe_stream_finish These functions have already been sent before.

    Finally, call the following statement in R5:

    uint8_t Text[64] =

        {

            0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,

            0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,

            0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,

            0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,

            0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,

            0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,

            0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,

            0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10

        };

        uint8_t Text1[65] =

        {

            0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,

            0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,

            0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,

            0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,

            0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,

            0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,

            0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,

            0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,

            0x10

        };

        uint8_t Text2[86] =

        {

            0x11, 0x34, 0x44, 0x75, 0x2e, 0x65, 0x66, 0x88,

            0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x44, 0x17, 0x2a,

            0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,

            0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,

            0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,

            0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,

            0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,

            0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,

            0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,

            0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,

            0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f,

        };

        ①status = AES_CMAC_Algo_HSM(AES128_KEY1_INDEX, HSM_KEY_BASE_ADDR, DTHE_AES_KEY_128_SIZE, Text, sizeof(Text),   AES128_CMAC1, AES_STREAM_MODE_ONESHOT);

     

        ②status = AES_CMAC_Algo_HSM(AES128_KEY1_INDEX, HSM_KEY_BASE_ADDR, DTHE_AES_KEY_128_SIZE, NULL,  0x00U,         AES128_CMAC2, AES_STREAM_MODE_START);

        ③status = AES_CMAC_Algo_HSM(AES128_KEY1_INDEX, HSM_KEY_BASE_ADDR, DTHE_AES_KEY_128_SIZE, Text1, sizeof(Text1), AES128_CMAC2, AES_STREAM_MODE_UPDATE);

        ④status = AES_CMAC_Algo_HSM(AES128_KEY1_INDEX, HSM_KEY_BASE_ADDR, DTHE_AES_KEY_128_SIZE, Text2, sizeof(Text2), AES128_CMAC2, AES_STREAM_MODE_UPDATE);

    ⑤status = AES_CMAC_Algo_HSM(AES128_KEY1_INDEX, HSM_KEY_BASE_ADDR, DTHE_AES_KEY_128_SIZE, NULL,  0x00U,         AES128_CMAC2, AES_STREAM_MODE_FINISH);

    The above sentence① runs normally and CMAC is also correct. The states returned by ②, ③, ④, and ⑤ are correct, but the results are incorrect.

  • Hi,

    in 2 ,3, 4, 5 is CMAC incorrect all steps, I mean, ideally each should be similar to one -shot method right?

    Thanks and Regards,

    Nikhil Dasan

  • I'm not entirely clear about your meaning. Steps 2-5 form a complete process. It's only at step 5 that we can see whether the CMAC is correct. What I can confirm now is that the status returned from steps 2-5 is correct, and the CMAC algorithm on the M4 side is running normally. However, the CMAC result is just incorrect. Yet, this exact logic runs correctly on R5. The process starts with AES_STREAM_MODE_START, then loads data twice via two calls to AES_STREAM_MODE_UPDATE, and finally completes the calculation by loading the remaining data through the finish operation.

  • Upon initial analysis, 

    I see that one difference between R5 and M4 code is that for R5 code as shown below

    R5F

    aesParams.ptrPlainTextData  = (uint32_t*)&gCmac_unprocessed_block[0U];

    M4

    aesParams.ptrPlainTextData  = (uint32_t*)SOC_virtToPhy((void *)&gCmac_unprocessed_block[0U]);

    Can you add SOC_virtToPhy in all aesParams.ptrPlainTextData in update and finish APIs and also in app_aes_ecb plain and encrypted text as shown above?

    Thanks and Regards,

    Nikhil Dasan

  • Hello, after adding SOC_virtToPhy to ptrPlainTextData in the update and finish functions, the program runs correctly.

    Through simulation, I learned that SOC_virtToPhy on the M4 core adds an offset of 0x20020000U to RAM addresses 0x0-0x40000. What is the purpose of this? Is it to convert the memory view to a global view, as I understand it?

    I have a question regarding this: since the above gCmac_unprocessed_block is a global variable defined in the M4 core, the aesParams.ptrPlainTextData variable requires the SOC_virtToPhy operation. However, for variables such as aesParams.ptrKey, aesParams.ptrKey2, and aesParams.ptrKey3 in the app_aes_cmac_dthe_stream_start function, which are also defined in the M4 core, no SOC_virtToPhy operation is performed. Similarly, operations like memcpy(&gCmac_unprocessed_block[gCmac_unprocessed_len], *input, APP_CRYPTO_AES_BLOCK_LENGTH - gCmac_unprocessed_len) are not converted either. Could you list the scenarios where SOC_virtToPhy is necessary?

    Regarding RAM addresses passed from the R5 core, such as 0x70042345, my current code also adds SOC_virtToPhy. Is its purpose to convert the virtual addresses (memory view) of the TCM allocated to each core into physical addresses (global view)? Could you confirm if my understanding is correct?

    Thank you for your responses, experts

  • Hi,

    Through simulation, I learned that SOC_virtToPhy on the M4 core adds an offset of 0x20020000U to RAM addresses 0x0-0x40000. What is the purpose of this? Is it to convert the memory view to a global view, as I understand it?

    Yes, this is the same concept as local and global address.

    I have a question regarding this: since the above gCmac_unprocessed_block is a global variable defined in the M4 core, the aesParams.ptrPlainTextData variable requires the SOC_virtToPhy operation. However, for variables such as aesParams.ptrKey, aesParams.ptrKey2, and aesParams.ptrKey3 in the app_aes_cmac_dthe_stream_start function, which are also defined in the M4 core, no SOC_virtToPhy operation is performed. Similarly, operations like memcpy(&gCmac_unprocessed_block[gCmac_unprocessed_len], *input, APP_CRYPTO_AES_BLOCK_LENGTH - gCmac_unprocessed_len) are not converted either. Could you list the scenarios where SOC_virtToPhy is necessary?

    The global addresses are accessed when other master is trying to access the content. In this case, the PlaintextData and EncryptData are being accessed by DMA, (as DMA would be enabled by default). The other fields are accessed by HSM core itself.

    Hence the DMA accessed fields should be in global address and HSM accessed field is local address. 

    Regarding RAM addresses passed from the R5 core, such as 0x70042345, my current code also adds SOC_virtToPhy. Is its purpose to convert the virtual addresses (memory view) of the TCM allocated to each core into physical addresses (global view)? Could you confirm if my understanding is correct?

    Yes, correct, on the R5 side, this is for only if data is in TCM region, i.e. local to global mapping of TCM region. Data in OCRAM does not apply these changes.

    Thanks and Regards,

    Nikhil Dasan

  • I have a few more questions:

    1、Is it necessary to perform DTHE_AES_open and DTHE_AES_close every time a DTHE operation is executed? For example, if I first need to perform an AES_CBC operation, I would do DTHE_AES_open, then DTHE_AES_execute, followed by DTHE_AES_close. Then, for an AES_ECB operation, would I repeat the same three steps? Or can I simply execute DTHE_AES_open once, then perform DTHE_AES_execute for both CBC and ECB operations without closing in between? Currently, the program runs normally when following the three-step approach each time.

    2、Is it recommended to execute HsmClient_register(&client, APP_CLIENT_ID) and HsmClient_unregister(&client, APP_CLIENT_ID) every time an IPC service is requested from the HSM core? Currently, the program runs normally when registering once, sending a request, and then unregistering.

    3、In AES operations, apart from PlaintextData and EncryptData, does aesParams.ptrTag also require SOC_virtToPhy conversion? I noticed this in the example code—what is the rationale behind this? For SHA, is it only shaParams.ptrDataBuffer that needs to be accessed by DMA (global access)? My understanding is that if the code runs within its own core, no local-to-global conversion is needed. Is that correct?

    4、Would it be safer to always perform SOC_virtToPhy on addresses passed from the R5 core to the M4 core whenever DMA is involved, since I may not know whether the incoming data resides in TCM? Similarly, would it be safer for the R5 core to always perform SOC_phyToVirt on addresses received from the M4 core or other R5 cores

    Thank you for your responses, experts
  • For example, if I first need to perform an AES_CBC operation, I would do DTHE_AES_open, then DTHE_AES_execute, followed by DTHE_AES_close. Then, for an AES_ECB operation, would I repeat the same three steps? Or can I simply execute DTHE_AES_open once, then perform DTHE_AES_execute for both CBC and ECB operations without closing in between? Currently, the program runs normally when following the three-step approach each time.

    The open and close would typically reset the AES module. Are you facing issues if you are not doing the same?

    Is it recommended to execute HsmClient_register(&client, APP_CLIENT_ID) and HsmClient_unregister(&client, APP_CLIENT_ID) every time an IPC service is requested from the HSM core? Currently, the program runs normally when registering once, sending a request, and then unregistering.

    One register should be sufficient for all services

    In AES operations, apart from PlaintextData and EncryptData, does aesParams.ptrTag also require SOC_virtToPhy conversion? I noticed this in the example code—what is the rationale behind this? For SHA, is it only shaParams.ptrDataBuffer that needs to be accessed by DMA (global access)? My understanding is that if the code runs within its own core, no local-to-global conversion is needed. Is that correct?

    Yes, correct. self core needs no conversion. Only DMA accessed data needs conversion

    Would it be safer to always perform SOC_virtToPhy on addresses passed from the R5 core to the M4 core whenever DMA is involved, since I may not know whether the incoming data resides in TCM? Similarly, would it be safer for the R5 core to always perform SOC_phyToVirt on addresses received from the M4 core or other R5 cores

    Soc_virtToPhy works differently for R5 and M4. For R5 it is for TCM (global/local mapping) and for M4 it is for HSM RAM (global/local mapping)

    Thanks and Regards,

    Nikhil Dasan