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.

[FAQ] MCU-PLUS-SDK-AM263X: How to implement streaming or scatter gather mode for DTHE-AES ?

Part Number: MCU-PLUS-SDK-AM263X

Q1. How to optimize the DTHE-AES engine usage to support multiple algorithm in parallel or support to use it by-parts ?

Q2. How to optimize the memory usage by reusing the same region for authentication ?

Q3. What if my data is not continuous ? Can I do scatter-gather mode of AES operations for the same ?

  • Taking a reference of CBC in DTHE-AES

    CBC works with IV and Plaintext as XOR'ed and Key as another input to block cipher. The cipher text generated as an output.

    Let's take an input data of 16KB which is logically partitioned like this -

    We have defined the API in this manner -

    • Start API - Initializes the AES Parameters like AlgoType, opType, ptrKey, keyLen, ptrIV, ptrPlaintextData, ptrEncryptedData
      • IV for next input stream is updated in the API itself.
      • Currently the API only takes input as multishot option and output is provided at single location.
      • User is expected to update the new pointer to Plain Text Data is updated (either the data pointer changes or the data at a given time changes).
      • Also user is expected to provide the updated data length (if its changing).
    • Update API - Executes the DTHE Engine based on the params stored.
      • User is expected to update the new pointer to Plain Text Data is updated.
      • Also user is expected to provide the updated data length (if its changing).
    • Finish API - Provides the final data back to the SW at the Encrypted Address Location.

    Also using the same APIs in case of Scatter Gather Table. Implementation part of the c file attached. In this the example contains multiple memory fragments having the plain data which is being given together to the DTHE (or handled in such a fashion).

    What is the difference between Streaming Data and Scatter Gather Table ?

    • Scatter Gather Table allows a data which is spread across the memories and requires the processing to be done as a single blob. Although it is expected for the data of the scatter gather to be available at t=0 when the calls are made to DTHE.
    • Streaming Data allows a data which is not present at t=0 and is going to come till t(completion). The data needs to be processed accordingly with limited buffer allocation by reallocating the same memory during the run-time.

    Similarly this could be changed to create an implementation for AES-CBC-DECRYPT or even different protocol -

    Please find the example file (application level implementation for the same) -

    crypto_aes_cbc_256.c
    /*
     *  Copyright (C) 2022-23 Texas Instruments Incorporated
     *
     *  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.
     */
    
    /* This example demonstrates the DTHE AES 256 cbc Encryption and Decryptions. */
    
    #include <string.h>
    #include <kernel/dpl/DebugP.h>
    #include <security/crypto/dthe/dthe.h>
    #include <security/crypto/dthe/dthe_aes.h>
    #include "ti_drivers_config.h"
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    
    /* Input or output length*/
    #define APP_CRYPTO_AES_CBC_256_INOUT_LENGTH             (16U*1024U)
    /* AES CBC IV length in bytes */
    #define APP_CRYPTO_AES_CBC_256_IV_LENGTH_IN_BYTES       (16U)
    /* AES CBC KEY length in bytes */
    #define APP_CRYPTO_AES_CBC_256_KEY_LENGTH_IN_BYTES      (32U)
    /* AES CBC KEY Catche alignment size */
    #define APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT         (32U)
    /* DTHE Public address */
    #define CSL_DTHE_PUBLIC_U_BASE                          (0xCE000810U)
    /* DTHE Aes Public address */
    #define CSL_DTHE_PUBLIC_AES_U_BASE                      (0xCE007000U)
    /* DTHE Aes Public address */
    #define CSL_DTHE_PUBLIC_SHA_U_BASE                      (0xCE005000U)
    
    #define AES_BLOCK_SIZE                                  (16U)
    
    uint8_t gCryptoAesCbc256PlainText[APP_CRYPTO_AES_CBC_256_INOUT_LENGTH] __attribute__ ((aligned (APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT)));
    
    uint8_t gCryptoAesCbc256PlainTextPartA[8U*1024U] __attribute__ ((aligned (APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT)));
    
    /* The AES algorithm encrypts and decrypts data in blocks of 128 bits. It can do this using 128-bit or 256-bit keys */
    uint8_t gCryptoAesCbc256Key[APP_CRYPTO_AES_CBC_256_KEY_LENGTH_IN_BYTES] __attribute__ ((aligned (APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT))) =
    {
        0xc4U, 0x7bU, 0x02U, 0x94U, 0xdbU, 0xbbU, 0xeeU, 0x0fU,
        0xecU, 0x47U, 0x57U, 0xf2U, 0x2fU, 0xfeU, 0xeeU, 0x35U,
        0x87U, 0xcaU, 0x47U, 0x30U, 0xc3U, 0xd3U, 0x3bU, 0x69U,
        0x1dU, 0xf3U, 0x8bU, 0xabU, 0x07U, 0x6bU, 0xc5U, 0x58U
    };
    
    uint8_t gCryptoAesCbc256PlainTextPartB[4U*1024U] __attribute__ ((aligned (APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT)));
    
    /* Encrypted buffer of gCryptoAesCbc256PlainText */
    uint8_t gCryptoAesCbc256CipherText[APP_CRYPTO_AES_CBC_256_INOUT_LENGTH] __attribute__ ((aligned (APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT)));
    
    uint8_t gCryptoAesCbc256PlainTextPartC[2U*1024U] __attribute__ ((aligned (APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT)));
    
    uint8_t gCryptoAesCbc256CipherTextExp[APP_CRYPTO_AES_CBC_256_INOUT_LENGTH] __attribute__ ((aligned (APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT)));
    
    uint8_t gCryptoAesCbc256PlainTextPartD[1U*1024U] __attribute__ ((aligned (APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT)));
    
    /* Initialization vector (IV) is an arbitrary number that can be used along with a secret key for data encryption/decryption. */
    uint8_t gCryptoAesCbc256Iv[APP_CRYPTO_AES_CBC_256_IV_LENGTH_IN_BYTES] __attribute__ ((aligned (APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT))) =
    {
        0x01U, 0x02U, 0x03U, 0x04U, 0x05U, 0x06U, 0x07U, 0x08U,
        0x09U, 0x0AU, 0x0BU, 0x0CU, 0x0DU, 0x0EU, 0x0FU, 0xFFU
    };
    
    uint8_t gCryptoAesCbc256PlainTextPartE[1U*1024U] __attribute__ ((aligned (APP_CRYPTO_AES_CBC_256_CATCHE_ALIGNMENT)));
    
    typedef struct {
        uint32_t no_of_sgt_entries;
        uint8_t * ptr_in_A[16U];
        uint32_t A_in_len[16U];
        uint8_t * ptr_out_A;
    }sgtTable;
    
    DTHE_AES_Return_t DTHE_AES_execute_start(DTHE_Handle handle, DTHE_AES_Params* ptrParams)
    {
        DTHE_AES_Return_t   status;
    
        status = DTHE_AES_execute(handle, ptrParams);
        ptrParams->ptrIV = (uint32_t*)(&ptrParams->ptrEncryptedData[0U] + ((ptrParams->dataLenBytes - AES_BLOCK_SIZE)/sizeof(ptrParams->ptrEncryptedData[0U])));
        ptrParams->ptrEncryptedData  += ((ptrParams->dataLenBytes)/sizeof(ptrParams->ptrEncryptedData[0U]));
    
        return status;
    }
    
    DTHE_AES_Return_t DTHE_AES_execute_update(DTHE_Handle handle, DTHE_AES_Params* ptrParams)
    {
        DTHE_AES_Return_t   status;
    
        status = DTHE_AES_execute(handle, ptrParams);
        ptrParams->ptrIV = (uint32_t*)(&ptrParams->ptrEncryptedData[0U] + ((ptrParams->dataLenBytes - AES_BLOCK_SIZE)/sizeof(ptrParams->ptrEncryptedData[0U])));
        ptrParams->ptrEncryptedData  += ((ptrParams->dataLenBytes)/sizeof(ptrParams->ptrEncryptedData[0U]));
    
        return status;
    }
    
    DTHE_AES_Return_t DTHE_AES_execute_finish(DTHE_Handle handle, DTHE_AES_Params* ptrParams)
    {
        return DTHE_AES_RETURN_SUCCESS;
    }
    
    DTHE_AES_Return_t DTHE_AES_execute_SGT_mode(DTHE_Handle aesHandle, DTHE_AES_Params* ptrParams, sgtTable* ptrSGTtable)
    {
        DTHE_AES_Return_t   status;
        uint32_t curr_entry = 0;
    
        ptrParams->dataLenBytes      = ptrSGTtable->A_in_len[0U];
        ptrParams->ptrPlainTextData  = (uint32_t *)(ptrSGTtable->ptr_in_A[0U]);
        ptrParams->ptrEncryptedData  = (uint32_t *)(ptrSGTtable->ptr_out_A);
        status = DTHE_AES_execute_start(aesHandle, ptrParams);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
        ++curr_entry;
    
        while(ptrSGTtable->no_of_sgt_entries > curr_entry)
        {
            ptrParams->dataLenBytes      = ptrSGTtable->A_in_len[curr_entry];
            ptrParams->ptrPlainTextData  = (uint32_t *)(ptrSGTtable->ptr_in_A[curr_entry]);
            status = DTHE_AES_execute_update(aesHandle, ptrParams);
            DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
            ++curr_entry;
        }
    
        status = DTHE_AES_execute_finish(aesHandle, ptrParams);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        return DTHE_AES_RETURN_SUCCESS;
    }
    
    void crypto_aes_cbc_256_main(void *args)
    {
        Drivers_open();
        Board_driversOpen();
    
        DTHE_AES_Return_t   status;
        DTHE_Handle         aesHandle;
        DTHE_AES_Params     aesParams;
    
        /* opens DTHe driver */
        aesHandle = DTHE_open(0);
        DebugP_assert(aesHandle != NULL);
    
        DebugP_log("[CRYPTO] DTHE AES CBC-256 example started ...\r\n");
    
        (void)memset ((void *)&gCryptoAesCbc256PlainText, 0xFFU, sizeof(gCryptoAesCbc256PlainText));
        (void)memset ((void *)&gCryptoAesCbc256PlainTextPartA, 0xFFU, sizeof(gCryptoAesCbc256PlainTextPartA));
        (void)memset ((void *)&gCryptoAesCbc256PlainTextPartB, 0xFFU, sizeof(gCryptoAesCbc256PlainTextPartB));
        (void)memset ((void *)&gCryptoAesCbc256PlainTextPartC, 0xFFU, sizeof(gCryptoAesCbc256PlainTextPartC));
        (void)memset ((void *)&gCryptoAesCbc256PlainTextPartD, 0xFFU, sizeof(gCryptoAesCbc256PlainTextPartD));
        (void)memset ((void *)&gCryptoAesCbc256PlainTextPartE, 0xFFU, sizeof(gCryptoAesCbc256PlainTextPartE));
    
        /************************** Trying the One-Shot Mechanism **************************/
    
        /* Initialize the AES Parameters: */
        (void)memset ((void *)&aesParams, 0, sizeof(DTHE_AES_Params));
    
        /* Initialize the Encryption parameters in One-Shot */
        aesParams.algoType          = DTHE_AES_CBC_MODE;
        aesParams.opType            = DTHE_AES_ENCRYPT;
        aesParams.ptrKey            = (uint32_t*)&gCryptoAesCbc256Key[0];
        aesParams.keyLen            = DTHE_AES_KEY_256_SIZE;
        aesParams.ptrIV             = (uint32_t*)&gCryptoAesCbc256Iv[0];
        aesParams.ptrEncryptedData  = (uint32_t*)&gCryptoAesCbc256CipherTextExp[0];
        aesParams.dataLenBytes      = APP_CRYPTO_AES_CBC_256_INOUT_LENGTH;
        aesParams.ptrPlainTextData  = (uint32_t*)&gCryptoAesCbc256PlainText[0];
        aesParams.useKEKMode        = FALSE;
    
        /* Encryption */
        status = DTHE_AES_execute(aesHandle, &aesParams);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        /* Closing AES Driver */
        status = DTHE_AES_close(aesHandle);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        /* Closing DTHE driver */
        if (DTHE_RETURN_SUCCESS == DTHE_close(aesHandle))
        {
            status = DTHE_AES_RETURN_SUCCESS;
        }
        else
        {
            status = DTHE_AES_RETURN_FAILURE;
        }
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        /************************** Trying the Streaming Mechanism **************************/
    
        aesHandle = DTHE_open(0);
        DebugP_assert(aesHandle != NULL);
    
        /* Opens aes driver */
        status = DTHE_AES_open(aesHandle);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        /* Initialize the AES Parameters */
        (void)memset ((void *)&aesParams, 0, sizeof(DTHE_AES_Params));
    
        /* Initialize the encryption parameters in Streaming */
        aesParams.algoType          = DTHE_AES_CBC_MODE;
        aesParams.opType            = DTHE_AES_ENCRYPT;
        aesParams.ptrKey            = (uint32_t*)&gCryptoAesCbc256Key[0];
        aesParams.keyLen            = DTHE_AES_KEY_256_SIZE;
        aesParams.ptrIV             = (uint32_t*)&gCryptoAesCbc256Iv[0];
        aesParams.ptrPlainTextData  = (uint32_t*)&gCryptoAesCbc256PlainText[0];
        aesParams.ptrEncryptedData  = (uint32_t*)&gCryptoAesCbc256CipherText[0];
        aesParams.useKEKMode        = FALSE;
    
        /* Encryption */
        aesParams.dataLenBytes      = (8U*1024U);
        status = DTHE_AES_execute_start(aesHandle, &aesParams);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        aesParams.ptrPlainTextData  += ((aesParams.dataLenBytes)/sizeof(aesParams.ptrPlainTextData[0U]));
        aesParams.dataLenBytes      = (4U*1024U);
        status = DTHE_AES_execute_update(aesHandle, &aesParams);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        aesParams.ptrPlainTextData  += ((aesParams.dataLenBytes)/sizeof(aesParams.ptrPlainTextData[0U]));
        aesParams.dataLenBytes      = (2U*1024U);
        status = DTHE_AES_execute_update(aesHandle, &aesParams);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        aesParams.ptrPlainTextData  += ((aesParams.dataLenBytes)/sizeof(aesParams.ptrPlainTextData[0U]));
        aesParams.dataLenBytes      = (1U*1024U);
        status = DTHE_AES_execute_update(aesHandle, &aesParams);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        aesParams.ptrPlainTextData  += ((aesParams.dataLenBytes)/sizeof(aesParams.ptrPlainTextData[0U]));
        status = DTHE_AES_execute_update(aesHandle, &aesParams);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        status = DTHE_AES_execute_finish(aesHandle, &aesParams);
        DebugP_assert(DTHE_AES_RETURN_SUCCESS == status);
    
        /* Comparing Aes operation result with expected result One-Shot vs Streaming */
        if (memcmp ((void *)&gCryptoAesCbc256CipherTextExp[0], (void *)&gCryptoAesCbc256CipherText[0], APP_CRYPTO_AES_CBC_256_INOUT_LENGTH) == 0)
        {
            DebugP_log("[CRYPTO] DTHE AES CBC-256 example completed!!\r\n");
            DebugP_log("All tests have passed!!\r\n");
        }
        else
        {
            DebugP_log("[CRYPTO] DTHE AES CBC-256 example failed!!\r\n");
        }
    
        /************************** Trying the Scatter Gather Mechanism ********************************/
        sgtTable sgtTable_AES = {0U};
        sgtTable_AES.no_of_sgt_entries = 5U;
    
        sgtTable_AES.ptr_in_A[0U] = &gCryptoAesCbc256PlainTextPartA[0U];
        sgtTable_AES.A_in_len[0U] = sizeof(gCryptoAesCbc256PlainTextPartA);
    
        sgtTable_AES.ptr_in_A[1U] = &gCryptoAesCbc256PlainTextPartB[0U];
        sgtTable_AES.A_in_len[1U] = sizeof(gCryptoAesCbc256PlainTextPartB);
    
        sgtTable_AES.ptr_in_A[2U] = &gCryptoAesCbc256PlainTextPartC[0U];
        sgtTable_AES.A_in_len[2U] = sizeof(gCryptoAesCbc256PlainTextPartC);
    
        sgtTable_AES.ptr_in_A[3U] = &gCryptoAesCbc256PlainTextPartD[0U];
        sgtTable_AES.A_in_len[3U] = sizeof(gCryptoAesCbc256PlainTextPartD);
    
        sgtTable_AES.ptr_in_A[4U] = &gCryptoAesCbc256PlainTextPartE[0U];
        sgtTable_AES.A_in_len[4U] = sizeof(gCryptoAesCbc256PlainTextPartE);
    
        sgtTable_AES.ptr_out_A = &gCryptoAesCbc256CipherText[0U];
    
        /* Initialize the encryption parameters in Streaming */
        aesParams.algoType          = DTHE_AES_CBC_MODE;
        aesParams.opType            = DTHE_AES_ENCRYPT;
        aesParams.ptrKey            = (uint32_t*)&gCryptoAesCbc256Key[0];
        aesParams.keyLen            = DTHE_AES_KEY_256_SIZE;
        aesParams.ptrIV             = (uint32_t*)&gCryptoAesCbc256Iv[0];
        aesParams.useKEKMode        = FALSE;
    
        status = DTHE_AES_execute_SGT_mode(aesHandle, &aesParams, &sgtTable_AES);
    
        /* Comparing Aes operation result with expected result One-Shot vs Streaming */
        if (memcmp ((void *)&gCryptoAesCbc256CipherTextExp[0], (void *)&gCryptoAesCbc256CipherText[0], APP_CRYPTO_AES_CBC_256_INOUT_LENGTH) == 0)
        {
            DebugP_log("[CRYPTO] DTHE AES CBC-256 example completed!!\r\n");
            DebugP_log("All tests have passed!!\r\n");
        }
        else
        {
            DebugP_log("[CRYPTO] DTHE AES CBC-256 example failed!!\r\n");
        }
    
        Board_driversClose();
        Drivers_close();
    
        return;
    }
    
    /* Public context crypto dthe, aes and sha accelerators base address */
    DTHE_Attrs gDTHE_Attrs[1] =
    {
        {
            /* crypto accelerator base address */
            .caBaseAddr         = CSL_DTHE_PUBLIC_U_BASE,
            /* AES base address */
            .aesBaseAddr        = CSL_DTHE_PUBLIC_AES_U_BASE,
            /* SHA base address */
            .shaBaseAddr        = CSL_DTHE_PUBLIC_SHA_U_BASE,
            /* For checking dthe driver open or close */
            .isOpen             = FALSE,
        },
    };
    
    DTHE_Config gDtheConfig[1]=
    {
        {
            &gDTHE_Attrs[0],
        },
    };
    uint32_t gDtheConfigNum = 1;