/**
*   @file    Crypto_Cse.c
*
*   @version 1.0.0
*   @brief   AUTOSAR Crypto - Cryptographic Services Engine (CSE) functions
*   @details Contains functions for accessing CSE from the Crypto driver perspective
*
*   @addtogroup  Crypto
*   @{
*/
/*==================================================================================================
*   Project              : AUTOSAR 4.3 MCAL
*   Platform             : PA
*   Peripheral           : Crypto
*   Dependencies         : none
*
*   Autosar Version      : 4.3.1
*   Autosar Revision     : ASR_REL_4_3_REV_0001
*   Autosar Conf.Variant :
*   SW Version           : 1.0.0
*   Build Version        : MPC5777C_MCAL_1_0_0_RTM_ASR_REL_4_3_REV_0001_20190315
*
*   (c) Copyright 2006-2016 Freescale Semiconductor, Inc. 
*       Copyright 2017-2019 NXP
*   All Rights Reserved.
==================================================================================================*/
/*==================================================================================================
==================================================================================================*/

#ifdef __cplusplus
extern "C"{
#endif

/*==================================================================================================
*                                        INCLUDE FILES
* 1) system and project includes
* 2) needed interfaces from external units
* 3) internal and external interfaces from this unit
==================================================================================================*/
#include "Crypto.h"
#include "Crypto_Private.h"
#include "Crypto_Util.h"
#include "Crypto_Cse.h" 
#include "Crypto_Reg_eSys_Cse.h"
#include "StdRegMacros.h"

/*==================================================================================================
*                                       SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define CRYPTO_CSE_VENDOR_ID_C                     43
#define CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION_C      4
#define CRYPTO_CSE_AR_RELEASE_MINOR_VERSION_C      3
#define CRYPTO_CSE_AR_RELEASE_REVISION_VERSION_C   1
#define CRYPTO_CSE_SW_MAJOR_VERSION_C              1
#define CRYPTO_CSE_SW_MINOR_VERSION_C              0
#define CRYPTO_CSE_SW_PATCH_VERSION_C              0

/*==================================================================================================
*                                      FILE VERSION CHECKS
==================================================================================================*/
/* Check if Crypto_Cse source file and Crypto header file are of the same vendor */
#if (CRYPTO_CSE_VENDOR_ID_C != CRYPTO_VENDOR_ID)
    #error "Crypto_Cse.c and Crypto.h have different vendor ids"
#endif

/* Check if Crypto_Cse source file and Crypto header file are of the same Autosar version */
#if ((CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION_C    != CRYPTO_AR_RELEASE_MAJOR_VERSION) || \
     (CRYPTO_CSE_AR_RELEASE_MINOR_VERSION_C    != CRYPTO_AR_RELEASE_MINOR_VERSION) || \
     (CRYPTO_CSE_AR_RELEASE_REVISION_VERSION_C != CRYPTO_AR_RELEASE_REVISION_VERSION) \
    )
    #error "AutoSar Version Numbers of Crypto_Cse.c and Crypto.h are different"
#endif

/* Check if Crypto_Cse source file and Crypto header file are of the same Software version */
#if ((CRYPTO_CSE_SW_MAJOR_VERSION_C != CRYPTO_SW_MAJOR_VERSION) || \
     (CRYPTO_CSE_SW_MINOR_VERSION_C != CRYPTO_SW_MINOR_VERSION) || \
     (CRYPTO_CSE_SW_PATCH_VERSION_C != CRYPTO_SW_PATCH_VERSION)    \
    )
    #error "Software Version Numbers of Crypto_Cse.c and Crypto.h are different"
#endif

/* Check if Crypto_Cse source file and Crypto private header file are of the same vendor */
#if (CRYPTO_CSE_VENDOR_ID_C != CRYPTO_VENDOR_ID_PRIVATE)
    #error "Crypto_Cse.c and Crypto_Private.h have different vendor ids"
#endif

/* Check if Crypto_Cse source file and Crypto private header file are of the same Autosar version */
#if ((CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION_C    != CRYPTO_AR_RELEASE_MAJOR_VERSION_PRIVATE) || \
     (CRYPTO_CSE_AR_RELEASE_MINOR_VERSION_C    != CRYPTO_AR_RELEASE_MINOR_VERSION_PRIVATE) || \
     (CRYPTO_CSE_AR_RELEASE_REVISION_VERSION_C != CRYPTO_AR_RELEASE_REVISION_VERSION_PRIVATE) \
    )
    #error "AutoSar Version Numbers of Crypto_Cse.c and Crypto_Private.h are different"
#endif

/* Check if Crypto_Cse source file and Crypto private header file are of the same Software version */
#if ((CRYPTO_CSE_SW_MAJOR_VERSION_C != CRYPTO_SW_MAJOR_VERSION_PRIVATE) || \
     (CRYPTO_CSE_SW_MINOR_VERSION_C != CRYPTO_SW_MINOR_VERSION_PRIVATE) || \
     (CRYPTO_CSE_SW_PATCH_VERSION_C != CRYPTO_SW_PATCH_VERSION_PRIVATE)    \
    )
    #error "Software Version Numbers of Crypto_Cse.c and Crypto_Private.h are different"
#endif

/* Check if Crypto_Cse source file and Crypto_Cse header file are of the same vendor */
#if (CRYPTO_CSE_VENDOR_ID_C != CRYPTO_CSE_VENDOR_ID)
    #error "Crypto_Cse.c and Crypto_Cse.h have different vendor ids"
#endif

/* Check if Crypto_Cse source file and Crypto_Cse header file are of the same Autosar version */
#if ((CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION_C    != CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION) || \
     (CRYPTO_CSE_AR_RELEASE_MINOR_VERSION_C    != CRYPTO_CSE_AR_RELEASE_MINOR_VERSION) || \
     (CRYPTO_CSE_AR_RELEASE_REVISION_VERSION_C != CRYPTO_CSE_AR_RELEASE_REVISION_VERSION) \
    )
    #error "AutoSar Version Numbers of Crypto_Cse.c and Crypto_Cse.h are different"
#endif

/* Check if Crypto_Cse source file and Crypto_Cse header file are of the same Software version */
#if ((CRYPTO_CSE_SW_MAJOR_VERSION_C != CRYPTO_CSE_SW_MAJOR_VERSION) || \
     (CRYPTO_CSE_SW_MINOR_VERSION_C != CRYPTO_CSE_SW_MINOR_VERSION) || \
     (CRYPTO_CSE_SW_PATCH_VERSION_C != CRYPTO_CSE_SW_PATCH_VERSION) \
    )
    #error "Software Version Numbers of Crypto_Cse.c and Crypto_Cse.h are different"
#endif

/* Check if Crypto_Cse source file and Crypto_Reg_eSys_Cse header file are of the same vendor */
#if (CRYPTO_CSE_VENDOR_ID_C != REG_ESYS_CSE_VENDOR_ID)
    #error "Crypto_Cse.c and Crypto_Reg_eSys_Cse.h have different vendor ids"
#endif

/* Check if Crypto_Cse source file and Crypto_Reg_eSys_Cse header file are of the same Autosar version */
#if ((CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION_C    != REG_ESYS_CSE_AR_RELEASE_MAJOR_VERSION) || \
     (CRYPTO_CSE_AR_RELEASE_MINOR_VERSION_C    != REG_ESYS_CSE_AR_RELEASE_MINOR_VERSION) || \
     (CRYPTO_CSE_AR_RELEASE_REVISION_VERSION_C != REG_ESYS_CSE_AR_RELEASE_REVISION_VERSION) \
    )
    #error "AutoSar Version Numbers of Crypto_Cse.c and Crypto_Reg_eSys_Cse.h are different"
#endif

/* Check if Crypto_Cse source file and Crypto_Reg_eSys_Cse header file are of the same Software version */
#if ((CRYPTO_CSE_SW_MAJOR_VERSION_C != REG_ESYS_CSE_SW_MAJOR_VERSION) || \
     (CRYPTO_CSE_SW_MINOR_VERSION_C != REG_ESYS_CSE_SW_MINOR_VERSION) || \
     (CRYPTO_CSE_SW_PATCH_VERSION_C != REG_ESYS_CSE_SW_PATCH_VERSION) \
    )
    #error "Software Version Numbers of Crypto_Cse.c and Crypto_Reg_eSys_Cse.h are different"
#endif

/* Check if Crypto_Cse source file and Crypto_Util header file are of the same vendor */
#if (CRYPTO_CSE_VENDOR_ID_C != CRYPTO_UTIL_VENDOR_ID)
    #error "Crypto_Cse.c and Crypto_Util.h have different vendor ids"
#endif

/* Check if Crypto_Cse source file and Crypto_Util header file are of the same Autosar version */
#if ((CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION_C    != CRYPTO_UTIL_AR_RELEASE_MAJOR_VERSION) || \
     (CRYPTO_CSE_AR_RELEASE_MINOR_VERSION_C    != CRYPTO_UTIL_AR_RELEASE_MINOR_VERSION) || \
     (CRYPTO_CSE_AR_RELEASE_REVISION_VERSION_C != CRYPTO_UTIL_AR_RELEASE_REVISION_VERSION) \
    )
    #error "AutoSar Version Numbers of Crypto_Cse.c and Crypto_Util.h are different"
#endif

/* Check if Crypto_Cse source file and Crypto_Util header file are of the same Software version */
#if ((CRYPTO_CSE_SW_MAJOR_VERSION_C != CRYPTO_UTIL_SW_MAJOR_VERSION) || \
     (CRYPTO_CSE_SW_MINOR_VERSION_C != CRYPTO_UTIL_SW_MINOR_VERSION) || \
     (CRYPTO_CSE_SW_PATCH_VERSION_C != CRYPTO_UTIL_SW_PATCH_VERSION)    \
    )
    #error "Software Version Numbers of Crypto_Cse.c and Crypto_Util.h are different"
#endif

#ifndef DISABLE_MCAL_INTERMODULE_ASR_CHECK
    /* Check if Crypto_Cse source file and StdRegMacros header file are of the same Autosar version */
    #if ((CRYPTO_CSE_AR_RELEASE_MAJOR_VERSION_C != STDREGMACROS_AR_RELEASE_MAJOR_VERSION) || \
         (CRYPTO_CSE_AR_RELEASE_MINOR_VERSION_C != STDREGMACROS_AR_RELEASE_MINOR_VERSION)    \
        )
        #error "AutoSar Version Numbers of Crypto_Cse.c and StdRegMacros.h are different"
    #endif
#endif

/*==================================================================================================
*                          LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
==================================================================================================*/

/*==================================================================================================
*                                       LOCAL MACROS
==================================================================================================*/
#define CRYPTO_CSE_CMAC_OUT_LEN_U32         ((uint32)0x10)
#define CRYPTO_CSE_SHA256_OUT_LEN_U32       ((uint32)0x20)
#define CRYPTO_CSE_MP_COMP_OUT_LEN_U32      ((uint32)0x10)
#define CRYPTO_CSE_SEED_LEN_U32             ((uint32)0x10)
#define CRYPTO_CSE_KEY_ID_MASK_U8           ((uint8)0x0FU)
#define CRYPTO_CSE_AES_BLOCK_SIZE_U32       ((uint32)0x10)

/*==================================================================================================
*                                      LOCAL CONSTANTS
==================================================================================================*/

/*==================================================================================================
*                                      LOCAL VARIABLES
==================================================================================================*/
#define CRYPTO_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Crypto_MemMap.h"

/* Variable storing the job that is currently processing */
static VAR (Crypto_JobType, AUTOMATIC) Crypto_JobInProgress;

#define CRYPTO_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Crypto_MemMap.h"


#define CRYPTO_START_SEC_VAR_NO_INIT_BOOLEAN
#include "Crypto_MemMap.h"

/* Flag to store status of CSE2 only support */
static VAR (boolean,AUTOMATIC) bCSE2OnlySupport;

#define CRYPTO_STOP_SEC_VAR_NO_INIT_BOOLEAN
#include "Crypto_MemMap.h"



#define CRYPTO_START_SEC_VAR_INIT_8_NO_CACHEABLE
#include "Crypto_MemMap.h"

static VAR(uint8, AUTOMATIC) u8aSeedResult[CRYPTO_CSE_SEED_LEN_U32] = {0};
static VAR(uint8, AUTOMATIC) u8aHashMacTemp[CRYPTO_CSE_SHA256_OUT_LEN_U32] = {0};

#define CRYPTO_STOP_SEC_VAR_INIT_8_NO_CACHEABLE
#include "Crypto_MemMap.h"

/*==================================================================================================
*                                      GLOBAL CONSTANTS
==================================================================================================*/

/*==================================================================================================
*                                      GLOBAL VARIABLES
==================================================================================================*/
#define CRYPTO_START_SEC_VAR_INIT_UNSPECIFIED
#include "Crypto_MemMap.h"

extern VAR(Crypto_DriverStateType, CRYPTO_VAR) Crypto_eDriverState;

#define CRYPTO_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Crypto_MemMap.h"


#define CRYPTO_START_SEC_VAR_INIT_BOOLEAN
#include "Crypto_MemMap.h"

extern VAR (boolean, CRYPTO_VAR) Crypto_Cse_bCommandInProgress;
extern VAR (boolean, CRYPTO_VAR) Crypto_Cse_bCommandInProgressIsAJob;

#define CRYPTO_STOP_SEC_VAR_INIT_BOOLEAN
#include "Crypto_MemMap.h"

/*==================================================================================================
*                                   LOCAL FUNCTION PROTOTYPES
==================================================================================================*/
#define CRYPTO_START_SEC_CODE
#include "Crypto_MemMap.h"

LOCAL_INLINE FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_VerifyCseResponse
(
    VAR (uint32, AUTOMATIC) u32Message
);

LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_FillVerifyPtr
(
    VAR(Std_ReturnType, AUTOMATIC) CseResponse
);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_ProcessOperation
(
    VAR  (uint32,         AUTOMATIC                  ) u32ObjectIdIdx,
    P2VAR(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
);

#if (STD_ON == CRYPTO_KEYS_EXIST)
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_MacGenerate 
(
    VAR     (uint32,            AUTOMATIC                  ) u32ObjectIdIdx, 
    P2CONST (Crypto_JobType,    AUTOMATIC, CRYPTO_APPL_DATA) pJob
);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_MacVerify 
(
    VAR     (uint32,         AUTOMATIC                  ) u32ObjectIdIdx, 
    P2CONST (Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_Encrypt 
(
    VAR     (uint32,        AUTOMATIC                  ) u32ObjectIdIdx, 
    P2CONST (Crypto_JobType,AUTOMATIC, CRYPTO_APPL_DATA) pJob
);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_Decrypt 
(
    VAR     (uint32,         AUTOMATIC                  ) u32ObjectIdIdx, 
    P2CONST (Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
);
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_Hash 
(
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
);
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_Random 
( 
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA ) pJob
);

/*==================================================================================================
*                                      LOCAL FUNCTIONS
==================================================================================================*/
#if (STD_ON == CRYPTO_KEYS_EXIST)

/**
* @brief           Generate Mac.
* @details         Calculate 128-bit MAC using AES CMAC algorithm.
*
* @param[inout]    pJob              Pointer to the job.
* @param[in]       u32ObjectIdIdx    Index of the object used.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_MacGenerate 
( 
    VAR     (uint32,         AUTOMATIC                  ) u32ObjectIdIdx, 
    P2CONST (Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
)
{
    VAR (uint32,                        AUTOMATIC) u32CryptoKeyIdIdx = Crypto_Util_GetKeyIdIdx (pJob->cryptoKeyId);
    VAR (Cse_ErrorCodeType,             AUTOMATIC) eStatus           = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;
    VAR (Std_ReturnType,                AUTOMATIC) RetVal            = (Std_ReturnType)E_NOT_OK;
    VAR (uint32,                        AUTOMATIC) u32ResultLen      = pJob->jobPrimitiveInfo->primitiveInfo->resultLength;
    VAR (uint32,                        AUTOMATIC) u32OutputLen      = *pJob->jobPrimitiveInputOutput.outputLengthPtr;
    VAR (Crypto_ProcessingType,         AUTOMATIC) eProcessingType   = pJob->jobPrimitiveInfo->processingType;
    VAR (Crypto_VerifyKeyElementIdType, AUTOMATIC) VerifyKeyMaterial;
    
    /* Ignore compiler warning for not used parameter */
    (void)u32ObjectIdIdx;
    
    VerifyKeyMaterial = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KEY_MATERIAL_U32);
    
    if ((Std_ReturnType)E_OK  == VerifyKeyMaterial.RetVal)
    {
        if ( u32OutputLen >= u32ResultLen )
        {      
            /* Fill the outputLengthPtr with the size of MAC. If job->jobPrimitiveInfo->primitiveInfo->service is set to CRYPTO_HASH or CRYPTO_MACGENERATE, the parameter job->jobPrimitiveInfo->primitiveInfo->resultLength is required.*/
            *pJob->jobPrimitiveInputOutput.outputLengthPtr = u32ResultLen;
            /* TODO - More elegant way to update input length from bytes to bits */
            /* pJob->jobPrimitiveInputOutput.inputLength = pJob->jobPrimitiveInputOutput.inputLength << 3; */

            eStatus = Crypto_Cse_SendCommandMacGenerate((Cse_KeyHandleType)Crypto_aKeyElementList[VerifyKeyMaterial.u32Counter]->u32CryptoKeyHandle,
                                         pJob->jobPrimitiveInputOutput.inputPtr,
                                         pJob->jobPrimitiveInputOutput.inputLength,
                                         u8aHashMacTemp,
                                         eProcessingType
                                       );
            if(CRYPTO_PROCESSING_SYNC == eProcessingType)
            {
                if (CSE_ERC_NO_ERROR == eStatus)
                {
                    if( u32ResultLen >= CRYPTO_CSE_CMAC_OUT_LEN_U32 )
                    {
                        Crypto_Util_Memcpy(u8aHashMacTemp, pJob->jobPrimitiveInputOutput.outputPtr, CRYPTO_CSE_CMAC_OUT_LEN_U32);
                    }
                    else
                    {
                        /** If result length is smaller than 
                        standard length output the most significant bits of the result 
                        shall be truncated to the configured result length*/
                        Crypto_Util_Memcpy(u8aHashMacTemp, pJob->jobPrimitiveInputOutput.outputPtr, u32ResultLen);
                    }
                }
            }
            RetVal = Crypto_Cse_VerifyCseResponse (eStatus);
        }
        else
        {
            RetVal = (Std_ReturnType)CRYPTO_E_SMALL_BUFFER;
        }
    }
    return RetVal;
}

/**
* @brief           Verify Mac.
* @details         Calculates the 128-bit MAC of a given message and compares it with the provided MAC of that message.
*
* @param[inout]    pJob              Pointer to the job.
* @param[in]       u32ObjectIdIdx    Index of the object used.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_MacVerify 
(
    VAR     (uint32,         AUTOMATIC                  ) u32ObjectIdIdx, 
    P2CONST (Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
)
{
    VAR (Cse_ErrorCodeType,             AUTOMATIC) eStatus           = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;
    VAR (uint32,                        AUTOMATIC) u32CryptoKeyIdIdx = Crypto_Util_GetKeyIdIdx (pJob->cryptoKeyId);
    VAR (Std_ReturnType,                AUTOMATIC) RetVal            = (Std_ReturnType)E_NOT_OK;
    VAR (Crypto_VerifyKeyElementIdType, AUTOMATIC) VerifyKeyMaterial;
    
    /* Ignore compiler warning for not used parameter */
    (void)u32ObjectIdIdx;

    VerifyKeyMaterial = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KEY_MATERIAL_U32);
    
    if ((Std_ReturnType)E_OK  == VerifyKeyMaterial.RetVal)
    {
        eStatus = Crypto_Cse_SendCommandMacVerify ((Cse_KeyHandleType)Crypto_aKeyElementList[VerifyKeyMaterial.u32Counter]->u32CryptoKeyHandle,
                                                    pJob->jobPrimitiveInputOutput.inputPtr, 
                                                    pJob->jobPrimitiveInputOutput.inputLength,
                                                    pJob->jobPrimitiveInputOutput.secondaryInputLength,
                                                    pJob->jobPrimitiveInputOutput.secondaryInputPtr,
                                                    pJob->jobPrimitiveInfo->processingType);
        if((Cse_ErrorCodeType)CSE_ERC_NO_ERROR == eStatus)
        {
            *(pJob->jobPrimitiveInputOutput.verifyPtr) = CRYPTO_E_VER_OK;   
        }
        else
        {
            *(pJob->jobPrimitiveInputOutput.verifyPtr) = CRYPTO_E_VER_NOT_OK;
        }
        RetVal = Crypto_Cse_VerifyCseResponse(eStatus);
    }
    
    return RetVal;
}

/**
* @brief           AES Encrypt.
* @details         Performs AES-128 encryption on n 128-bit blocks of data.
*
* @param[inout]    pJob              Pointer to the job.
* @param[in]       u32ObjectIdIdx    Index of the object used.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_Encrypt 
(
    VAR(uint32,             AUTOMATIC                  ) u32ObjectIdIdx, 
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
)
{
    VAR (Cse_ErrorCodeType,             AUTOMATIC) eStatus           = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;
    VAR (uint32,                        AUTOMATIC) u32CryptoKeyIdIdx = Crypto_Util_GetKeyIdIdx (pJob->cryptoKeyId);
    VAR (Std_ReturnType,                AUTOMATIC) RetVal            = (Std_ReturnType)E_NOT_OK;
    VAR (Crypto_VerifyKeyElementIdType, AUTOMATIC) VerifyKeyIV;
    VAR (Crypto_VerifyKeyElementIdType, AUTOMATIC) VerifyKeyMaterial;

    /* Ignore compiler warning for not used parameter */
    (void)u32ObjectIdIdx;

    VerifyKeyMaterial = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KEY_MATERIAL_U32);
    VerifyKeyIV       = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KE_CIPHER_IV);
    
    if ((Std_ReturnType)E_OK  == VerifyKeyMaterial.RetVal)
    {
        if(*pJob->jobPrimitiveInputOutput.outputLengthPtr >= Crypto_Cse_Get128BitBuffBlockCount(pJob->jobPrimitiveInputOutput.inputLength) * CRYPTO_CSE_AES_BLOCK_SIZE_U32)
        {
            /* Fill the outputLengthPtr with the size of the inputPtr only if outputLengthPtr is greater or equal to the size of the expected result (which is equal to the inputLength)  */
            if ( *pJob->jobPrimitiveInputOutput.outputLengthPtr >= pJob->jobPrimitiveInputOutput.inputLength)
            {
                *pJob->jobPrimitiveInputOutput.outputLengthPtr = pJob->jobPrimitiveInputOutput.inputLength;

                switch (pJob->jobPrimitiveInfo->primitiveInfo->algorithm.mode)
                {
                    case CRYPTO_ALGOMODE_ECB:
                        eStatus = Crypto_Cse_SendCommandEcbEncrypt((Cse_KeyHandleType)Crypto_aKeyElementList[VerifyKeyMaterial.u32Counter]->u32CryptoKeyHandle,
                                                                    pJob->jobPrimitiveInputOutput.inputPtr, 
                                                                    pJob->jobPrimitiveInputOutput.inputLength,
                                                                    pJob->jobPrimitiveInputOutput.outputPtr,
                                                                    pJob->jobPrimitiveInfo->processingType
                                                                   );
                        break;

                    case CRYPTO_ALGOMODE_CBC:
                        if ( ( (Std_ReturnType)E_OK  == VerifyKeyIV.RetVal ) )
                        {
                            eStatus = Crypto_Cse_SendCommandCbcEncrypt((Cse_KeyHandleType)Crypto_aKeyElementList[VerifyKeyMaterial.u32Counter]->u32CryptoKeyHandle,
                                                                       pJob->jobPrimitiveInputOutput.inputPtr,
                                                                       pJob->jobPrimitiveInputOutput.inputLength, 
                                                                       Crypto_aKeyElementList[VerifyKeyIV.u32Counter]->pCryptoElementArray,
                                                                       pJob->jobPrimitiveInputOutput.outputPtr,
                                                                       pJob->jobPrimitiveInfo->processingType
                                                                      );
                        }
                        break;
                    default:
                        eStatus = CSE_ERC_INVALID_CMD;
                        break;
                }
                RetVal = Crypto_Cse_VerifyCseResponse(eStatus);
            }
        }
        else
        {
            RetVal = (Std_ReturnType)CRYPTO_E_SMALL_BUFFER;
        }
    }
    return RetVal;
}

/**
* @brief           AES Dencrypt.
* @details         Performs AES-128 decryption on n 128-bit blocks of data.
*
* @param[inout]    pJob              Pointer to the job.
* @param[in]       u32ObjectIdIdx    Index of the object used.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_Decrypt 
(
    VAR    (uint32,         AUTOMATIC                  ) u32ObjectIdIdx, 
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
)
{
    VAR (Cse_ErrorCodeType,             AUTOMATIC) eStatus           = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;
    VAR (uint32,                        AUTOMATIC) u32CryptoKeyIdIdx = Crypto_Util_GetKeyIdIdx (pJob->cryptoKeyId);
    VAR (Std_ReturnType,                AUTOMATIC) RetVal            = (Std_ReturnType)E_NOT_OK;
    VAR (Crypto_VerifyKeyElementIdType, AUTOMATIC) VerifyKeyIV;
    VAR (Crypto_VerifyKeyElementIdType, AUTOMATIC) VerifyKeyMaterial;

    /* Ignore compiler warning for not used parameter */
    (void)u32ObjectIdIdx;

    VerifyKeyMaterial = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KEY_MATERIAL_U32);
    VerifyKeyIV       = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KE_CIPHER_IV);

    if ((Std_ReturnType)E_OK  == VerifyKeyMaterial.RetVal)
    {
        if(*pJob->jobPrimitiveInputOutput.outputLengthPtr >= Crypto_Cse_Get128BitBuffBlockCount(pJob->jobPrimitiveInputOutput.inputLength) * CRYPTO_CSE_AES_BLOCK_SIZE_U32)
        {
            /* Fill the outputLengthPtr with the size of the inputPtr only if outputLengthPtr is greater or equal to the size of the expected result (which is equal to the inputLength)  */
            if ( *pJob->jobPrimitiveInputOutput.outputLengthPtr >= pJob->jobPrimitiveInputOutput.inputLength)
            {
                *pJob->jobPrimitiveInputOutput.outputLengthPtr = pJob->jobPrimitiveInputOutput.inputLength;
                switch (pJob->jobPrimitiveInfo->primitiveInfo->algorithm.mode)
                {
                    case CRYPTO_ALGOMODE_ECB:
                        eStatus = Crypto_Cse_SendCommandEcbDecrypt((Cse_KeyHandleType)Crypto_aKeyElementList[VerifyKeyMaterial.u32Counter]->u32CryptoKeyHandle,
                                                                    pJob->jobPrimitiveInputOutput.inputPtr, 
                                                                    pJob->jobPrimitiveInputOutput.inputLength, 
                                                                    pJob->jobPrimitiveInputOutput.outputPtr, 
                                                                    pJob->jobPrimitiveInfo->processingType
                                                                  );
                        break;
                        
                    case CRYPTO_ALGOMODE_CBC:
                        if ( ( (Std_ReturnType)E_OK  == VerifyKeyIV.RetVal ) )
                        {
                            eStatus = Crypto_Cse_SendCommandCbcDecrypt((Cse_KeyHandleType)Crypto_aKeyElementList[VerifyKeyMaterial.u32Counter]->u32CryptoKeyHandle,
                                                                        pJob->jobPrimitiveInputOutput.inputPtr, 
                                                                        pJob->jobPrimitiveInputOutput.inputLength,
                                                                        Crypto_aKeyElementList[VerifyKeyIV.u32Counter]->pCryptoElementArray,
                                                                        pJob->jobPrimitiveInputOutput.outputPtr,
                                                                        pJob->jobPrimitiveInfo->processingType
                                                                      );
                        }
                        break;
                     default:
                        eStatus = CSE_ERC_INVALID_CMD;
                        break;
                }
                RetVal = Crypto_Cse_VerifyCseResponse(eStatus);
            }
        }
        else
        {
            RetVal = (Std_ReturnType)CRYPTO_E_SMALL_BUFFER;
        }
    }
    
    return RetVal;
}

/**
* @brief           Hash.
* @details         Generates the hash over the input message.
*
* @param[inout]    pJob: Pointer to the job.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_Hash 
(
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
)
{
    VAR(Std_ReturnType,         AUTOMATIC) RetVal          = (Std_ReturnType)E_NOT_OK;
    VAR(uint32,                 AUTOMATIC) u32OutputLen    = *pJob->jobPrimitiveInputOutput.outputLengthPtr;
    VAR(uint32,                 AUTOMATIC) u32ResultLen    = pJob->jobPrimitiveInfo->primitiveInfo->resultLength;
    VAR(uint64,                 AUTOMATIC) u64InputLength  = pJob->jobPrimitiveInputOutput.inputLength;
    VAR (Crypto_ProcessingType, AUTOMATIC) eProcessingType = pJob->jobPrimitiveInfo->processingType;
    
    if(u32OutputLen >= u32ResultLen)
    {
        *pJob->jobPrimitiveInputOutput.outputLengthPtr = u32ResultLen;
        
        switch (pJob->jobPrimitiveInfo->primitiveInfo->algorithm.mode)
        {
            /* SHA-256 HTA */
            case CRYPTO_ALGOMODE_RSASSA_PKCS1_v1_5:
                    RetVal = Crypto_Cse_SHA256(pJob->jobPrimitiveInputOutput.inputPtr, 
                                               &u64InputLength,
                                               u8aHashMacTemp,
                                               eProcessingType);
                    if(CRYPTO_PROCESSING_SYNC == eProcessingType)
                    {
                        if ((Std_ReturnType)E_OK == RetVal)
                        {
                            if ( u32ResultLen >= CRYPTO_CSE_SHA256_OUT_LEN_U32 )
                            {
                                Crypto_Util_Memcpy(u8aHashMacTemp, pJob->jobPrimitiveInputOutput.outputPtr, CRYPTO_CSE_SHA256_OUT_LEN_U32);
                            }
                            else
                            {
                                /** If result length is smaller than 
                                standard length output the most significant bits of the result 
                                shall be truncated to the configured result length*/
                                Crypto_Util_Memcpy(u8aHashMacTemp, pJob->jobPrimitiveInputOutput.outputPtr, u32ResultLen);
                            }
                        }
                    }
                break;

            /* MP compression */
            case CRYPTO_ALGOMODE_ECB:
                RetVal = Crypto_Cse_MPCompression (pJob->jobPrimitiveInputOutput.inputPtr, 
                                                   &u64InputLength,
                                                   u8aHashMacTemp,
                                                   eProcessingType);
                if(CRYPTO_PROCESSING_SYNC == eProcessingType)
                {
                    if ((Std_ReturnType)E_OK == RetVal)
                    {
                        if ( u32ResultLen >= CRYPTO_CSE_MP_COMP_OUT_LEN_U32 )
                        {
                            Crypto_Util_Memcpy(u8aHashMacTemp, pJob->jobPrimitiveInputOutput.outputPtr, CRYPTO_CSE_MP_COMP_OUT_LEN_U32);
                        }
                        else
                        {
                            /** If result length is smaller than 
                            standard length output the most significant bits of the result 
                            shall be truncated to the configured result length*/
                            Crypto_Util_Memcpy(u8aHashMacTemp, pJob->jobPrimitiveInputOutput.outputPtr, u32ResultLen);
                        }
                    }
                }
                break;

             default:
                RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
                break;
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_SMALL_BUFFER;
    }

    return RetVal;
}

#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */

/**
* @brief           AES Random.
* @details         The function returns a vector of 128 random bits.
*
* @param[in]       pJob    Pointer to the job.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_Random 
(
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
)
{
    VAR(Std_ReturnType,    AUTOMATIC) RetVal = (Std_ReturnType)E_NOT_OK;
    VAR(Cse_ErrorCodeType, AUTOMATIC) eStatus;

    if(*pJob->jobPrimitiveInputOutput.outputLengthPtr >= CRYPTO_CSE_AES_BLOCK_SIZE_U32)
    {
        eStatus = Crypto_Cse_SendCommandGenerateRnd (pJob->jobPrimitiveInputOutput.outputPtr);
        RetVal  = Crypto_Cse_VerifyCseResponse (eStatus);
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_SMALL_BUFFER;
    }
    
    return RetVal;
}

/**
* @brief           Verify the return of the HW.
* @details         Verify the return of the HW to match with error code of Crypto driver.
*
* @param[in]       u32Message    The return of HW.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
LOCAL_INLINE FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_VerifyCseResponse
(
    VAR (uint32, AUTOMATIC) u32Message
)
{
    VAR (Cse_ErrorCodeType, AUTOMATIC) eCseErrorCode = (Cse_ErrorCodeType)u32Message;
    VAR (Std_ReturnType,    AUTOMATIC) RetVal;
    
    switch (eCseErrorCode)
    {
        /* CSE command successfully executed with no error. */
        case CSE_ERC_NO_ERROR:
            RetVal = (Std_ReturnType)E_OK;
            break;  

        case CSE_ERC_SEQUENCE_ERROR:    /* Command issued before the SHE_DEBUG_CHAL command */ 
        case CSE_ERC_KEY_EMPTY:         /* Specified key slot is empty */ 
        case CSE_ERC_NO_SECURE_BOOT:    /* 1. SECURE_BOOT issued when secure boot is disabled or the BOOT_MAC_KEY slot is empty; 2. BOOT_FAIL or BOOT_OK issued */ 
        case CSE_ERC_KEY_UPDATE_ERROR:  /* RND, EXTEND_SEED or DEBUG_CHAL command issued before the INIT_RNG command */
        case CSE_ERC_RNG_SEED:          /* DEBUG_AUTH command issued with invalid MAC value. */
        case CSE_ERC_NO_DEBUGGING: 
        case CSE_ERC_SYSTEM_MEMMORY:
        case CSE_ERC_INVALID_CMD:
        case CSE_ERC_TRNG:
        case CSE_ERC_FLASH_BLOCK:
        case CSE_ERC_INTERNAL_CMD_PROCESSOR:
        case CSE_ERC_LENGTH:
        case CSE_ERC_MEMORY_FAILURE: /* An internal memory error was encountered while executing the command */
        case CSE_ERC_GENERAL_ERROR: 
            RetVal = (Std_ReturnType)E_NOT_OK;
            break;
        
        /* The service request failed because read access was denied */        
        case CSE_ERC_KEY_WRITE_PROTECTED:
            RetVal = (Std_ReturnType)CRYPTO_E_KEY_WRITE_FAIL;
            break;

        /* This error code is returned if a key is locked due to failed boot measurement or an active debugger. */        
        case CSE_ERC_KEY_NOT_AVAILABLE:
            RetVal = (Std_ReturnType)CRYPTO_E_KEY_NOT_AVAILABLE;
            break;

        /* Specified key slot is either not valid or not available due to a key usage flags restrictions. */        
        case CSE_ERC_KEY_INVALID:
            RetVal = (Std_ReturnType)CRYPTO_E_KEY_NOT_VALID;
            break;

        /* HSM request issued when the HSM is in busy state (on that HSM Host) . */        
        case CSE_ERC_BUSY:
            RetVal = (Std_ReturnType)CRYPTO_E_BUSY;
            break;
        
        /* The service request failed because CSE still busy and counter timeout occurred */
        case CSE_CMD_TIMEOUT:
            RetVal = (Std_ReturnType)CRYPTO_E_OPERATION_TIMEOUT;
            break;
        
        /* The service is not supported */
        case CSE_ERC_NOT_SUPPORTED:
            RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
            break;
        default:
            /* Should not get here */
            RetVal = (Std_ReturnType)E_NOT_OK;
            break;
    }
    
    return RetVal;
}

/**
* @brief           Fills the verifyPtr for MAC verification jobs.
* @details         Fills the verifyPtr (E_OK or E_NOT_OK) for MAC verification jobs. This function is needed because the CSE descriptors do not provide such field (verifyPtr).
*
* @param[in]       CseResponse    Response received from CSE.
*
* @return          Result of the operation.
*                   Void.
*
* @api
*
* @pre            Driver must be initialized.
*
*/
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_Cse_FillVerifyPtr
(
    VAR(Std_ReturnType, AUTOMATIC) CseResponse
)
{
    VAR(Crypto_ServiceInfoType, AUTOMATIC) eCryptoService = Crypto_JobInProgress.jobPrimitiveInfo->primitiveInfo->service;
    if ( 
        ( MAC_VERIFY   == eCryptoService ) || \
        ( AEAD_DECRYPT == eCryptoService )
       )
    {
        if ( (Std_ReturnType)E_OK == CseResponse )
        {
            *(Crypto_JobInProgress).jobPrimitiveInputOutput.verifyPtr = CRYPTO_E_VER_OK;
        }
        else
        {
            *(Crypto_JobInProgress).jobPrimitiveInputOutput.verifyPtr = CRYPTO_E_VER_NOT_OK;
        }
    }
}
/**
* @brief           Processes a job.
* @details         Tries to initiate a request to CSE to process a job.
*
* @param[in]       u32ObjectIdIdx    Index of the object used.
* @param[inout]    pJob              Pointer to the job to be processed.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_ProcessOperation
(
    VAR  (uint32,         AUTOMATIC                  ) u32ObjectIdIdx,
    P2VAR(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
)
{
    VAR  (Std_ReturnType, AUTOMATIC) RetVal = (Std_ReturnType)E_NOT_OK;

    /* Check if CSE is not busy processing a request */
    if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
    {
        /* Copy the job to the Crypto_JobInProgress, as the job can be asynchronous */
        Crypto_Util_JobTypeMemcpy (pJob, &Crypto_JobInProgress);
        /* Mark the current command sent to CSE as being a job process request */
        Crypto_Cse_bCommandInProgressIsAJob = (boolean)TRUE;
        
        switch (pJob->jobPrimitiveInfo->primitiveInfo->service)
        {
            case CRYPTO_MACGENERATE: 
#if (STD_ON == CRYPTO_KEYS_EXIST)
                RetVal = Crypto_Cse_MacGenerate (u32ObjectIdIdx, pJob);
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */
                break;    
            case CRYPTO_MACVERIFY:
#if (STD_ON == CRYPTO_KEYS_EXIST)
                RetVal = Crypto_Cse_MacVerify (u32ObjectIdIdx, pJob);
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */
                break;
                
            case CRYPTO_ENCRYPT:
#if (STD_ON == CRYPTO_KEYS_EXIST)
                RetVal = Crypto_Cse_Encrypt (u32ObjectIdIdx, pJob);
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */
                break;
                
            case CRYPTO_DECRYPT:
#if (STD_ON == CRYPTO_KEYS_EXIST)
                RetVal = Crypto_Cse_Decrypt (u32ObjectIdIdx, pJob);
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */
                break;

            case CRYPTO_HASH:
#if (STD_ON == CRYPTO_KEYS_EXIST)
                RetVal = Crypto_Cse_Hash (pJob);
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */
                break;
                
            case CRYPTO_RANDOMGENERATE:
                RetVal = Crypto_Cse_Random (pJob);
                break;
                
            default:
                /* Do nothing, RetVal is already E_NOT_OK */
                break;
        }
    }
    else 
    {
        /* No free Cse channel was found */
        RetVal = (Std_ReturnType)CRYPTO_E_BUSY;
    }
    return RetVal;
}


/*==================================================================================================
*                                       GLOBAL FUNCTIONS
==================================================================================================*/
/**
* @brief           Miyaguchi-Preneel Compression.
* @details         One-way compression function used to derive a 128-bit output from a given message.
*
* @param[in]       pInputKey         Message start address.
* @param[in]       pInputKeyLen      Message length (bytes) address.
* @param[out]      pResult           Output address.
* @param[in]       eJobProcessing    The processing type used.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_MPCompression 
(
    P2CONST(uint8,                 AUTOMATIC, CRYPTO_APPL_CONST) pInputKey, 
    P2VAR  (uint64,                AUTOMATIC, CRYPTO_APPL_DATA ) pInputKeyLen,
    P2VAR  (uint8,                 AUTOMATIC, CRYPTO_APPL_DATA ) pResult,
    VAR    (Crypto_ProcessingType, AUTOMATIC                   ) eJobProcessing
)
{
    VAR  (Cse_ErrorCodeType,AUTOMATIC) eStatus = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR; 
    VAR  (Std_ReturnType,   AUTOMATIC) RetVal  = (Std_ReturnType)E_NOT_OK;
    
    if ((boolean)TRUE == bCSE2OnlySupport)
    {
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            eStatus = Crypto_Cse_SendCommandMPCompression(pInputKey,pInputKeyLen,pResult,eJobProcessing);
        }
        else
        {
            eStatus = (Cse_ErrorCodeType)CSE_ERC_BUSY;
        }

        /** @violates @ref Crypto_Ipw_c_REF_5 Violates MISRA 2004 Required Rule 10.1, the value of an expression of integer is converted to a different underlying type */
        RetVal = Crypto_Cse_VerifyCseResponse ((Cse_ErrorCodeType)eStatus);
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }

    return RetVal;
}

/**
* @brief           Configure Secure Counter.
* @details         Using the provided ID and Rollover Value CSE will associate a secure counter with the given id and set its Rollover Value.
*                  A status will be returned after the execution of the command to inform if a new counter is used or an existing one is reused.
*
* @param[in]       u32CounterId        The id of the secure counter.
* @param[in]       u32RolloverValue    Defines the secure counter value at which point the RP is stored in flash memory.
* @param[out]      pStatus             Informs if a new secure counter is used.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*                   
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_CfgSecCounter
(
    VAR(uint32,   AUTOMATIC                  ) u32CounterId,
    VAR(uint32,   AUTOMATIC                  ) u32RolloverValue,
    P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) pStatus
)
{
    VAR  (Std_ReturnType,   AUTOMATIC) RetVal = (Std_ReturnType)E_NOT_OK;
#if (STD_ON == CRYPTO_KEYS_EXIST)
    VAR  (Cse_ErrorCodeType,AUTOMATIC) eStatus      = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;

    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            eStatus = Crypto_Cse_SendCommandCfgSecCounter((Cse_CounterId)u32CounterId, u32RolloverValue, pStatus);
        }
        else
        {
            eStatus = (Cse_ErrorCodeType)CSE_ERC_BUSY;
        }

        /** @violates @ref Crypto_Ipw_c_REF_5 Violates MISRA 2004 Required Rule 10.1, the value of an expression of integer is converted to a different underlying type */
        RetVal = Crypto_Cse_VerifyCseResponse ((Cse_ErrorCodeType)eStatus);
    }
    else 
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }
#else
    (void)u32CounterId;
    (void)u32RolloverValue;
    (void)pStatus;
#endif

    return RetVal;
}

/**
* @brief            CMAC Generation with Secure Counter.
* @details          Calculates the MAC of a given input message concatenated with the incremented value of the selected secure counter, using the parameters provided.
*
* @param[in]    u32KeyId            KeyID used to perform the cryptographic operation.
* @param[in]    u8CounterId         The secure counter ID that will be used.
* @param[in]    u32MessageLength    Number of bytes of message on which CMAC is to be computed.
* @param[in]    pMessage            Pointer to the message buffer.
* @param[out]   pMac                Pointer to the 128-bit buffer containing the result of the CMAC generation.
* @param[out]   u32MacLen           The output buffer length for MAC.
* @param[out]   pVolatileCounter    Pointer to the the current VC.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_MacGenerateSecCounter
(
    VAR    (uint32, AUTOMATIC                   ) u32KeyId,
    VAR    (uint8,  AUTOMATIC                   ) u8CounterId,
    VAR    (uint32, AUTOMATIC                   ) u32MessageLength,
    P2CONST(uint8,  AUTOMATIC, CRYPTO_APPL_CONST) pMessage,
    P2VAR  (uint8,  AUTOMATIC, CRYPTO_APPL_DATA ) pMac,
    VAR    (uint32, AUTOMATIC                   ) u32MacLen,
    P2VAR  (uint32, AUTOMATIC, CRYPTO_APPL_DATA ) pVolatileCounter
)
{
    VAR(Std_ReturnType,                AUTOMATIC) RetVal            = (Std_ReturnType)E_NOT_OK;
#if (STD_ON == CRYPTO_KEYS_EXIST)
    VAR(uint32,                        AUTOMATIC) u32CryptoKeyIdIdx = Crypto_Util_GetKeyIdIdx (u32KeyId);
    VAR(Cse_ErrorCodeType,             AUTOMATIC) eStatus           = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;
    VAR(Crypto_VerifyKeyElementIdType, AUTOMATIC) VerifyKeyMaterial;
    
    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        VerifyKeyMaterial = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KEY_MATERIAL_U32);

        if ((Std_ReturnType)E_OK  == VerifyKeyMaterial.RetVal)
        {
            /* Request From CSE the generation */
            eStatus = Crypto_Cse_SendCommandMacGenerateSecCounter((Cse_KeyHandleType)Crypto_aKeyElementList[VerifyKeyMaterial.u32Counter]->u32CryptoKeyHandle,
                                                                  (Cse_CounterId)u8CounterId,
                                                                  u32MessageLength,
                                                                  pMessage,
                                                                  u8aHashMacTemp,
                                                                  pVolatileCounter
                                                                 );
            if(CSE_ERC_NO_ERROR == eStatus)
            {
                if(CRYPTO_CSE_CMAC_OUT_LEN_U32 <= u32MacLen)
                {
                    Crypto_Util_Memcpy(u8aHashMacTemp, pMac, CRYPTO_CSE_CMAC_OUT_LEN_U32);
                }
                else
                {
                    /* If the result pointer is smaller than standard length output then the most significant bits of the result will be returned */
                    Crypto_Util_Memcpy(u8aHashMacTemp, pMac, u32MacLen);
                }
            }
            RetVal = Crypto_Cse_VerifyCseResponse (eStatus);
        }
    }
    else 
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }
    
#else
    (void)u32KeyId;
    (void)u8CounterId;
    (void)u32MessageLength;
    (void)pMessage;
    (void)pMac;
    (void)u32MacLen;
    (void)pVolatileCounter;
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */

    return RetVal;
}

/**
* @brief            CMAC Verification with Secure Counter.
* @details          Verifies the MAC of a given input message, concatenated with the implied value of the selected secure counter.
*
* @param[in]       u32KeyId             KeyID used to perform the cryptographic operation.
* @param[in]       u8CounterId          The secure counter ID that will be used.
* @param[in]       u8RlvPrtOffset       Rollover protection offset.
* @param[in]       u32MessageLength     Number of bytes of message on which CMAC is to be computed.
* @param[in]       pMessage             Pointer to the message buffer.
* @param[in]       pMac                 Pointer to the 128-bit buffer containing the the CMAC.
* @param[in]       u32MacLength         The length of the MAC.
* @param[in]       u32VolatileCounter   Implied value of the Volatile Counter.
* @param[out]      pVrfStatus           Verification status.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_MacVerifySecCounter
(
    VAR    (uint32, AUTOMATIC                   ) u32KeyId,
    VAR    (uint8,  AUTOMATIC                   ) u8CounterId,
    VAR    (uint8,  AUTOMATIC                   ) u8RlvPrtOffset,
    VAR    (uint32, AUTOMATIC                   ) u32MessageLength,
    P2CONST(uint8,  AUTOMATIC, CRYPTO_APPL_CONST) pMessage,
    P2VAR  (uint8,  AUTOMATIC, CRYPTO_APPL_DATA ) pMac,
    VAR    (uint8,  AUTOMATIC                   ) u32MacLength,
    VAR    (uint32, AUTOMATIC                   ) u32VolatileCounter,
    P2VAR  (uint32, AUTOMATIC, CRYPTO_APPL_DATA ) pVrfStatus
)
{
    VAR(Std_ReturnType,                AUTOMATIC) RetVal            = (Std_ReturnType)E_NOT_OK;
#if (STD_ON == CRYPTO_KEYS_EXIST)
    VAR(uint32,                        AUTOMATIC) u32CryptoKeyIdIdx = Crypto_Util_GetKeyIdIdx (u32KeyId);
    VAR(Cse_ErrorCodeType,             AUTOMATIC) eStatus           = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;
    VAR(Crypto_VerifyKeyElementIdType, AUTOMATIC) VerifyKeyMaterial;
    
    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        VerifyKeyMaterial = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KEY_MATERIAL_U32);
        if ((Std_ReturnType)E_OK  == VerifyKeyMaterial.RetVal)
        {
            /* Request From CSE the verification */
            eStatus = Crypto_Cse_SendCommandMacVerifySecCounter((Cse_KeyHandleType)Crypto_aKeyElementList[VerifyKeyMaterial.u32Counter]->u32CryptoKeyHandle,
                                                                (Cse_CounterId)u8CounterId,
                                                                u8RlvPrtOffset,
                                                                u32MessageLength,
                                                                pMessage,
                                                                pMac,
                                                                u32MacLength,
                                                                u32VolatileCounter,
                                                                pVrfStatus
                                                                );
        }
        RetVal = Crypto_Cse_VerifyCseResponse (eStatus);
    }
    else 
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }
#else
    (void)u32KeyId;
    (void)u8CounterId;
    (void)u8RlvPrtOffset;
    (void)u32MessageLength;
    (void)pMessage;
    (void)pMac;
    (void)u32MacLength;
    (void)u32VolatileCounter;
    (void)pVrfStatus;
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */

    return RetVal;
}

/**
* @brief           Send command for SHA-256.
* @details         The SHA-256_HASH command generates the hash over the input message based on the RSA SSA-PKCS1-V1_5 standard.
*
* @param[in]       pInputKey         Message start address.
* @param[in]       pInputKeyLen      Message length (bytes) address.
* @param[out]      pResult           Output address.
* @param[in]       eJobProcessing    The processing type used.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_SHA256
(
    P2CONST(uint8,                 AUTOMATIC, CRYPTO_APPL_CONST) pInputKey, 
    P2VAR  (uint64,                AUTOMATIC, CRYPTO_APPL_DATA ) pInputKeyLen,
    P2VAR  (uint8,                 AUTOMATIC, CRYPTO_APPL_DATA ) pResult,
    VAR    (Crypto_ProcessingType, AUTOMATIC                   ) eJobProcessing
)
{
    VAR  (Cse_ErrorCodeType, AUTOMATIC) eStatus = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR; 
    VAR  (Std_ReturnType,    AUTOMATIC) RetVal  = (Std_ReturnType)E_NOT_OK;
    
    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        /* TODO - check size for pResultBitLen */
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            eStatus = Crypto_Cse_SendCommandSHA_256(pInputKey,pInputKeyLen,pResult,eJobProcessing);
        }
        else
        {
            eStatus = (Cse_ErrorCodeType)CSE_ERC_BUSY;
        }

        /** @violates @ref Crypto_Ipw_c_REF_5 Violates MISRA 2004 Required Rule 10.1, the value of an expression of integer is converted to a different underlying type */
        RetVal = Crypto_Cse_VerifyCseResponse ((Cse_ErrorCodeType)eStatus);
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }

    return RetVal;
}

/**
* @brief           Send debug challenge command.
* @details         Generates a 128-bit random challenge output value that is used in conjunction with the DEBUG_AUTH command.
*
* @param[out]      pOutChallengeAdress - Message start address where the output challenge will be stored.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE)Crypto_Cse_DebugChallenge
(
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) pOutChallengeAdress
)
{
    VAR(Std_ReturnType,     AUTOMATIC) RetVal  = (Std_ReturnType)CRYPTO_E_BUSY;
    VAR(Cse_ErrorCodeType,  AUTOMATIC) eStatus = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;

    if ((boolean)TRUE == bCSE2OnlySupport)
    {
        /* Check if driver is initialized and PRNG state is initialized */
        if ( CRYPTO_DRIVER_INITIALIZED == Crypto_eDriverState )
        {
            if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
            {
                eStatus = Crypto_Cse_SendCommandDebugChallenge(pOutChallengeAdress);
                RetVal  = Crypto_Cse_VerifyCseResponse (eStatus);
            }
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }
    return RetVal;
}

/**
* @brief           Send session challenge command.
* @details         The SS_CHAL command outputs a 288-bit value consisting of a 128-bit random challenge value concatenated with the 120-bit UID,
*                  4-bit Certificate ID, 4-bit Challenge Mode, and 32 bits of zero padding.
*
* @param[out]      pOutChallengeAdress    Message start address where the output challenge will be stored.
* @param[in]       u8CertificateId        Public key specified.
* @param[in]       u8ChallengeMode        0 - No keys are erased.
*                                         1 - Erase all symmetric keys, excluding BOOT_MAC_KEY and BOOT_MAC.
*                                         2 - Erase all installed public key certificates, including ROOT_PK and CRL.
*                                         3 - Erase all installed public key certificates, including ROOT_PK and CRL.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE)Crypto_Cse_SessionChallenge
(
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) pOutChallengeAdress,
    VAR  (uint8, AUTOMATIC                  ) u8CertificateId,
    VAR  (uint8, AUTOMATIC                  ) u8ChallengeMode
)
{
    VAR(Std_ReturnType,     AUTOMATIC) RetVal  = (Std_ReturnType)CRYPTO_E_BUSY;
    VAR(Cse_ErrorCodeType,  AUTOMATIC) eStatus = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;

    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        /* Check if driver is initialized and PRNG state is initialized */
        if ( CRYPTO_DRIVER_INITIALIZED == Crypto_eDriverState )
        {
            if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
            {
                eStatus = Crypto_Cse_SendCommandSessionChallenge(pOutChallengeAdress,u8CertificateId,u8ChallengeMode);
                RetVal  = Crypto_Cse_VerifyCseResponse (eStatus);
            }
        }
    }
    else 
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }

    return RetVal;
}

/**
* @brief           Send debug authorization command.
* @details         Erases all user keys and sets the CSE_SR[IDB] flag which enables internal debugging if the 128-bit authorization input value is valid
*                  and no memory slots are write protected.
*
* @param[in]       pAuthorization - Message start address where the output challenge was stored.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE)Crypto_Cse_DebugAuthorization
(
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) pAuthorization
)
{
    VAR(Std_ReturnType,     AUTOMATIC) RetVal  = (Std_ReturnType)CRYPTO_E_BUSY;
    VAR(Cse_ErrorCodeType,  AUTOMATIC) eStatus = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;
    
    if ((boolean)TRUE == bCSE2OnlySupport)
    {
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            eStatus = Crypto_Cse_SendCommandDebugAuth(pAuthorization);
            
            if ((Cse_ErrorCodeType)CSE_ERC_NO_ERROR == eStatus)
            {
                eStatus = Crypto_Cse_WaitCommandComplete();
                RetVal  = Crypto_Cse_VerifyCseResponse (eStatus);
            }
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }
    return RetVal;
}

/**
* @brief           Send secure session authorization command.
* @details         Erases all user keys and sets the CSE_SR[IDB] flag which enables internal debugging if the 128-bit authorization input value is valid
*                  and no memory slots are write protected.
*
* @param[in]       pAuthorization - Message start address where the output challenge was stored.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE)Crypto_Cse_SecureSessionAuth
(
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) pAuthorization
)
{
    VAR(Std_ReturnType,     AUTOMATIC) RetVal  = (Std_ReturnType)CRYPTO_E_BUSY;
    VAR(Cse_ErrorCodeType,  AUTOMATIC) eStatus = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;
    
    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            eStatus = Crypto_Cse_SendCommandDebugAuth(pAuthorization);
            
            if ((Cse_ErrorCodeType)CSE_ERC_NO_ERROR == eStatus)
            {
                eStatus = Crypto_Cse_WaitCommandComplete();
                RetVal  = Crypto_Cse_VerifyCseResponse (eStatus);
            }
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }
    return RetVal;
}

/**
* @brief           Initializes the driver.
* @details         Initializes the driver.
*
* @param[in]       None.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE)Crypto_Cse_Init(void)
{
    VAR(Std_ReturnType,     AUTOMATIC) RetVal = (Std_ReturnType)E_NOT_OK;
    VAR(Cse_ErrorCodeType,  AUTOMATIC) eBrcsStatus;
    VAR(Cse_ErrorCodeType,  AUTOMATIC) eStatus;
    VAR(uint32,             AUTOMATIC) u32BckImageTemp;
    VAR(uint32,             AUTOMATIC) u32KeyStatusTemp;
    VAR(uint32,             AUTOMATIC) u32CounterStatusTemp;
    
    /* INIT TRNG Clock Divider Select. All other bits are set to 0 */
    REG_WRITE32(CRYPTO_CSE_CR_ADDR32, CRYPTO_TRNG_CLOCK_DIV_U32);

    /* Clear the CIF bit in CSE_IR (w1c) */
    REG_WRITE32(CRYPTO_CSE_IR_ADDR32, CRYPTO_CSE_IR_CIF_BIT_MASK_U32);

    /* Initialize PRNG state using TRNG to obtain a seed value for PRNG */
    eStatus = Crypto_Cse_SendCommandInitRng();
    RetVal      = Crypto_Cse_VerifyCseResponse (eStatus);
    
    if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
    {
        /* Check status of BRCS in order to set global flag bCSE2OnlySupport*/
        eBrcsStatus = Crypto_Cse_SendBrcsCommand(STATUS, &u32BckImageTemp, &u32KeyStatusTemp, &u32CounterStatusTemp);
        
        if ((Std_ReturnType)CSE_ERC_NO_ERROR == eBrcsStatus)
        {
            bCSE2OnlySupport = FALSE;
        }
        else
        {
            bCSE2OnlySupport = TRUE;
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_BUSY;
    }

    return RetVal;
}

/**
* @brief           Processes a job.
* @details         Tries to initiate a request to CSE to process a job. If CSE is busy and the job is async, it queues it.
*
* @param[in]       u32ObjectIdIdx    Ientifier of the Crypto Driver Object to be used for processing the job.
* @param[in]       pJob              Pointer to the job to be processed.
*
* @return          Result of the operation.
*                   Std_ReturnType
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_ProcessJob
(
    VAR  (uint32,         AUTOMATIC                  ) u32ObjectIdIdx,
    P2VAR(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) pJob
)
{
    VAR (Std_ReturnType, AUTOMATIC) RetVal;

    if(CRYPTO_OPERATIONMODE_SINGLECALL == pJob->jobPrimitiveInputOutput.mode)
    {
        /* Try to send the job for processing to CSE */
        RetVal = Crypto_Cse_ProcessOperation(u32ObjectIdIdx, pJob);
        /* If there was no channel available to process the request, check the type of the request (sync or async) */
        if((Std_ReturnType)CRYPTO_E_BUSY == RetVal)
        {
            if  (
                   ( CRYPTO_PROCESSING_ASYNC == pJob->jobPrimitiveInfo->processingType ) && \
                   ( 0U != Crypto_aObjectList[u32ObjectIdIdx]->u32CryptoQueueSize )
                )
            {
                /* Check if the async job has the same jobId with the currently processed job (req SWS_Crypto_00121), and if yes, bypass it from queuing */
                if(pJob->jobInfo->jobId == Crypto_JobInProgress.jobInfo->jobId)
                {
                     RetVal = (Std_ReturnType)E_NOT_OK;
                }
                else
                {
                    /* Try to queue the job */
                    if((boolean)TRUE == Crypto_Util_QueueJob(u32ObjectIdIdx, pJob))
                    {
                        /* Set return value to E_OK, as the async job has been queued successfully for later processing */
                        RetVal = (Std_ReturnType)E_OK;
                    }
                    else
                    {
                        /* Job could not be queued as the CDO queue is full */
                        RetVal = (Std_ReturnType)CRYPTO_E_QUEUE_FULL;
                    }
                }
            }
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }
    return RetVal;
}

/**
* @brief           Cancels a job.
* @details         Tries to cancel the currently processing job if the id is the same. Otherwise searches the queue of jobs in order to dequeue it.
*
* @param[in]       u32ObjectIdIdx    Identifier of the Crypto Driver Object to be used for canceling the job.
* @param[in]       pJobInfo          Pointer to the jobInfo of the job to be canceled.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_CancelJob
(
    VAR  (uint32,             AUTOMATIC                  ) u32ObjectIdIdx,
    P2VAR(Crypto_JobInfoType, AUTOMATIC, CRYPTO_APPL_DATA) pJobInfo
)
{
    VAR(Cse_ErrorCodeType, AUTOMATIC) eCseResponse;
    VAR(Std_ReturnType,    AUTOMATIC) RetVal;

    /* Check if there is a processing command ongoing that is a job, matching the same id with the one requested to be canceled */
    if(((boolean)TRUE   == Crypto_Cse_bCommandInProgress)       && \
       ((boolean)TRUE   == Crypto_Cse_bCommandInProgressIsAJob) && \
       ((boolean)TRUE   == Crypto_Cse_IsBusy())                 && \
       (pJobInfo->jobId == Crypto_JobInProgress.jobInfo->jobId)
       )
    {
        /* Try to cancel the job by canceling the current command sent to CSE */
        eCseResponse = Crypto_Cse_SendCommandCancel();
        /* Check if the currently processing job was successfully canceled */
        if(CSE_ERC_NO_ERROR == eCseResponse)
        {
            /* SWS_Crypto_00144 - If a job is canceled, it shall return CRYPTO_E_JOB_CANCELED either with the callback, when the job is an asynchronous job
            or as the return value of the function Crypto_ProcessJob(), in case the job is synchronous.*/
            if(CRYPTO_PROCESSING_ASYNC == Crypto_JobInProgress.jobPrimitiveInfo->processingType)
            {
                Callback (&Crypto_JobInProgress, CRYPTO_E_JOB_CANCELED);
                /* SWS_Crypto_00122 - Return value: Std_ReturnType: E_OK: Request successful, job has been removed.*/
                RetVal = (Std_ReturnType)E_OK;
            }
            else
            {
                RetVal = (Std_ReturnType)CRYPTO_E_JOB_CANCELED;
            }
            /* As the job has been successfully canceled, there is no currently processing CSE command */
            Crypto_Cse_bCommandInProgress       = (boolean)FALSE;
            Crypto_Cse_bCommandInProgressIsAJob = (boolean)FALSE;
        }
        else
        {
            /* SWS_Crypto_00181 - If cancellation of the currently processed is not possible due to limitations, the result of the job shall be discarded and the callback notification shall be suppressed. */
            /* SWS_Crypto_00183 - If cancellation of the currently processed is not possible immediately due to limitations, Crypto_CancelJob() shall return with CRYPTO_E_JOB_CANCELED as return value. */
            RetVal = (Std_ReturnType)CRYPTO_E_JOB_CANCELED;
        }
    }
    else
    {
        /* Check the job queue of the CDO pointed by u32ObjectIdIdx to see if a job with the same jobId can be found */
        RetVal = Crypto_Util_DequeueJob(u32ObjectIdIdx, pJobInfo);
        /* If a job with same jobId was found in the list of queued jobs, it was dequeued by the above function and now it resides on the first (head) position in the list of free jobs */
        if(RetVal == (Std_ReturnType)E_OK)
        {
            Callback (&(Crypto_aObjectList[u32ObjectIdIdx]->pQueuedJobs[Crypto_aObjectList[u32ObjectIdIdx]->u32HeadOfFreeJobs].Job), CRYPTO_E_JOB_CANCELED);
        }
        else
        {
            /* SWS_Crypto_00122 - Return value: Std_ReturnType: E_NOT_OK: Request Failed, job couldn't be removed. */
            RetVal = (Std_ReturnType)E_NOT_OK;
        }
    }
    
    return RetVal;
}

/**
* @brief           Main function.
* @details         Main function checks for async jobs, then send jobs from the queue.
*
* @param[in]       None.
*
* @return          Result of the operation.
*                   Void.
*
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC (void, CRYPTO_CODE) Crypto_Cse_MainFunction(void)
{
    VAR  (boolean,                AUTOMATIC                  ) bJobSentToCseAndDequeued = (boolean)TRUE;
    VAR  (uint32,                 AUTOMATIC                  ) u32ResultLen             = Crypto_JobInProgress.jobPrimitiveInfo->primitiveInfo->resultLength;
    VAR  (Crypto_ServiceInfoType, AUTOMATIC                  ) eService                 = Crypto_JobInProgress.jobPrimitiveInfo->primitiveInfo->service;
    VAR  (Std_ReturnType,         AUTOMATIC                  ) CseResponse;
    VAR  (uint32,                 AUTOMATIC                  ) u32ReceiveMsg;
    VAR  (uint32,                 AUTOMATIC                  ) u32HeadOfQueuedJobs;
    P2VAR(Crypto_JobType,         AUTOMATIC, CRYPTO_APPL_DATA) pJob;
    
    static VAR(uint32,AUTOMATIC) u32ObjectIdIdx = 0U;
    
    /* Check if there is a processing job that has been finished */
    if(((boolean)TRUE == Crypto_Cse_bCommandInProgress)       && \
       ((boolean)TRUE == Crypto_Cse_bCommandInProgressIsAJob) && \
       ((boolean)FALSE == Crypto_Cse_IsBusy())
      )
    {
        /* Read the receive register */
        u32ReceiveMsg = REG_READ32(CRYPTO_CSE_ECR_ADDR32);
        /* No CSE command is currently processed */
        Crypto_Cse_bCommandInProgress       = (boolean)FALSE;
        /* Reset also the flag that states that the currently processed command is a job */
        Crypto_Cse_bCommandInProgressIsAJob = (boolean)FALSE;
        /* For the Mac Generation and HASH requests move the result of the cryptographic operation into job's outputPtr */
        if (CSE_ERC_NO_ERROR == (Cse_ErrorCodeType)u32ReceiveMsg)
        {
            if(CRYPTO_MACGENERATE == eService)
            {
                if(CRYPTO_CSE_CMAC_OUT_LEN_U32 <= u32ResultLen)
                {
                    Crypto_Util_Memcpy(u8aHashMacTemp, Crypto_JobInProgress.jobPrimitiveInputOutput.outputPtr, CRYPTO_CSE_CMAC_OUT_LEN_U32);
                }
                else
                {
                    /** If result length is smaller than 
                    standard length output the most significant bits of the result 
                    shall be truncated to the configured result length*/
                    Crypto_Util_Memcpy(u8aHashMacTemp, Crypto_JobInProgress.jobPrimitiveInputOutput.outputPtr, u32ResultLen);
                }
            }
            else if(CRYPTO_HASH == eService)
            {
                switch (Crypto_JobInProgress.jobPrimitiveInfo->primitiveInfo->algorithm.mode)
                {
                    /* SHA-256 HTA */
                    case CRYPTO_ALGOMODE_RSASSA_PKCS1_v1_5:
                        if (CRYPTO_CSE_SHA256_OUT_LEN_U32 <= u32ResultLen)
                        {
                            Crypto_Util_Memcpy(u8aHashMacTemp, Crypto_JobInProgress.jobPrimitiveInputOutput.outputPtr, CRYPTO_CSE_SHA256_OUT_LEN_U32);
                        }
                        else
                        {
                            /** If result length is smaller than 
                            standard length output the most significant bits of the result 
                            shall be truncated to the configured result length*/
                            Crypto_Util_Memcpy(u8aHashMacTemp, Crypto_JobInProgress.jobPrimitiveInputOutput.outputPtr, u32ResultLen);
                        }
                        break;
                    /* MP compression */
                    case CRYPTO_ALGOMODE_ECB:
                        if (CRYPTO_CSE_MP_COMP_OUT_LEN_U32 >= u32ResultLen)
                        {
                            Crypto_Util_Memcpy(u8aHashMacTemp, Crypto_JobInProgress.jobPrimitiveInputOutput.outputPtr, CRYPTO_CSE_MP_COMP_OUT_LEN_U32);
                        }
                        else
                        {
                            /** If result length is smaller than 
                            standard length output the most significant bits of the result 
                            shall be truncated to the configured result length*/
                            Crypto_Util_Memcpy(u8aHashMacTemp, Crypto_JobInProgress.jobPrimitiveInputOutput.outputPtr, u32ResultLen);
                        }
                        break;
                    default:
                        u32ReceiveMsg =(uint32)CSE_ERC_INVALID_CMD;
                        break;
                }
            }
        }
        
        /* Interpret the message received from CSE */
        CseResponse = Crypto_Cse_VerifyCseResponse (u32ReceiveMsg);
        
        /* Fill the verifyPtr in case the primitive was MacGenerate or AEAD Decrypt */
        Crypto_Cse_FillVerifyPtr (CseResponse);
        
        /* Call the callback */
        Callback (&Crypto_JobInProgress, CseResponse);
    }

    /* Keep looping while we manage to dequeue async jobs from any of the CDOs queues and send them to CSE */
    while((boolean)TRUE == bJobSentToCseAndDequeued)
    {
        bJobSentToCseAndDequeued = (boolean)FALSE;
        /* Try to take the first job from each CDO's queue of jobs and send it to CSE, in order to assure that jobs requests from all CDOs are sent being processed with the same priority */
        while(CRYPTO_JOB_QUEUE_NONE_U32 != Crypto_aObjectList[u32ObjectIdIdx]->u32HeadOfQueuedJobs)
        {
            u32HeadOfQueuedJobs = Crypto_aObjectList[u32ObjectIdIdx]->u32HeadOfQueuedJobs;
            /* Take the first job in the queue. The queue is already ordered by priority so the first job in queue has the highest priority */
            pJob = &(Crypto_aObjectList[u32ObjectIdIdx]->pQueuedJobs[u32HeadOfQueuedJobs].Job);
            /* Try to send the job to CSE for processing */
            CseResponse = Crypto_Cse_ProcessOperation(u32ObjectIdIdx, pJob);
            
            if((Std_ReturnType)CRYPTO_E_BUSY != CseResponse)
            {
                /* If return value is not E_OK, call the callback to inform the upper layers an error happened with the job */
                if ((Std_ReturnType)E_OK != CseResponse)
                {
                    Callback (pJob, CseResponse);
                }
                /* If return value is not CRYPTO_E_BUSY, it means that a free channel was found and the request was send to CSE
                   Take the first queued job and put it back in the free jobs queue */
                Crypto_Util_DequeueHeadJob(u32ObjectIdIdx);
                /* Mark the job as being dequeued and sent to CSE for processing */
                bJobSentToCseAndDequeued = (boolean)TRUE;
            }
            else
            {
                /* Exit the inner while without updating the CDO, so that at next MainFunction call the current CDO has the chance to send again the job to CSE */
                break;
            }
            /* Pass to the queue of the next CDO */
            u32ObjectIdIdx = (u32ObjectIdIdx+1U)%CRYPTO_NUMBER_OF_DRIVER_OBJECTS_U32;
        }
    }
}

/**
* @brief           Import key.
* @details         Loads the key from the pointer to RAM,NVM or using SHE specification.
*
* @param[in]       pKeyPtr             Pointer to the buffer containing the key that needs to be copied.
* @param[in]       u32CryptoKeyIdIdx   The index of the used key.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_LoadKey
(
    P2CONST(uint8,  AUTOMATIC, CRYPTO_APPL_CONST) pKeyPtr,
    VAR    (uint32, AUTOMATIC                   ) u32CryptoKeyIdIdx
)
{
    VAR  (Std_ReturnType,                   AUTOMATIC                   ) RetVal                   = (Std_ReturnType)E_NOT_OK;
#if (STD_ON == CRYPTO_KEYS_EXIST)
    VAR  (Cse_ErrorCodeType,                AUTOMATIC                   ) eStatus                  = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;
    VAR  (Crypto_VerifyKeyElementIdType,    AUTOMATIC                   ) VerifyKeyMaterialElement = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KEY_MATERIAL_U32);
    VAR  (uint32,                           AUTOMATIC                   ) u32KeyHandleId           = Crypto_aKeyElementList[VerifyKeyMaterialElement.u32Counter]->u32CryptoKeyHandle;
    VAR  (boolean ,                         AUTOMATIC                   ) bKeyElPersist            = Crypto_aKeyElementList[VerifyKeyMaterialElement.u32Counter]->bCryptoKeyElementPersist;
    CONST(Crypto_KeyElementWriteAccessType, CRYPTO_CONST                ) eKeyElementWriteAccess   = Crypto_aKeyElementList[VerifyKeyMaterialElement.u32Counter]->eCryptoKeyElementWriteAccess;
    VAR  (Crypto_VerifyKeyElementIdType,    AUTOMATIC                   ) VerifyKeyMacProof;
    VAR  (Crypto_VerifyKeyElementIdType,    AUTOMATIC                   ) VerifyKeyCipherProof;
    P2VAR(uint8,                            AUTOMATIC,  CRYPTO_APPL_DATA) pMacProof;
    VAR  (uint32,                           AUTOMATIC                   ) u32MacProofLength;
    P2VAR(uint8,                            AUTOMATIC,  CRYPTO_APPL_DATA) pCipherProof;
    VAR  (uint32,                           AUTOMATIC                   ) u32CipherProofLength;
    
    VerifyKeyMacProof     = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KE_MAC_PROOF);
    VerifyKeyCipherProof  = Crypto_Util_VerifyKeyElementId (u32CryptoKeyIdIdx, CRYPTO_KE_CIPHER_PROOF);
    
    if ( ((Std_ReturnType)E_NOT_OK == VerifyKeyMacProof.RetVal) || ((Std_ReturnType)E_NOT_OK == VerifyKeyCipherProof.RetVal) )
    {
        VerifyKeyMacProof.u32Counter    = VerifyKeyMaterialElement.u32Counter;
        VerifyKeyCipherProof.u32Counter = VerifyKeyMaterialElement.u32Counter;
    }
    
    pMacProof            = Crypto_aKeyElementList[VerifyKeyMacProof.u32Counter]->pCryptoElementArray;
    pCipherProof         = Crypto_aKeyElementList[VerifyKeyCipherProof.u32Counter]->pCryptoElementArray;
    u32MacProofLength    = Crypto_aKeyElementList[VerifyKeyMacProof.u32Counter]->u32CryptoKeyElementActualSize;
    u32CipherProofLength = Crypto_aKeyElementList[VerifyKeyCipherProof.u32Counter]->u32CryptoKeyElementActualSize;
    
    if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
    {
        if (u32KeyHandleId == (uint32)CSE_RAM_KEY)
        {
            if ( (boolean)FALSE == bKeyElPersist )
            {
                /*Work around: use load plain key to test other functions*/
                eStatus = Crypto_Cse_SendCommandPlainKey(pKeyPtr);
            }
            else
            {
                eStatus = (Cse_ErrorCodeType)CSE_ERC_KEY_INVALID;
            }
        }
        else
        {
            if ( CRYPTO_WA_ENCRYPTED == eKeyElementWriteAccess )
            {
                /* Check if M4 and M5 output length is at least equal to standard size*/
                if ((u32MacProofLength >= CRYPTO_M5SIZE_U32) && (u32CipherProofLength >= CRYPTO_M4SIZE_U32))
                {
                    /* Load SHE keys to memory*/
                    /** @violates @ref Crypto_Ipw_c_REF_5 Violates MISRA 2004 Required Rule 10.1, the value of an expression of integer is converted to a different underlying type */
                    /** @violates @ref Crypto_Ipw_c_REF_4 Violates MISRA 2004 Required Rule 17.4, Array indexing shall be the only allowed form of pointer*/
                    eStatus = Crypto_Cse_SendCommandLoadKey((Cse_KeyHandleType)u32KeyHandleId, 
                                                             &pKeyPtr[CRYPTO_M1INDEX_U32],
                                                             &pKeyPtr[CRYPTO_M2INDEX_U32],
                                                             &pKeyPtr[CRYPTO_M3INDEX_U32],
                                                             &pCipherProof[0],
                                                             &pMacProof[0]
                                                            );
                }
                else
                {
                    eStatus = (Cse_ErrorCodeType)CSE_ERC_LENGTH;
                }
            }
            /* Load Plain Text Key to NVM */
            else
            {
                if ( (boolean)TRUE == bKeyElPersist )
                {
                    if ((boolean)FALSE == bCSE2OnlySupport)
                    {
                        eStatus = Crypto_Cse_SendCommandLoadPlainTextKey((Cse_KeyHandleType)u32KeyHandleId,
                                                                         pKeyPtr,
                                                                         Crypto_aKeyElementList[VerifyKeyMaterialElement.u32Counter]->u32CryptoKeyFlags
                                                                        );
                    }
                    else
                    {
                        eStatus = (Cse_ErrorCodeType)CSE_ERC_NOT_SUPPORTED;
                    }

                }
                else
                {
                    eStatus = (Cse_ErrorCodeType)CSE_ERC_KEY_INVALID;
                }
            }
        }
    }
    else
    {
        eStatus = (Cse_ErrorCodeType)CSE_ERC_BUSY;
    }
    
    RetVal = Crypto_Cse_VerifyCseResponse ((uint32)eStatus);
#else
    (void)pKeyPtr;
    (void)u32CryptoKeyIdIdx;
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */

    return RetVal;
}

/**
* @brief           Export key.
* @details         Exports the RAM key to the provided address.
*
* @param[in]       u32CryptoKeyElementIdIdx    The index of the used key.
* @param[out]      pResult                     Address where the key will be stored.
* @param[in]       pResultLength               Length of the output pointer.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_ExportKey 
(
    VAR  (uint32, AUTOMATIC                  ) u32CryptoKeyElementIdIdx,
    P2VAR(uint8,  AUTOMATIC, CRYPTO_APPL_DATA) pResult,
    P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) pResultLength
)
{
    VAR (Std_ReturnType,    AUTOMATIC) RetVal         = (Std_ReturnType)E_NOT_OK;
#if (STD_ON == CRYPTO_KEYS_EXIST)
    VAR (Cse_ErrorCodeType, AUTOMATIC) eStatus        = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;
    VAR (uint32,            AUTOMATIC) u32KeyHandleId = Crypto_aKeyElementList[u32CryptoKeyElementIdIdx]->u32CryptoKeyHandle;

    if ((boolean)bCSE2OnlySupport == TRUE)
    {
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            if (u32KeyHandleId == (uint32)CSE_RAM_KEY)
            {
                if (*pResultLength >= CRYPTO_SHE_SIZE_OUT_U32)
                {
                    eStatus = Crypto_Cse_SendCommandExportRamKey(pResult);
                }
            }
        }
        else
        {
            eStatus = (Cse_ErrorCodeType)CSE_ERC_BUSY;
        }
        /** @violates @ref Crypto_Ipw_c_REF_5 Violates MISRA 2004 Required Rule 10.1, the value of an expression of integer is converted to a different underlying type */
        RetVal = Crypto_Cse_VerifyCseResponse ((Cse_ErrorCodeType)eStatus);
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }

#else
    (void)u32CryptoKeyElementIdIdx;
    (void)pResult;
    (void)pResultLength;
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */

    return RetVal;
}

/**
* @brief           Generate Key.
* @details         Generates a key and loads it into RAM slot.
*
* @param[in]       u32KeyId    The slot where they key will be stored, it must be the RAM slot.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_GenerateKey
(
    VAR(uint32, AUTOMATIC) u32CryptoKeyElementIdIdx
)
{
    VAR (Std_ReturnType, AUTOMATIC) RetVal = (Std_ReturnType)E_NOT_OK;
#if (STD_ON == CRYPTO_KEYS_EXIST)
    VAR(Cse_ErrorCodeType, AUTOMATIC) eStatus                           = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR; 
    VAR(uint32,            AUTOMATIC) u32KeyHandleId                    = Crypto_aKeyElementList[u32CryptoKeyElementIdIdx]->u32CryptoKeyHandle;
    VAR(uint8,             AUTOMATIC) u8aRnd[CRYPTO_LENGTH_OF_ARRAY_16] = {(uint8)0}; 
    
    if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
    {
        if ((uint32)CSE_RAM_KEY == u32KeyHandleId)
        {
            eStatus = Crypto_Cse_SendCommandInitRng();
            if (CSE_ERC_NO_ERROR == eStatus)
            {
                eStatus = Crypto_Cse_SendCommandGenerateRnd(u8aRnd);
                if (CSE_ERC_NO_ERROR == eStatus)
                {
                    eStatus = Crypto_Cse_SendCommandPlainKey(u8aRnd);
                }
            }
        }
    }
    else
    {
        eStatus = (Cse_ErrorCodeType)CSE_ERC_BUSY;
    }
    
    /** @violates @ref Crypto_Ipw_c_REF_5 Violates MISRA 2004 Required Rule 10.1, the value of an expression of integer is converted to a different underlying type */
    RetVal = Crypto_Cse_VerifyCseResponse ((Cse_ErrorCodeType)eStatus);
#else
    (void)u32CryptoKeyElementIdIdx;
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */

    return RetVal;
}

#if (STD_ON == CRYPTO_ASYNC_PROCESS_INTERRUPT)
/**
* @brief           Interrupt handler for CSE IP.
* @details         This function shall manage the interrupt for CSE.
*
* @param[in]       None.
*
* @return          Result of the operation.
*                   Void.
*
* @api
*
* @pre            Driver must be initialized.
*
* @note           Internal driver function.
*
* @implements     Crypto_Cse_InterruptHandler_Activity
*
*/
FUNC(void, CRYPTO_CODE) Crypto_Cse_InterruptHandler(void)
{
    /* Variable to store current value of CSE Interrupt Register */
    VAR(uint32, AUTOMATIC) u32CseInterruptReg = REG_READ32(CRYPTO_CSE_IR_ADDR32);
    /* Variable to store current value of CSE Control Register */
    VAR(uint32, AUTOMATIC) u32CseControlReg   = REG_READ32(CRYPTO_CSE_CR_ADDR32);
    
    /* Clear the interrupt flag (CIF bit in CSE_IR) - w1c */
    REG_WRITE32(CRYPTO_CSE_IR_ADDR32, CRYPTO_CSE_IR_CIF_BIT_MASK_U32);
    /* Clear the CIE bit in CSE_CR register. It will be set by the next asynchronous request */
    REG_BIT_CLEAR32(CRYPTO_CSE_CR_ADDR32, CRYPTO_CSE_CR_CIE_BIT_MASK_U32);
    
    /* Check if the interrupt is not spurious:
        - interrupt should be received  with the CIE bit set in the CSE_CR (Control Register)
        - interrupt should be received  with the CIF bit set in the CSE_IR (Interrupt Register) */
    if ( ((boolean)TRUE == Crypto_Cse_IsBitSet(u32CseControlReg,   CRYPTO_CSE_CR_CIE_BIT_MASK_U32)) && \
         ((boolean)TRUE == Crypto_Cse_IsBitSet(u32CseInterruptReg, CRYPTO_CSE_IR_CIF_BIT_MASK_U32))    \
       )
    {
        /* Check if the Crypto driver is initialized */
        if ( CRYPTO_DRIVER_INITIALIZED == Crypto_eDriverState )
        {
            Crypto_Cse_MainFunction();
        }
    }
}
#endif /* (STD_ON == CRYPTO_ASYNC_PROCESS_INTERRUPT) */

/**
* @brief           Generates a vector of 128 ture random bits.
* @details         The function returns a vector of 128 ture random bits. 
*                  CSE_CR[DIV] field must be properly configured before this command is executed.
*                  There is a very small probability that this command may return a TRNG error (EC = 0x12) even when the TRNG is operating properly.
*                  This function does not work for VLRP (Very Low Power).
*
* @param[out]      pTrueRandomValue: The address where the random value will be stored.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @api
*
* @pre            Driver must be initialized.
*
*/
/**
* @violates @ref Crypto_Ipw_c_REF_3 Violates MISRA 2004 Required Rule 8.10 could be made static
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_GenerateTrueRandom
(
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) pTrueRandomValue
)
{
    VAR(Std_ReturnType,     AUTOMATIC) RetVal  = (Std_ReturnType)E_NOT_OK;
    VAR(Cse_ErrorCodeType,  AUTOMATIC) eStatus = (Cse_ErrorCodeType)CSE_ERC_GENERAL_ERROR;

    if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
    {
        eStatus = Crypto_Cse_SendCommandGenerateTrueRandom(pTrueRandomValue);
        RetVal  = Crypto_Cse_VerifyCseResponse (eStatus);
    }
    else
    {
        RetVal = (Cse_ErrorCodeType)CRYPTO_E_BUSY;
    }
    return RetVal;
}

/**
* @brief        Generates the internal seed state using the provided entropy source.
* @details      Update the seed state with new entropy.
*
* @param[in]    pEntropy          Pointer to a 128-bit buffer containing the entropy
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre          Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_GenerateSeed
(
    P2CONST(uint8,  AUTOMATIC, CRYPTO_APPL_CONST) pEntropy,
    VAR    (uint32, AUTOMATIC                   ) u32SeedLength,
    P2VAR  (uint8,  AUTOMATIC, CRYPTO_APPL_DATA ) pSeedState
)
{
    VAR(Cse_ErrorCodeType, AUTOMATIC) eStatus    = CSE_ERC_GENERAL_ERROR;
    VAR(Std_ReturnType,    AUTOMATIC) RetVal     = (Std_ReturnType)E_NOT_OK;

    /* Seed must have 128bits of information */
    if(CRYPTO_CSE_SEED_LEN_U32 == u32SeedLength)
    {
        eStatus = Crypto_Cse_SendCommandExtendPrngSeed(pEntropy);

        if (CSE_ERC_NO_ERROR == eStatus)
        {
            eStatus = Crypto_Cse_SendCommandGenerateRnd(u8aSeedResult);

            /* Copy u8aSeedResult into pSeedState */
            if(CSE_ERC_NO_ERROR == (Cse_ErrorCodeType)eStatus)
            {
                Crypto_Util_Memcpy(u8aSeedResult, pSeedState, 16U);
            }
        }
        RetVal = Crypto_Cse_VerifyCseResponse (eStatus);
    }
    return RetVal;
}

/**
* @brief        Generates UID value.
* @details      UID will be written in pointer parameter.
*
* @param[out]    pUidResultAddr          Pointer to a 128-bit buffer where UID will be stored.
* @param[out]    pMacAddr                Pointer to a 128-bit buffer where MAC key will be stored.
* @param[out]    pSregAddr               Pointer to a 128-bit buffer where status register will be stored.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre          Driver must be initialized.
*
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_Cse_GetID
(
    P2VAR(uint8,  AUTOMATIC, CRYPTO_APPL_DATA) pUidResultAddr,
    P2VAR(uint8,  AUTOMATIC, CRYPTO_APPL_DATA) pMacAddr,
    P2VAR(uint8,  AUTOMATIC, CRYPTO_APPL_DATA) pSregAddr
)
{
    VAR(uint8,             AUTOMATIC)challenge[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
    VAR(Cse_ErrorCodeType, AUTOMATIC)eOutResponse  = CSE_ERC_GENERAL_ERROR;
    VAR(Std_ReturnType,    AUTOMATIC)RetVal        = (Std_ReturnType)E_NOT_OK;

    if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
    {
        eOutResponse = Crypto_Cse_SendCommandGetId(pUidResultAddr,pMacAddr,pSregAddr,challenge);

        if ((Cse_ErrorCodeType)CSE_ERC_NO_ERROR == eOutResponse)
        {
            eOutResponse = Crypto_Cse_WaitCommandComplete();
            RetVal      = Crypto_Cse_VerifyCseResponse (eOutResponse);
        }
    }
    else
    {
        RetVal = (Cse_ErrorCodeType)CRYPTO_E_BUSY;
    }

    return RetVal;
}

/**
* @brief         Send BOOT OK command.
* @details       The BOOT_OK command sets the CSE_SR[BFN] flag and leaves the CSE_SR[BOK] flag set to confirm successful completion of the secure boot processes.
*                This enables the use of memory slots that have the BOOT_PROT flag set if they are not disabled for some other reason.
*
* @param[in]     None
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre          
*
*/
FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_BootOk(void)
{
    VAR(Cse_ErrorCodeType, AUTOMATIC) eOutResponse  = CSE_ERC_GENERAL_ERROR;
    VAR(Std_ReturnType,    AUTOMATIC) RetVal       =  (Std_ReturnType)E_NOT_OK;
    
    if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
    {
        eOutResponse = Crypto_Cse_SendCommandBootOk();
        RetVal       = Crypto_Cse_VerifyCseResponse (eOutResponse);
    }
    else
    {
        RetVal = (Cse_ErrorCodeType)CRYPTO_E_BUSY;
    }
    return RetVal;
}

/**
* @brief         Send Boot Failure command.
* @details       The BOOT_FAILURE command sets the CSE_SR[BFN] flag and clears the CSE_SR[BOK] flag to disable use of memory slots that have the BOOT_PROT flag set.
*
* @param[in]     None.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre         
*
*/
FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_BootFailure(void)
{
    VAR(Cse_ErrorCodeType, AUTOMATIC) eOutResponse = CSE_ERC_GENERAL_ERROR;
    VAR(Std_ReturnType,    AUTOMATIC) RetVal       = (Std_ReturnType)E_NOT_OK;
    
    if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
    {
        eOutResponse = Crypto_Cse_SendCommandBootFailure();
        RetVal       = Crypto_Cse_VerifyCseResponse (eOutResponse);
    }
    else
    {
        RetVal = (Cse_ErrorCodeType)CRYPTO_E_BUSY;
    }
    return RetVal;
}

/**
* @brief         Send Install Certificate command.
* @details       The INSTALL_CERTIFICATE command authenticates a public key certificate stored in system flash memory and enables the public key to be used
*                for subsequent CSE operations.
*
* @param[in]     u8CertifId        Certificate ID.
* @param[in]     u8AuthCertifId    Authorization certificate ID.
* @param[in]     pCertifAddr       Certificate Address.
* @param[in]     u8CertifType      Certificate Type.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre         Driver must be initialized.
*
*/
FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_InstallCertificate
(
    VAR    (uint8,  AUTOMATIC                   ) u8CertifId,
    VAR    (uint8,  AUTOMATIC                   ) u8AuthCertifId,
    P2CONST(uint8,  AUTOMATIC, CRYPTO_APPL_CONST) pCertifAddr,
    VAR    (uint8,  AUTOMATIC                   ) u8CertifType
)
{
    VAR(Cse_ErrorCodeType, AUTOMATIC)eOutResponse = CSE_ERC_GENERAL_ERROR;
    VAR(Std_ReturnType,    AUTOMATIC)RetVal       = (Std_ReturnType)E_NOT_OK;
    
    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            eOutResponse = Crypto_Cse_SendInstallCertificate(u8CertifId,u8AuthCertifId,pCertifAddr,u8CertifType);
            RetVal       = Crypto_Cse_VerifyCseResponse (eOutResponse);
        }
        else
        {
            RetVal = (Std_ReturnType)CRYPTO_E_BUSY;
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }

    return RetVal;
}

/**
* @brief         Send Verify Signature command.
* @details       The VERIFY_SIGNATURE command verifies a signed message using the RSA SSA- PKCS1-V1_5 standard.
*
* @param[in]     u8AuthCertifId    Authorization certificate ID.
* @param[in]     pMessAddr         Message Address.
* @param[in]     u32MessLen        Message Length (bytes).
* @param[in]     pSignatureAddr    Signature Address.
* @param[out]    pVerifStatus      Verification Status.
* @param[in]     bClearBootMac     Clear BOOT_MAC( if set )
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre         Driver must be initialized.
*
*/
FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_VerifySignature
(
    VAR    (uint8,  AUTOMATIC                   ) u8AuthCertifId,
    P2CONST(uint8,  AUTOMATIC, CRYPTO_APPL_CONST) pMessAddr,
    VAR    (uint32, AUTOMATIC                   ) u32MessLen,
    P2CONST(uint8,  AUTOMATIC, CRYPTO_APPL_CONST) pSignatureAddr,
    P2VAR  (uint32,  AUTOMATIC, CRYPTO_APPL_DATA) pVerifStatus,
    VAR    (boolean,AUTOMATIC                   ) bClearBootMac
)
{
    VAR(Cse_ErrorCodeType, AUTOMATIC)eOutResponse  = CSE_ERC_GENERAL_ERROR;
    VAR(Std_ReturnType,    AUTOMATIC)RetVal        = (Std_ReturnType)E_NOT_OK;

    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            eOutResponse    = Crypto_Cse_SendVerifySignature(u8AuthCertifId,pMessAddr,u32MessLen,pSignatureAddr,bClearBootMac,pVerifStatus);
            RetVal          = Crypto_Cse_VerifyCseResponse (eOutResponse);
        }
        else
        {
            RetVal = (Cse_ErrorCodeType)CRYPTO_E_BUSY;
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }

    return RetVal;
}

/**
* @brief         Send Delete plain text key command.
* @details       The DELETE_PT_KEY command clears plaintext key from RAM.
*
* @param[in]     u8KeyId    The input key ID.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre         Driver must be initialized.
*
*/
FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_DeletePlainTextKey
(
    VAR(uint8, AUTOMATIC) u8KeyId
)
{
    VAR(Std_ReturnType,    AUTOMATIC)RetVal       = (Std_ReturnType)E_NOT_OK;
#if (STD_ON == CRYPTO_KEYS_EXIST)
    VAR(Cse_ErrorCodeType, AUTOMATIC)eOutResponse = CSE_ERC_GENERAL_ERROR;
    VAR(Cse_KeyHandleType, AUTOMATIC)eKeyId       = (Cse_KeyHandleType)u8KeyId;

    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            /* Select the Key Bank used based on the key id */
            Crypto_Cse_KeyBankSelect(&eKeyId);

            eOutResponse = Crypto_Cse_SendCommandDeletePlainTextKey(eKeyId);
            RetVal       = Crypto_Cse_VerifyCseResponse (eOutResponse);
        }
        else
        {
            RetVal = (Std_ReturnType)CRYPTO_E_BUSY;
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }
#else
    (void)u8KeyId;
#endif /* (STD_ON == CRYPTO_KEYS_EXIST) */
    return RetVal;
}

/**
* @brief         Backup Restore Cleanup Status.
* @details       The BRCS command provides 4 separate functions based on the mode input value.
*
* @param[in]     eBrcsMode             Mode.
* @param[inout]  pImageAddress         Backup image address.
* @param[out]    pKeySlotStatus        Slot usage status.
* @param[out]    pCounterSlotStatus    Status of counter slots.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre         Driver must be initialized.
*
*/
FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_BRCS
(
    VAR  (Crypto_BrcsModeType, AUTOMATIC                  ) eBrcsMode,
    P2VAR(uint32,              AUTOMATIC, CRYPTO_APPL_DATA) pImageAddress,
    P2VAR(uint32,              AUTOMATIC, CRYPTO_APPL_DATA) pKeySlotStatus,
    P2VAR(uint32,              AUTOMATIC, CRYPTO_APPL_DATA) pCounterSlotStatus
)
{
    VAR(Cse_ErrorCodeType, AUTOMATIC)eOutResponse = CSE_ERC_GENERAL_ERROR;
    VAR(Std_ReturnType,    AUTOMATIC)RetVal       = (Std_ReturnType)E_NOT_OK;
    
    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            eOutResponse = Crypto_Cse_SendBrcsCommand(eBrcsMode,pImageAddress,pKeySlotStatus,pCounterSlotStatus);
            RetVal       = Crypto_Cse_VerifyCseResponse(eOutResponse);
        }
        else
        {
            RetVal = (Std_ReturnType)CRYPTO_E_BUSY;
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }

    return RetVal;
}

/**
* @brief         Update firmware.
* @details       The UPDATE_FIRMWARE command provides a secure method to update CSE firmware in the field.
*
* @param[in]     pFirmwareAddr          The firmware address input must point to the new encrypted firmware image.
* @param[in]     pSignatureAddr         Signature address.
* @param[in]     u8AuthCertifId         CSE_P3 selects the public key certificate to use for signature verification of the firmware update image.
* @param[out]    pNewFirmVersion        New firmware version is returned in CSE_P4.
* @param[out]    pCurrentFirmVersion    Old firmware version is returned in CSE_P5.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre         Driver must be initialized.
*
*/
FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_UpdateFirmware
(
    P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) pFirmwareAddr,
    P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) pSignatureAddr,
    VAR  (uint8,  AUTOMATIC                  ) u8AuthCertifId,
    P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) pNewFirmVersion,
    P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) pCurrentFirmVersion
)
{
    VAR(Cse_ErrorCodeType, AUTOMATIC)eOutResponse  = CSE_ERC_GENERAL_ERROR;
    VAR(Std_ReturnType,    AUTOMATIC)RetVal        = (Std_ReturnType)E_NOT_OK;
    
    if ((boolean)FALSE == bCSE2OnlySupport)
    {
        if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
        {
            eOutResponse = Crypto_Cse_SendUpdateFirmware(pFirmwareAddr,pSignatureAddr,u8AuthCertifId,pNewFirmVersion,pCurrentFirmVersion);
            RetVal       = Crypto_Cse_VerifyCseResponse(eOutResponse);
        }
        else
        {
            RetVal = (Std_ReturnType)CRYPTO_E_BUSY;
        }
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_NOT_SUPPORTED;
    }

    return RetVal;
}

/**
* @brief           Select Key Bank.
* @details         Selects which set of AES application keys are visible for commands. This field is ignored
*                  for RSA commands when selecting a certificate ID, including SS_CHAL, INSTALL_CERTIFICATE,
*                  UPDATE_FIRMWARE, and VERIFY_SIGNATURE.
*
* @param[in]       pKeyId    Pointer to key id on which will be chosen the slot and key bank
*
* @return          Result of the operation.
*                   None
*
* @api
*
* @pre          Driver must be initialized.
*
*/
FUNC(void, CRYPTO_CODE) Crypto_Cse_KeyBankSelect
(
    P2VAR(Cse_KeyHandleType, AUTOMATIC, CRYPTO_APPL_DATA) pKeyId
)
{
    VAR (uint8, AUTOMATIC) u8KeyBankSelector = (uint8) ((uint8) (*pKeyId) & (~CRYPTO_CSE_KEY_ID_MASK_U8));
    
    /* Select Key Bank based on the 5th bit value of the Key ID, value "0" means that the key is in the range of KEY_3–KEY_10 otherwise the range is KEY_11–KEY_20 */ 
    if((uint8)0U == u8KeyBankSelector)
    {
        /* Select KEY_1-KEY_10 by clearing KBS bit of the CSE Control Register(CSE_CR) */
        REG_BIT_CLEAR32(CRYPTO_CSE_CR_ADDR32, CRYPTO_CSE_CR_KBS_BIT_MASK_U32);
    }
    else
    {
        /* Select KEY_11-KEY_20 by setting KBS bit of the CSE Control Register(CSE_CR) */
        REG_BIT_SET32(CRYPTO_CSE_CR_ADDR32, CRYPTO_CSE_CR_KBS_BIT_MASK_U32);
    }
    /* Extract the Key Slot from Key ID used for cryptographic operations */
    *pKeyId = (Cse_KeyHandleType) ((uint8)(*pKeyId) & CRYPTO_CSE_KEY_ID_MASK_U8);
}

/**
* @brief        Initializes the seed and derives a key for the PRNG.
* @details      This function initializes the seed and derives a key for the PRNG. 
*               The function must be called before CMD_RND after every power cycle or reset.
*
* @param[in]     None
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre         
*
*/
FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_InitRng
(
    void
)
{
    VAR(Cse_ErrorCodeType, AUTOMATIC)eOutResponse  = CSE_ERC_GENERAL_ERROR;
    VAR(Std_ReturnType,    AUTOMATIC)RetVal        = (Std_ReturnType)E_NOT_OK;

    /* Check if CSE is not busy processing a request */
    if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
    {
        eOutResponse = Crypto_Cse_SendCommandInitRng();
        RetVal       = Crypto_Cse_VerifyCseResponse(eOutResponse);
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_BUSY;
    }

    return RetVal;
}

/**
* @brief        Extends the seed of the PRNG by compressing the former seed value and the supplied entropy into a new seed.
* @details      This function extends the seed of the PRNG by compressing the former seed value and the supplied 
*               entropy into a new seed which will be used to generate the following random numbers.
*
* @param[in]     pEntropy    Pointer to a 128-bit buffer containing the entropy.
*
* @return          Result of the operation.
*                   Std_ReturnType
*
* @pre         Driver must be initialized.
*
*/
FUNC (Std_ReturnType, CRYPTO_CODE) Crypto_Cse_ExtendPrngSeed
(
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) pEntropy
)
{
    VAR(Cse_ErrorCodeType, AUTOMATIC)eOutResponse  = CSE_ERC_GENERAL_ERROR;
    VAR(Std_ReturnType,    AUTOMATIC)RetVal        = (Std_ReturnType)E_NOT_OK;

    /* Check if CSE is not busy processing a request */
    if(((boolean)FALSE == Crypto_Cse_bCommandInProgress) && ((boolean)FALSE == Crypto_Cse_IsBusy()))
    {
        eOutResponse = Crypto_Cse_SendCommandExtendPrngSeed(pEntropy);
        RetVal       = Crypto_Cse_VerifyCseResponse(eOutResponse);
    }
    else
    {
        RetVal = (Std_ReturnType)CRYPTO_E_BUSY;
    }
    return RetVal;
}

#define CRYPTO_STOP_SEC_CODE
/**
* @violates @ref Crypto_Cse_c_REF_3 Violates MISRA 2004 Required Rule 19.15, #include preceded by non preproc directives.
* @violates @ref Crypto_Cse_c_REF_1 Violates MISRA 2004 Advisory Rule 19.1, Repeated include file MemMap.h.
*/
#include "Crypto_MemMap.h"

#ifdef __cplusplus
}
#endif

/** @} */
