/*!
* @file     Crypto_Cse.c
*
* @version  1.0.0
*
* @brief    AUTOSAR Crypto Driver 
 *           
* @attention
*
* Project Name      : AUTOSAR MCAL
*
* Platform          : Arm
*
* Autosar Standard  : Classic Platform 4.4.0
*
* Compiled Version  : G32A10xx_MCAL_1_0_0_15-Nov-25
*
* Copyright (C) 2026 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (Geehy Semiconductor Software License Agreement).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the Geehy Semiconductor Software License Agreement for the governing permissions
* and limitations under the License.
*/

#ifdef __cplusplus
extern "C"{
#endif

#include "Crypto_AesReg.h"
#include "Crypto_Cse.h"
#include "StdRegMacros.h"
#include "CryIf_Cbk.h"
#include "Crypto_Impl.h"
#include "SchM_Crypto.h"
#include "Crypto_Aes256.h"
#include "Crypto_Sha256.h"
#include "Crypto_ShaReg.h"
#include "Crypto_Rng.h"
#include "Crypto_RngReg.h"
/** @addtogroup G32A10xx_StdPeriphDriver
  @{
*/

/** @defgroup CRYPTO_Driver
  * @brief CRYPTO driver modules
  @{
*/

/** @defgroup CRYPTO_Macros
  @{
*/
/*******************************************************************************
                    VENDOR ID & AUTOSAR VERSION INFO
*******************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define CRYPTO_CSE_VENDOR_ID                            0x00C1U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION             0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define CRYPTO_CSE_AR_RELEASE_MINOR_VERSION             0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define CRYPTO_CSE_AR_RELEASE_REVISION_VERSION          0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define CRYPTO_CSE_SW_MAJOR_VERSION                     0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define CRYPTO_CSE_SW_MINOR_VERSION                     0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define CRYPTO_CSE_SW_PATCH_VERSION                     0x00U

/*******************************************************************************
                             VERSION CHECK
*******************************************************************************/
/* Make sure the vendor id is the same between Crypto_Cse.c and StdRegMacros.h */
#if (CRYPTO_CSE_VENDOR_ID != STD_REG_MACROS_H_VENDOR_ID)
    #error "Vendor id mismatch between Crypto_Cse.c and StdRegMacros.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Crypto_Cse.c and StdRegMacros.h */
#if (CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION != STD_REG_MACROS_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR major version number mismatch between Crypto_Cse.c and StdRegMacros.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Crypto_Cse.c and StdRegMacros.h */
#if (CRYPTO_CSE_AR_RELEASE_MINOR_VERSION != STD_REG_MACROS_H_AR_RELEASE_MINOR_VERSION)
    #error "AUTOSAR minor version number mismatch between Crypto_Cse.c and StdRegMacros.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Crypto_Cse.c and StdRegMacros.h */
#if (CRYPTO_CSE_AR_RELEASE_REVISION_VERSION != STD_REG_MACROS_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR revision version number mismatch between Crypto_Cse.c and StdRegMacros.h"
#endif
/* Make sure the software major version number is the same between Crypto_Cse.c and StdRegMacros.h */
#if (CRYPTO_CSE_SW_MAJOR_VERSION != STD_REG_MACROS_H_SW_MAJOR_VERSION)
    #error "Software major version number mismatch between Crypto_Cse.c and StdRegMacros.h"
#endif
/* Make sure the software minor version number is the same between Crypto_Cse.c and StdRegMacros.h */
#if (CRYPTO_CSE_SW_MINOR_VERSION != STD_REG_MACROS_H_SW_MINOR_VERSION)
    #error "Software minor version number mismatch between Crypto_Cse.c and StdRegMacros.h"
#endif
/* Make sure the software patch version number is the same between Crypto_Cse.c and StdRegMacros.h */
#if (CRYPTO_CSE_SW_PATCH_VERSION != STD_REG_MACROS_H_SW_PATCH_VERSION)
    #error "Software patch version number mismatch between Crypto_Cse.c and StdRegMacros.h"
#endif
/* Make sure the vendor id is the same between Crypto_Cse.c and Crypto_Cse.h */
#if (CRYPTO_CSE_VENDOR_ID != CRYPTO_CSE_H_VENDOR_ID)
    #error "Vendor id mismatch between Crypto_Cse.c and Crypto_Cse.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Crypto_Cse.c and Crypto_Cse.h */
#if (CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION != CRYPTO_CSE_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR major version number mismatch between Crypto_Cse.c and Crypto_Cse.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Crypto_Cse.c and Crypto_Cse.h */
#if (CRYPTO_CSE_AR_RELEASE_MINOR_VERSION != CRYPTO_CSE_H_AR_RELEASE_MINOR_VERSION)
    #error "AUTOSAR minor version number mismatch between Crypto_Cse.c and Crypto_Cse.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Crypto_Cse.c and Crypto_Cse.h */
#if (CRYPTO_CSE_AR_RELEASE_REVISION_VERSION != CRYPTO_CSE_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR revision version number mismatch between Crypto_Cse.c and Crypto_Cse.h"
#endif
/* Make sure the software major version number is the same between Crypto_Cse.c and Crypto_Cse.h */
#if (CRYPTO_CSE_SW_MAJOR_VERSION != CRYPTO_CSE_H_SW_MAJOR_VERSION)
    #error "Software major version number mismatch between Crypto_Cse.c and Crypto_Cse.h"
#endif
/* Make sure the software minor version number is the same between Crypto_Cse.c and Crypto_Cse.h */
#if (CRYPTO_CSE_SW_MINOR_VERSION != CRYPTO_CSE_H_SW_MINOR_VERSION)
    #error "Software minor version number mismatch between Crypto_Cse.c and Crypto_Cse.h"
#endif
/* Make sure the software patch version number is the same between Crypto_Cse.c and Crypto_Cse.h */
#if (CRYPTO_CSE_SW_PATCH_VERSION != CRYPTO_CSE_H_SW_PATCH_VERSION)
    #error "Software patch version number mismatch between Crypto_Cse.c and Crypto_Cse.h"
#endif
/* Make sure the vendor id is the same between Crypto_Cse.c and Crypto_Impl.h */
#if (CRYPTO_CSE_VENDOR_ID != CRYPTO_IMPL_H_VENDOR_ID)
    #error "Vendor id mismatch between Crypto_Cse.c and Crypto_Impl.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Crypto_Cse.c and Crypto_Impl.h */
#if (CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION != CRYPTO_IMPL_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR major version number mismatch between Crypto_Cse.c and Crypto_Impl.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Crypto_Cse.c and Crypto_Impl.h */
#if (CRYPTO_CSE_AR_RELEASE_MINOR_VERSION != CRYPTO_IMPL_H_AR_RELEASE_MINOR_VERSION)
    #error "AUTOSAR minor version number mismatch between Crypto_Cse.c and Crypto_Impl.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Crypto_Cse.c and Crypto_Impl.h */
#if (CRYPTO_CSE_AR_RELEASE_REVISION_VERSION != CRYPTO_IMPL_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR revision version number mismatch between Crypto_Cse.c and Crypto_Impl.h"
#endif
/* Make sure the software major version number is the same between Crypto_Cse.c and Crypto_Impl.h */
#if (CRYPTO_CSE_SW_MAJOR_VERSION != CRYPTO_IMPL_H_SW_MAJOR_VERSION)
    #error "Software major version number mismatch between Crypto_Cse.c and Crypto_Impl.h"
#endif
/* Make sure the software minor version number is the same between Crypto_Cse.c and Crypto_Impl.h */
#if (CRYPTO_CSE_SW_MINOR_VERSION != CRYPTO_IMPL_H_SW_MINOR_VERSION)
    #error "Software minor version number mismatch between Crypto_Cse.c and Crypto_Impl.h"
#endif
/* Make sure the software patch version number is the same between Crypto_Cse.c and Crypto_Impl.h */
#if (CRYPTO_CSE_SW_PATCH_VERSION != CRYPTO_IMPL_H_SW_PATCH_VERSION)
    #error "Software patch version number mismatch between Crypto_Cse.c and Crypto_Impl.h"
#endif

#ifdef ENABLE_INTERMODULE_MCAL_CHECK
    /* Make sure the AUTOSAR major version number is the same between Crypto_Cse.C and CryIf_Cbk.h */
    #if (CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION != CRYIF_CBK_H_AR_RELEASE_MAJOR_VERSION)
        #error "AUTOSAR major version number mismatch between Crypto_Impl.c and CryIf_Cbk.h"
    #endif
    /* Make sure the AUTOSAR minor version number is the same between Crypto_Cse.C and CryIf_Cbk.h */
    #if (CRYPTO_CSE_AR_RELEASE_MINOR_VERSION != CRYIF_CBK_H_AR_RELEASE_MINOR_VERSION)
        #error "AUTOSAR minor version number mismatch between Crypto_Impl.c and CryIf_Cbk.h"
    #endif
#endif

/*******************************************************************************
                            LOCAL DEFINES AND MACROS
*******************************************************************************/

/** AES256 block size in bytes */
#define CSE_AES_BLOCK_SIZE                   (0x10U)

/** SHA256 max input data size in bytes */
#define CSE_HASH_INPUTDATA_LENGTH_MAX        ((uint16)0xE00U) 

#define CSE_HASH_CTRL_TYPE_SHA256            ((uint32)0x00000008U)

/** SHA256 block size in bytes */
#define HASH_BLOCK_SIZE                      (0x38U)   //(64 - 8) = 56 Bytes
#define HASH_ONEBLOCK_SIZE                   (0x40U)   //64 Bytes
#define HASH_ONEBLOCK_USED                   (0x37U)   //(64 - 8 - 1) = 55 Bytes

/** SHA256 max input data size in bytes */
#define HASH_INPUTDATA_LENGTH_MAX            (0xFB7U)  //(63 * 64 - 9) = 4023 Bytes
/**@} end of group CRYPTO_Macros */
/*******************************************************************************
                            LOCAL VARIABLES
*******************************************************************************/
/** @defgroup CRYPTO_Variable
  @{
*/
#define CRYPTO_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Crypto_MemMap.h"

/** Current state of the command */
static VAR(Crypto_Cse_CmdStateType, AUTOMATIC) g_cseCmdState;

#define CRYPTO_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Crypto_MemMap.h"

#define CRYPTO_START_SEC_VAR_INIT_UNSPECIFIED
#include "Crypto_MemMap.h"

/** Current working state of the CSE module */
static VAR(Crypto_Cse_WorkingStateType, CRYPTO_VAR) g_cseState = CSE_IDLE;

/** If the current command is sync or async */
static VAR(boolean, CRYPTO_VAR) g_isAsyncFunction = (boolean)FALSE;

static VAR(uint32, CRYPTO_VAR) g_uRandomNumber = 0u;

#define CRYPTO_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Crypto_MemMap.h"
/**@} end of group CRYPTO_Variable */
/*******************************************************************************
                        LOCAL FUNCTION DECLARATIONS
*******************************************************************************/
/** @defgroup CRYPTO_Fuctions
  @{
*/
#define CRYPTO_START_SEC_CODE
#include "Crypto_MemMap.h"

LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_CommandInit(
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) InputData,
    VAR(uint32, AUTOMATIC) NumberOfBlkn,
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) OutputData,
    VAR(Crypto_Cse_CommandType, AUTOMATIC) Cmd,
    VAR(uint32, AUTOMATIC) InputDataLength,
    VAR(uint32, AUTOMATIC) location,
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) SecondaryInputData,
    VAR(uint32, AUTOMATIC) SecondarydataLength,
    P2VAR(Crypto_VerifyResultType, AUTOMATIC, CRYPTO_APPL_DATA) verifyPtr
);

LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_ContinueEncryptDecrypt(void);

LOCAL_INLINE FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_StartGenerateHash(
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) inBuffer, 
    VAR(uint32, AUTOMATIC) lenBuffer, 
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) outBuffer);
    
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_ContinueRng(void);
    
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_ContinueGenerateHash (void);
    
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_ContinueMac(void);

LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_ContinueMpc(void);
    
LOCAL_INLINE FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_Sha256Process(VAR(uint8, AUTOMATIC) blkn, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) inBuffer, 
                        VAR(uint8, AUTOMATIC) lenBuffer, P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) outBuffer, 
                        P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) ivBuffer,VAR(Crypto_Sha256_ModeType, AUTOMATIC) mode);

static FUNC(void, CRYPTO_CODE) Crypto_Cse_ProcessInterrupt(void);
                        
#define CRYPTO_STOP_SEC_CODE
#include "Crypto_MemMap.h"

/*******************************************************************************
                            GLOBAL FUNCTIONS
*******************************************************************************/

#define CRYPTO_START_SEC_CODE
#include "Crypto_MemMap.h"

/*!
* @brief    Interrupt service routine to process the command
*/
ISR(SHA256_IRQHandler)
{
    Crypto_Cse_ProcessInterrupt();
    EXIT_INTERRUPT();
}

ISR(AES256_IRQHandler)
{
    Crypto_Cse_ProcessInterrupt();
    EXIT_INTERRUPT();
}

ISR(RNG_IRQHandler)
{
    Crypto_Cse_ProcessInterrupt();
    EXIT_INTERRUPT();
}

/*!
* @brief Interrupt service routine
*/
static FUNC(void, CRYPTO_CODE) Crypto_Cse_ProcessInterrupt(void)
{

    /* Check if hardware was initiated and interrupt is enabled */
    if (CSE_HW_READY == g_cseHardwareState)
    {
        switch (g_cseCmdState.cmd)
        {
            case CSE_CMD_GENERATE_MAC:
            case CSE_CMD_VERIFY_MAC:
                Crypto_Cse_ContinueMac();
                break;
            case CSE_CMD_ENC_CBC:
            case CSE_CMD_DEC_CBC:
            case CSE_CMD_ENC_ECB:
            case CSE_CMD_DEC_ECB:
            case CSE_CMD_ENC_CTR:
            case CSE_CMD_DEC_CTR:
                Crypto_Cse_ContinueEncryptDecrypt();
                break;
            case CSE_CMD_MP_COMPRESS:
                Crypto_Cse_ContinueMpc();
                break;
            case CSE_CMD_RND:
                Crypto_Cse_ContinueRng();
                break;
            case CSE_CMD_HASH:
                Crypto_Cse_ContinueGenerateHash();
                break;
            default:
                /* nothing */
                break;
        }
    }
    else
    {
        /* nothing */
    }
}

/*!
* @brief        Generate 32-bit random number
*
* @param[out]   RandomNumberPtr 32-bit buffer to store the generated random
*
* @return       Error code returned from hardware
*/
FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_GenerateRnd( P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) RandomNumberPtr,
               VAR(Crypto_ProcessingType, AUTOMATIC) Mode)
{
    VAR(Crypto_Cse_ErrorCodeType, AUTOMATIC) error = CSE_ERC_OK;

    g_cseState = CSE_BUSY;
    if(CRYPTO_PROCESSING_SYNC == Mode)
    {
        Crypto_Rng_Init();
        error = Crypto_Rng_WaitReady(CRYPTO_TIMEOUT_VALUE);
        switch (error)
        {
            case CSE_ERC_OK:
                g_uRandomNumber = Crypto_Rng_ReadRandomNumber();
                RandomNumberPtr[0] = (uint8)(g_uRandomNumber & 0xFFu);
                RandomNumberPtr[1] = (uint8)((g_uRandomNumber >> 8) & 0xFFu);
                RandomNumberPtr[2] = (uint8)((g_uRandomNumber >> 16) & 0xFFu);
                RandomNumberPtr[3] = (uint8)((g_uRandomNumber >> 24) & 0xFFu);
                break;
            default:
                /* nothing */
                break;
        }
        g_cseState = CSE_IDLE;
    }
    else
    {
        g_isAsyncFunction = (boolean)TRUE;

        Crypto_Cse_CommandInit(NULL_PTR, 0, RandomNumberPtr, CSE_CMD_RND, 0, 0, NULL_PTR, 0, NULL_PTR);
        g_cseCmdState.response = CSE_ERC_OK;
        Crypto_Rng_Init();
        Crypto_Rng_EnableInterrupt();
    }
    return error;
}

/*!
* @brief        Generate 256-bit HASH number
*
* @param[out]   RandomNumberPtr 32-bit buffer to store the generated random
*
* @return       Error code returned from hardware
*/
FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_GenerateHash(P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) inBuffer, VAR(uint32, AUTOMATIC) lenBuffer, 
     P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) outBuffer, VAR(Crypto_ProcessingType, AUTOMATIC) Mode)
{
    VAR(Crypto_Cse_ErrorCodeType, AUTOMATIC) error = CSE_ERC_ERROR;  
    
    VAR(uint32, AUTOMATIC) numberOfBlkn = ((lenBuffer + 8u)/HASH_ONEBLOCK_SIZE) + 1u;
    g_cseState = CSE_BUSY;
    Crypto_Cse_CommandInit(inBuffer, numberOfBlkn, outBuffer, CSE_CMD_HASH, 0, 0, NULL_PTR, 0, NULL_PTR);
    if(CRYPTO_PROCESSING_SYNC == Mode)
    {
        g_isAsyncFunction = (boolean)FALSE;
        error = Crypto_Cse_StartGenerateHash(inBuffer,lenBuffer,outBuffer);
        g_cseState = CSE_IDLE;
    }
    else
    {
        g_isAsyncFunction = (boolean)TRUE;
        error = Crypto_Cse_StartGenerateHash(inBuffer,lenBuffer,outBuffer);
    }
    return error;
}
/*!
* @brief        Perform AES-128 encryption in CTR mode with sync and async
* @details      
*
* @param[in]    mode                 AES256 Algorithm Direction:Encryption/Decryption_mode
* @param[in]    key                  key text buffer
* @param[in]    keysize              key size
* @param[in]    IV                   Initial Vectors 0-31 bit
* @param[in]    input                plain text message
* @param[in]    length               Number of bytes of plain text message to be encrypted.
*                                    Should be smaller than CSE_MAX_DATA_LEN bytes.
* @param[in]    syncmode             CRYPTO_PROCESSING_ASYNC or CRYPTO_PROCESSING_SYNC
* @param[out]   output               Cipher text buffer. The buffer shall have the same size as the plain text buffer.
*
* @return       Error code returned from hardware.
*               The output is valid if the error code is CSE_ERC_OK.
*/
FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_AesCtrEncryptDecrypt( VAR(Crypto_Aes256_OpcodeType, AUTOMATIC) mode, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) key,
                       VAR(Crypto_Aes256_KeySizeType, AUTOMATIC) keysize, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) IV, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) input,
                       VAR(uint32, AUTOMATIC) length, P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) output,VAR(Crypto_ProcessingType, AUTOMATIC) syncmode)
{
    VAR(Crypto_Cse_ErrorCodeType, AUTOMATIC) error = CSE_ERC_OK;    
    VAR(uint32, AUTOMATIC) numberOfBlkn = (length + CSE_AES_BLOCK_SIZE - 1u) / CSE_AES_BLOCK_SIZE;
    g_cseState = CSE_BUSY;
    
    if(CRYPTO_PROCESSING_SYNC == syncmode)
    {
        g_isAsyncFunction = (boolean)FALSE;
        error = Crypto_Aes256_GenerateCtr(mode, key, keysize,IV, input, length, output,syncmode);
        if(CSE_ERC_OK == error)
        {
            g_cseState = CSE_IDLE;
        }
        else
        {
            /* Nothing */
        }
    }
    else
    {
        g_isAsyncFunction = (boolean)TRUE;
        Crypto_Cse_CommandInit(input, numberOfBlkn, output, CSE_CMD_ENC_CTR, length, 0, NULL_PTR, 0, NULL_PTR);
        error = Crypto_Aes256_GenerateCtr(mode, key, keysize,IV, input, length, output,syncmode);
    }
    return error;
}
/*!
* @brief        Perform AES-128 encryption in CBC mode with sync and async
* @details      This function assumes that the plaintext length is a multiple of 16 bytes.
*
* @param[in]    mode                 AES256 Algorithm Direction:Encryption/Decryption_mode
* @param[in]    key                  key text buffer
* @param[in]    keysize              key size
* @param[in]    IV                   Initial Vectors 0-31 bit
* @param[in]    input                plain text message
* @param[in]    length               Number of bytes of plain text message to be encrypted.
*                                    Should be smaller than CSE_MAX_DATA_LEN bytes.
* @param[in]    syncmode             CRYPTO_PROCESSING_ASYNC or CRYPTO_PROCESSING_SYNC
* @param[out]   output               Cipher text buffer. The buffer shall have the same size as the plain text buffer.
*
* @return       Error code returned from hardware.
*               The output is valid if the error code is CSE_ERC_OK.
*/
FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_AesCbcEncryptDecrypt( VAR(Crypto_Aes256_OpcodeType, AUTOMATIC) mode, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) key,
                       VAR(Crypto_Aes256_KeySizeType, AUTOMATIC) keysize, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) IV, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) input,
                       VAR(uint32, AUTOMATIC) length, P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) output,VAR(Crypto_ProcessingType, AUTOMATIC) syncmode)
{
    VAR(Crypto_Cse_ErrorCodeType, AUTOMATIC) error = CSE_ERC_OK; 
    VAR(uint32, AUTOMATIC) numberOfBlkn = (length + CSE_AES_BLOCK_SIZE - 1u) / CSE_AES_BLOCK_SIZE;
    g_cseState = CSE_BUSY;
    if(CRYPTO_PROCESSING_SYNC == syncmode)
    {
        g_isAsyncFunction = (boolean)FALSE;
        error = Crypto_Aes256_GenerateCbc(mode, key, keysize,IV, input, length, output,syncmode);
        if(CSE_ERC_OK == error)
        {
            g_cseState = CSE_IDLE;
        }
        else
        {
            /* Nothing */
        }
    }
    else
    {
        g_isAsyncFunction = (boolean)TRUE;
        Crypto_Cse_CommandInit(input, numberOfBlkn, output, CSE_CMD_ENC_CBC, length, 0, NULL_PTR, 0, NULL_PTR);
        error = Crypto_Aes256_GenerateCbc(mode, key, keysize,IV, input, length, output,syncmode);
    }
    return error;
}

/*!
* @brief        Perform AES-128 encryption in ECB mode with sync and async
* @details      This function assumes that the plaintext length is a multiple of 16 bytes.
*
* @param[in]    mode                 AES256 Algorithm Direction:Encryption/Decryption_mode
* @param[in]    key                  key text buffer
* @param[in]    keysize              key size
* @param[in]    input                plain text message
* @param[in]    length               Number of bytes of plain text message to be encrypted.
*                                    Should be smaller than CSE_MAX_DATA_LEN bytes.
* @param[in]    syncmode             CRYPTO_PROCESSING_ASYNC or CRYPTO_PROCESSING_SYNC
* @param[out]   output               Cipher text buffer. The buffer shall have the same size as the plain text buffer.
*
* @return       Error code returned from hardware.
*               The output is valid if the error code is CSE_ERC_OK.
*/
FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_AesEcbEncryptDecrypt( VAR(Crypto_Aes256_OpcodeType, AUTOMATIC) mode, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) key,
                       VAR(Crypto_Aes256_KeySizeType, AUTOMATIC) keysize, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) input,
                       VAR(uint32, AUTOMATIC) length, P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) output,VAR(Crypto_ProcessingType, AUTOMATIC) syncmode)
{
    VAR(Crypto_Cse_ErrorCodeType, AUTOMATIC) error = CSE_ERC_OK;    
    VAR(uint32, AUTOMATIC) numberOfBlkn = (length + CSE_AES_BLOCK_SIZE - 1u) / CSE_AES_BLOCK_SIZE;
    g_cseState = CSE_BUSY;
    if(CRYPTO_PROCESSING_SYNC == syncmode)
    {
        g_isAsyncFunction = (boolean)FALSE;
        error = Crypto_Aes256_GenerateEcb(mode, key, keysize, input, length, output,syncmode);
        if(CSE_ERC_OK == error)
        {
            g_cseState = CSE_IDLE;
        }
        else
        {
            /* Nothing */
        }
    }
    else
    {
        g_isAsyncFunction = (boolean)TRUE;
        Crypto_Cse_CommandInit(input, numberOfBlkn, output, CSE_CMD_ENC_ECB, length, 0, NULL_PTR, 0, NULL_PTR);
        error = Crypto_Aes256_GenerateEcb(mode, key, keysize, input, length, output,syncmode);
    }
    return error;
}

/*!
* @brief        Perform AES-128 encryption in MPC mode with sync and async
* @details      This function assumes that the plaintext length is a multiple of 16 bytes.
*
* @param[in]    mode                 AES256 Algorithm Direction:Encryption/Decryption_mode
* @param[in]    key                  key text buffer
* @param[in]    keysize              key size
* @param[in]    input                plain text message
* @param[in]    length               Number of bytes of plain text message to be encrypted.
*                                    Should be smaller than CSE_MAX_DATA_LEN bytes.
* @param[in]    syncmode             CRYPTO_PROCESSING_ASYNC or CRYPTO_PROCESSING_SYNC
* @param[out]   output               Cipher text buffer. The buffer shall have the same size as the plain text buffer.
*
* @return       Error code returned from hardware.
*               The output is valid if the error code is CSE_ERC_OK.
*/
FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_AesGenerateMpc(P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) input,VAR(uint32, AUTOMATIC) length, 
                       P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) output,VAR(Crypto_ProcessingType, AUTOMATIC) syncmode)
{
    VAR(Crypto_Cse_ErrorCodeType, AUTOMATIC) error = CSE_ERC_OK;    
    VAR(uint32, AUTOMATIC) numberOfBlkn = (length + CSE_AES_BLOCK_SIZE - 1u) / CSE_AES_BLOCK_SIZE;
    g_cseState = CSE_BUSY;
    if(CRYPTO_PROCESSING_SYNC == syncmode)
    {
        g_isAsyncFunction = (boolean)FALSE;
        error = Crypto_Aes256_GenerateMpc(input, length, output,syncmode);
        if(CSE_ERC_OK == error)
        {
            g_cseState = CSE_IDLE;
        }
        else
        {
            /* Nothing */
        }
    }
    else
    {
        g_isAsyncFunction = (boolean)TRUE;
        Crypto_Cse_CommandInit(input, numberOfBlkn, output, CSE_CMD_MP_COMPRESS, length, 0, NULL_PTR, 0, NULL_PTR);
        error = Crypto_Aes256_GenerateMpc(input, length, output,syncmode);
    }
    return error;
}

/*!
* @brief        Generate CMAC of the given message 
*
* @param[in]    KeyId       The key used for the operation
* @param[in]    DataPtr     Pointer to the input data
* @param[in]    DataLength  Number of bytes of the input data
* @param[out]   MacPtr      Pointer to 128-bit buffer containing the result of the CMAC generation
*
* @return       Error code returned from hardware
*/
FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_AesGenerateMac( P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) key, VAR(Crypto_Aes256_KeySizeType, AUTOMATIC) keysize, 
                       P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) IV, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) input,
                       VAR(uint32, AUTOMATIC) length, P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) output,VAR(Crypto_ProcessingType, AUTOMATIC) syncmode)
{
    VAR(Crypto_Cse_ErrorCodeType, AUTOMATIC) error = CSE_ERC_OK;    
    VAR(uint32, AUTOMATIC) numberOfBlkn = (length + CSE_AES_BLOCK_SIZE - 1u) / CSE_AES_BLOCK_SIZE;
    g_cseState = CSE_BUSY;
    if(CRYPTO_PROCESSING_SYNC == syncmode)
    {
        g_isAsyncFunction = (boolean)FALSE;
        error = Crypto_Aes256_GenerateCmac(key, keysize, IV, input, length, output, syncmode);
        if(CSE_ERC_OK == error)
        {
            g_cseState = CSE_IDLE;
        }
        else
        {
            /* Nothing */
        }
    }
    else
    {
        g_isAsyncFunction = (boolean)TRUE;
        Crypto_Cse_CommandInit(input, numberOfBlkn, output, CSE_CMD_GENERATE_MAC,length , 0, NULL_PTR, 0, NULL_PTR);

        error = Crypto_Aes256_GenerateCmac(key, keysize, IV, input, length, output, syncmode);
    }
    return (error);
}

/*!
* @brief        Verify CMAC of the given message 
*
* @param[in]    KeyId       The key used for the operation
* @param[in]    DataPtr     Pointer to the input data
* @param[in]    DataLength  Number of bytes of the input data
* @param[out]   MacPtr      Pointer to 128-bit buffer containing the result of the CMAC generation
*
* @return       Error code returned from hardware
*/
FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_MacVerify( P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) key, VAR(Crypto_Aes256_KeySizeType, AUTOMATIC) keysize, 
                       P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) IV, P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_CONST) JobPtr)
{
    VAR(Crypto_Cse_ErrorCodeType, AUTOMATIC) error = CSE_ERC_OK;  
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) input = JobPtr->jobPrimitiveInputOutput.inputPtr;
    VAR(uint32, AUTOMATIC) length = JobPtr->jobPrimitiveInputOutput.inputLength;
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) output = JobPtr->jobPrimitiveInputOutput.outputPtr;
    VAR(Crypto_ProcessingType, AUTOMATIC) syncmode = JobPtr->jobPrimitiveInfo->processingType;
    VAR(uint32, AUTOMATIC) numberOfBlkn = (length + CSE_AES_BLOCK_SIZE - 1u) / CSE_AES_BLOCK_SIZE;
    g_cseState = CSE_BUSY;
    if(CRYPTO_PROCESSING_SYNC == syncmode)
    {
        g_isAsyncFunction = (boolean)FALSE;
        error = Crypto_Aes256_GenerateCmac(key, keysize, IV, input, length, output, syncmode);
        if(CSE_ERC_OK == error)
        {
            g_cseState = CSE_IDLE;
        }
        else
        {
            /* Nothing */
        }
    }
    else
    {
        g_isAsyncFunction = (boolean)TRUE;
        Crypto_Cse_CommandInit(input, numberOfBlkn, output, CSE_CMD_VERIFY_MAC, length, 0, JobPtr->jobPrimitiveInputOutput.secondaryInputPtr, 
                                        JobPtr->jobPrimitiveInputOutput.secondaryInputLength, JobPtr->jobPrimitiveInputOutput.verifyPtr);

        error = Crypto_Aes256_GenerateCmac(key, keysize, IV, input, length, output, syncmode);
    }
    return (error);
}

/*!
* @brief Check if the hardware is busy
*/
FUNC(boolean, CRYPTO_CODE) Crypto_Cse_IsBusy(void)
{
    VAR(boolean, AUTOMATIC) isBusy = (boolean)TRUE;
    VAR(boolean, AUTOMATIC) aesBusyStatus = Crypto_Aes256_IsBusy();
    VAR(boolean, AUTOMATIC) shaBusyStatus = Crypto_Sha256_IsBusy();
    if ((((boolean)FALSE == aesBusyStatus) || ((boolean)FALSE == shaBusyStatus)) && (CSE_IDLE == g_cseState))
    {
        isBusy = (boolean)FALSE;
    }
    else
    {
        /* Nothing */
    }
    return isBusy;
}

/*!
* @brief    Cancel the job which is currently in progress
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_Cancel(void)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;

    SchM_Enter_Crypto_CRYPTO_CRITICAL_SECTION3();
    if (CSE_BUSY != g_cseState)
    {
        /* The driver is not busy, nothing to cancel. */
        result = (Std_ReturnType)E_NOT_OK;
    }
    else
    {
        /* The driver is busy, change to idle state. */
        g_cseState = CSE_IDLE;
        result = (Std_ReturnType)E_OK;
    }
    SchM_Exit_Crypto_CRYPTO_CRITICAL_SECTION3();
    return result;
}

#define CRYPTO_STOP_SEC_CODE
#include "Crypto_MemMap.h"

/*******************************************************************************
                        LOCAL FUNCTIONS
*******************************************************************************/
#define CRYPTO_START_SEC_CODE
#include "Crypto_MemMap.h"

/*!
* @brief        This function prepares the data structure for a command
*
* @param[in]    KeyId           Key ID
* @param[in]    InputData       Input data buffer to execute the command
* @param[in]    NumberOfBlkn    Number of Message Blocks to be Processed for input data
* @param[in]    OutputData      Output data buffer
* @param[in]    Cmd             The command to be executed
*/
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_CommandInit(
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) InputData,
    VAR(uint32, AUTOMATIC) NumberOfBlkn,
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) OutputData,
    VAR(Crypto_Cse_CommandType, AUTOMATIC) Cmd,
    VAR(uint32, AUTOMATIC) InputDataLength,
    VAR(uint32, AUTOMATIC) location,
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) SecondaryInputData,
    VAR(uint32, AUTOMATIC) SecondarydataLength,
    P2VAR(Crypto_VerifyResultType, AUTOMATIC, CRYPTO_APPL_DATA) verifyPtr)
{
    g_cseCmdState.BlknsWritten = 0U;
    g_cseCmdState.cmd = Cmd;
    g_cseCmdState.numberOfBlkn = NumberOfBlkn;
    g_cseCmdState.inputData = InputData;
    g_cseCmdState.outputData = OutputData;
    g_cseCmdState.response = CSE_ERC_GENERAL_ERROR;
    g_cseCmdState.dataLength = InputDataLength;
    g_cseCmdState.location = location;
    g_cseCmdState.secondaryInputData = SecondaryInputData;
    g_cseCmdState.secondarydataLength = SecondarydataLength;
    g_cseCmdState.verifyPtr = verifyPtr;
}

/*!
* @brief    Continue RNG-32 generate
*/
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_ContinueRng(void)
{
    if (CSE_IDLE == g_cseState)
    {
        g_cseCmdState.response = CSE_ERC_CANCELED;
    }
    else
    {
        g_cseState = CSE_IDLE;
    }
    
    if(g_isAsyncFunction != (boolean)FALSE)
    {
        Crypto_Rng_DisableInterrupt();
        Crypto_Impl_CallBackNotification(g_cseCmdState.response);
        g_isAsyncFunction = (boolean)FALSE;
    }
    else
    {
        /* Nothing */
    }
    if(CSE_ERC_OK == g_cseCmdState.response)
    {
        g_uRandomNumber = Crypto_Rng_ReadRandomNumber();
        g_cseCmdState.outputData[0] = (uint8)(g_uRandomNumber & 0xFFu);
        g_cseCmdState.outputData[1] = (uint8)((g_uRandomNumber >> 8) & 0xFFu);
        g_cseCmdState.outputData[2] = (uint8)((g_uRandomNumber >> 16) & 0xFFu);
        g_cseCmdState.outputData[3] = (uint8)((g_uRandomNumber >> 24) & 0xFFu);
    }
    else
    {
        /* Nothing */
    }
}

/*!
 * @brief     Config the SHA256 peripheral according to PAD and INI Mode.
 *
 * @param     SHA256Config:
 *
 * @retval    None
 */
LOCAL_INLINE FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_Sha256Process(VAR(uint8, AUTOMATIC) blkn, P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) inBuffer, 
                        VAR(uint8, AUTOMATIC) lenBuffer, P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) outBuffer, 
                        P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) ivBuffer,VAR(Crypto_Sha256_ModeType, AUTOMATIC) mode)
{
    VAR(uint64, AUTOMATIC) len = 0;
    VAR(uint32, AUTOMATIC) data = 0;
    VAR(uint32, AUTOMATIC) tmp = 0;
    VAR(uint8, AUTOMATIC) rem = 0;
    Crypto_Cse_ErrorCodeType status = CSE_ERC_OK;
    VAR(uint8, AUTOMATIC) m = 0;
    VAR(uint32, AUTOMATIC) idx = 0;
    VAR(uint32, AUTOMATIC) ivWord = 0;

    len = (uint64)(lenBuffer) << 3;
    
    if ((REG_READ32(SHA256_STATUS_REG_ADDR) & SHA256_STATUS_BUSY_MASK) != 0u)
    {
        /* do nothing */
    }
    else
    {
        switch(mode)
        {
            case MODE_PAD_INIT:
                REG_BIT_CLEAR32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_PAD_MODE_MASK);
                REG_BIT_CLEAR32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_INI_MODE_MASK);
                break;
            case MODE_PAD_NO_INIT:
                REG_BIT_CLEAR32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_PAD_MODE_MASK);
                REG_BIT_SET32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_INI_MODE_MASK);
                break;
            case MODE_NO_PAD_INIT:
                REG_BIT_SET32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_PAD_MODE_MASK);
                REG_BIT_CLEAR32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_INI_MODE_MASK);
                break;
            case MODE_NO_PAD_NO_INIT:
                REG_BIT_SET32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_PAD_MODE_MASK);
                REG_BIT_SET32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_INI_MODE_MASK);
                break;
            default:
                REG_BIT_CLEAR32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_PAD_MODE_MASK);
                REG_BIT_CLEAR32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_INI_MODE_MASK);
                break;
        }
        
        REG_BIT_SET32(SHA256_CTRL_REG_ADDR, CSE_HASH_CTRL_TYPE_SHA256);

        REG_WRITE32(SHA256_BLKN_REG_ADDR, blkn);
        REG_WRITE32(SHA256_DILH_REG_ADDR, (uint32_t)(len >> 32));
        REG_WRITE32(SHA256_DILL_REG_ADDR, (uint32_t)len);

        for (m = 0u; (m + 4u) <= lenBuffer; m += 4u)
        {
            tmp = 0;
            tmp |= (uint32_t)inBuffer[m];
            tmp |= (uint32_t)inBuffer[m + 1u] << 8u;
            tmp |= (uint32_t)inBuffer[m + 2u] << 16u;
            tmp |= (uint32_t)inBuffer[m + 3u] << 24u;
            REG_WRITE32(SHA256_DIN_REG_ADDR, tmp);
        }

        rem = lenBuffer % 4u;
        if (rem != 0u)
        {
            data = 0;
            for (idx = 0u; idx < rem; idx++)
            {
                data |= (uint32_t)inBuffer[m + idx] << (8u * idx);
            }
            REG_WRITE32(SHA256_DIN_REG_ADDR, data);
        }
        else
        {
            /* Nothing */
        }
        if ((ivBuffer != NULL_PTR) && ((mode == MODE_NO_PAD_NO_INIT) || (mode == MODE_PAD_NO_INIT)))
        {
            for (m = 0u; m < 32u; m += 4u)
            {
                ivWord = 0u;
                ivWord |= (uint32)ivBuffer[m];
                ivWord |= (uint32)ivBuffer[m + 1u] << 8u;
                ivWord |= (uint32)ivBuffer[m + 2u] << 16u;
                ivWord |= (uint32)ivBuffer[m + 3u] << 24u;
                REG_WRITE32(SHA256_DIGEST_REG_ADDR, ivWord);
            }
        }
        else
        {
            /* Nothing */
        }
        if (g_isAsyncFunction == (boolean)TRUE)
        {
            Crypto_Sha256_EnableInterrupt();
            REG_BIT_SET32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_OP_START_MASK);
        }
        else
        {
            REG_BIT_SET32(SHA256_CTRL_REG_ADDR, SHA256_CTRL_OP_START_MASK);
            if (Crypto_Sha256_WaitForCompute(CRYPTO_TIMEOUT_VALUE) == TRUE)
            {
                Crypto_Sha256_ReadDigest(outBuffer);
            }
            else
            {
                status = CSE_ERC_ERROR;
            }
        }
    }
    return status;
}

/*!
* @brief         Generate hash (256 bits).
*
* @param[in]     inBuffer     point to input data
* @param[in]     lenBuffer    input data length
* @param[in]     outBuffer    point to output data
* @param[out]    None
* @param[in,out] None
*
* @note          Non-AUTOSAR support function
* @retval        retResult: CSE_ERC_OK,CSE_ERC_ERROR
*
*/
LOCAL_INLINE FUNC(Crypto_Cse_ErrorCodeType, CRYPTO_CODE) Crypto_Cse_StartGenerateHash(
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) inBuffer, 
    VAR(uint32, AUTOMATIC) lenBuffer, 
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) outBuffer)
{
    VAR(Crypto_Cse_ErrorCodeType, AUTOMATIC) error = CSE_ERC_ERROR;
    VAR(uint32, AUTOMATIC) dataLength = lenBuffer;
    VAR(uint32, AUTOMATIC) remaining = 0;
    VAR(uint8, AUTOMATIC) blkCnt = 1;
    VAR(uint8, AUTOMATIC) ivBuffer[32] = {0};
    VAR(uint8, AUTOMATIC) bufferCnt = 0;
    VAR(uint8, AUTOMATIC) chunkSize = 0;
    VAR(uint32, AUTOMATIC) offset = 0;
    if(dataLength > HASH_INPUTDATA_LENGTH_MAX)
    {
        error = CSE_ERC_DATA_LENGTH;
    }
    else
    {
        if(dataLength <= HASH_ONEBLOCK_USED)
        {
            if (g_isAsyncFunction == (boolean)TRUE)
            {
                g_cseCmdState.numberOfBlkn = 0;
            }
            else
            {
                /* Nothing */
            }
            error = Crypto_Cse_Sha256Process(blkCnt, inBuffer, (uint8)dataLength, outBuffer,NULL_PTR,MODE_PAD_INIT);
        }
        else
        {
            offset = 0;
            if (g_isAsyncFunction == (boolean)TRUE)
            {
                if(dataLength >= HASH_ONEBLOCK_SIZE)
                {
                    chunkSize = HASH_ONEBLOCK_SIZE;
                    error = Crypto_Cse_Sha256Process(blkCnt, inBuffer, chunkSize, outBuffer,ivBuffer,MODE_NO_PAD_INIT);
                }
                else
                {
                    chunkSize = (uint8)dataLength;
                    error = Crypto_Cse_Sha256Process(blkCnt, inBuffer, chunkSize, outBuffer,ivBuffer,MODE_PAD_INIT);
                }

                g_cseCmdState.numberOfBlkn -= 1u;
                g_cseCmdState.dataLength = dataLength - chunkSize;
                g_cseCmdState.location = blkCnt;
                
            }
            else
            {
                while (offset < dataLength) 
                {
                    remaining = (uint32)(dataLength - offset);

                    if (remaining >= HASH_ONEBLOCK_SIZE)
                    {
                        chunkSize = HASH_ONEBLOCK_SIZE;
                        if( 0u == offset )
                        {
                            error = Crypto_Cse_Sha256Process(blkCnt, inBuffer, chunkSize, outBuffer, ivBuffer, MODE_NO_PAD_INIT);
                        }
                        else
                        {
                            error = Crypto_Cse_Sha256Process(blkCnt, &inBuffer[offset], chunkSize, outBuffer, ivBuffer, MODE_NO_PAD_NO_INIT);
                        }
                    }
                    else
                    {
                        chunkSize = (uint8)remaining;
                        if( 0u == offset )
                        {
                            error = Crypto_Cse_Sha256Process(blkCnt, inBuffer, chunkSize, outBuffer, ivBuffer, MODE_PAD_INIT);
                        }
                        else
                        {
                            error = Crypto_Cse_Sha256Process(blkCnt, &inBuffer[offset], chunkSize, outBuffer, ivBuffer, MODE_PAD_NO_INIT);
                        }
                    }
                    
                    if(error != CSE_ERC_OK)
                    {
                        break;
                    }
                    else
                    {
                        for(bufferCnt = 0u; bufferCnt < 32u; bufferCnt++)
                        {
                            ivBuffer[bufferCnt] = outBuffer[bufferCnt];
                        }
                        offset += chunkSize;
                        blkCnt = (uint8)((offset/HASH_ONEBLOCK_SIZE) + 1u);
                    }
                }
            }
        }
    }
    return error;
}

LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_ContinueGenerateHash (void)
{
    VAR(Crypto_Cse_ErrorCodeType, AUTOMATIC) error = CSE_ERC_ERROR;

    VAR(uint32, AUTOMATIC) blkCnt = 1;
    VAR(uint32, AUTOMATIC) currentDataAddr = 0;
    VAR(uint8, AUTOMATIC) ivBuffer[32] = {0};
    VAR(uint8, AUTOMATIC) bufferCnt = 0;
    VAR(uint8, AUTOMATIC) chunkSize = 0;
    if (CSE_IDLE == g_cseState)
    {
        g_cseCmdState.response = CSE_ERC_CANCELED;
    }
    else
    {
        g_cseCmdState.response = CSE_ERC_OK;
        Crypto_Sha256_ReadDigest(g_cseCmdState.outputData);
    }
    if (CSE_ERC_OK != g_cseCmdState.response)
    {
        if (g_isAsyncFunction != (boolean)FALSE)
        {
            Crypto_Sha256_ClearStatusFlag();
            Crypto_Sha256_DisableInterrupt();
            g_cseState = CSE_IDLE;
            Crypto_Impl_CallBackNotification(g_cseCmdState.response);
            g_isAsyncFunction = (boolean)FALSE;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        if (g_cseCmdState.numberOfBlkn <= 0u)
        {
            if (g_isAsyncFunction != (boolean)FALSE)
            {
                Crypto_Sha256_ClearStatusFlag();
                Crypto_Sha256_DisableInterrupt();
                Crypto_Impl_CallBackNotification(g_cseCmdState.response);
                g_isAsyncFunction = (boolean)FALSE;
                g_cseState = CSE_IDLE;
            }
            else
            {
                /* nothing */
            }
        }
        else
        {
            for(bufferCnt = 0u; bufferCnt < 32u; bufferCnt++)
            {
                ivBuffer[bufferCnt] = g_cseCmdState.outputData[bufferCnt];
            }
            
            blkCnt = g_cseCmdState.location;
            g_cseCmdState.location++;
            g_cseCmdState.numberOfBlkn -= 1u;
            currentDataAddr = blkCnt * HASH_ONEBLOCK_SIZE;
            if(g_cseCmdState.dataLength >= HASH_ONEBLOCK_SIZE)
            {
                chunkSize = HASH_ONEBLOCK_SIZE;
                g_cseCmdState.dataLength -= HASH_ONEBLOCK_SIZE;
                error = Crypto_Cse_Sha256Process((uint8)(blkCnt + 1u), &g_cseCmdState.inputData[currentDataAddr], chunkSize, g_cseCmdState.outputData,ivBuffer,MODE_NO_PAD_NO_INIT);
            }
            else
            {
                chunkSize = (uint8)g_cseCmdState.dataLength;
                if(chunkSize != (uint8)0)
                {
                    error = Crypto_Cse_Sha256Process((uint8)(blkCnt + 1u), &g_cseCmdState.inputData[currentDataAddr], chunkSize, g_cseCmdState.outputData,ivBuffer,MODE_PAD_NO_INIT);
                }
                else
                {
                    /* Nothing */
                }
            }
            g_cseCmdState.response = error;
        }
    }
}

/*!
* @brief    Continue AES-128 encryption or decryption in CBC/CTR/ECB mode
*/
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_ContinueEncryptDecrypt(void)
{
    VAR(uint32, AUTOMATIC) dataIdx = 0;
    VAR(uint32, AUTOMATIC) outputAddr = (uint32)g_cseCmdState.outputData;
    
    if (CSE_IDLE == g_cseState)
    {
        g_cseCmdState.response = CSE_ERC_CANCELED;
    }
    else
    {
        if(Crypto_Aes256_ExpandInterruptStatus() != 0u)
        {
            Crypto_Aes256_EnableKeyExpandInterrupt(FALSE);
            Crypto_Aes256_ClearStatus();
            Crypto_Aes256_modeSet(AES256_ALGODIR_DECRYPT);
            Crypto_Aes256_BlockProcessAsync(g_cseCmdState.numberOfBlkn, g_cseCmdState.dataLength, g_cseCmdState.inputData);
        }
        else if ((g_cseCmdState.location + 1u) >= g_cseCmdState.numberOfBlkn)
        {
            g_cseState = CSE_IDLE;
            for (dataIdx = 0u; dataIdx < 4u; dataIdx++)
            {
                *((uint32*)(outputAddr + ((g_cseCmdState.numberOfBlkn - 1u) * 16u) + (dataIdx * 4u))) = REG_READ32(AES_DATAOUT_REG_ADDR(dataIdx));
            }
            if (g_isAsyncFunction != (boolean)FALSE)
            {
                Crypto_Aes256_EnableInterrupt(FALSE);
                Crypto_Aes256_ClearStatus();
                Crypto_Impl_CallBackNotification(g_cseCmdState.response);
                g_isAsyncFunction = (boolean)FALSE;
            }
            else
            {
                /* nothing */
            }
        }
        else
        {    
            for (dataIdx = 0u; dataIdx < 4u; dataIdx++)
            {
                *((uint32*)(outputAddr + (g_cseCmdState.location * 16u) + (dataIdx * 4u))) = REG_READ32(AES_DATAOUT_REG_ADDR(dataIdx));
            }
            g_cseCmdState.location++;
            (void)Crypto_Aes256_BlockProcessContinueAsync(g_cseCmdState.location,g_cseCmdState.dataLength,
                    g_cseCmdState.numberOfBlkn, g_cseCmdState.inputData);
            
        }
    }
}

/*!
* @brief    Continue AES-128 MAC/Verify-MAC
*/
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_ContinueMac(void)
{
    VAR(uint32, AUTOMATIC) dataIdx = 0;
    VAR(uint32, AUTOMATIC) cmpDataNum = 0;
    VAR(uint8, AUTOMATIC) verificationStatus = 0;
    VAR(uint32, AUTOMATIC) outputAddr = (uint32)g_cseCmdState.outputData;
    
    if (CSE_IDLE == g_cseState)
    {
        g_cseCmdState.response = CSE_ERC_CANCELED;
    }
    else
    {
        if ((g_cseCmdState.location + 1u) > g_cseCmdState.numberOfBlkn)
        {
            g_cseState = CSE_IDLE;
            for (dataIdx = 0u; dataIdx < 4u; dataIdx++)
            {
                *((uint32*)(outputAddr + (dataIdx * 4u))) = REG_READ32(AES_DATAOUT_REG_ADDR(dataIdx));
            }

            if(NULL_PTR != g_cseCmdState.verifyPtr)
            {
                for (cmpDataNum = 0; cmpDataNum < g_cseCmdState.secondarydataLength; cmpDataNum++) 
                {
                    verificationStatus |= g_cseCmdState.secondaryInputData[cmpDataNum] ^ g_cseCmdState.outputData[cmpDataNum];
                }
                *(g_cseCmdState.verifyPtr) = (CSE_MAC_VERIFY_CORRECT == verificationStatus) ? CRYPTO_E_VER_OK : CRYPTO_E_VER_NOT_OK;
            } 
            else
            {
                /* Nothing */
            }
            if (g_isAsyncFunction != (boolean)FALSE)
            {
                Crypto_Aes256_EnableInterrupt(FALSE);
                Crypto_Aes256_ClearStatus();
                Crypto_Impl_CallBackNotification(g_cseCmdState.response);
                g_isAsyncFunction = (boolean)FALSE;
            }
            else
            {
                /* nothing */
            }
        }
        else
        {    
            g_cseCmdState.location++;
            (void)Crypto_Aes256_BlockProcessMacContinueAsync(g_cseCmdState.location,g_cseCmdState.dataLength,
                    g_cseCmdState.numberOfBlkn, g_cseCmdState.inputData);
        }
    }
}

/*!
* @brief    Continue AES-128 MPC
*/
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_ContinueMpc(void)
{
    VAR(uint32, AUTOMATIC) dataIdx = 0;
    VAR(uint32, AUTOMATIC) outputAddr = (uint32)g_cseCmdState.outputData;
    
    if (CSE_IDLE == g_cseState)
    {
        g_cseCmdState.response = CSE_ERC_CANCELED;
    }
    else
    {
        if ((g_cseCmdState.location + 2u) > g_cseCmdState.numberOfBlkn)
        {
            g_cseState = CSE_IDLE;
            for (dataIdx = 0u; dataIdx < 4u; dataIdx++)
            {
                *((uint32*)(outputAddr + (dataIdx * 4u))) = REG_READ32(AES_DATAOUT_REG_ADDR(dataIdx));
            }
            if (g_isAsyncFunction != (boolean)FALSE)
            {
                Crypto_Aes256_EnableInterrupt(FALSE);
                Crypto_Aes256_ClearStatus();
                Crypto_Impl_CallBackNotification(g_cseCmdState.response);
                g_isAsyncFunction = (boolean)FALSE;
            }
            else
            {
                /* nothing */
            }
        }
        else
        {    
            g_cseCmdState.location++;
            (void)Crypto_Aes256_BlockProcessContinueAsync(g_cseCmdState.location,g_cseCmdState.dataLength,
                    g_cseCmdState.numberOfBlkn, g_cseCmdState.inputData);
        }
    }
}

#define CRYPTO_STOP_SEC_CODE
#include "Crypto_MemMap.h"

/**@} end of group CRYPTO_Fuctions */
#ifdef __cplusplus
}
#endif
/**@} end of group CRYPTO_Driver */
/**@} end of group G32A10xx_StdPeriphDriver */

