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


#ifdef __cplusplus
extern "C"{
#endif

#include "Crypto.h"
#include "CryIf_Cbk.h"
#include "Det.h"
#include "Crypto_Impl.h"
/** @addtogroup G32A10xx_StdPeriphDriver
  @{
*/

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

/** @defgroup CRYPTO_Macros
  @{
*/
/*******************************************************************************
                    VENDOR ID & AUTOSAR VERSION INFO
*******************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define CRYPTO_VENDOR_ID                        0x00C1U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define CRYPTO_AR_RELEASE_MAJOR_VERSION         0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define CRYPTO_AR_RELEASE_MINOR_VERSION         0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define CRYPTO_AR_RELEASE_REVISION_VERSION      0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define CRYPTO_SW_MAJOR_VERSION                 0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define CRYPTO_SW_MINOR_VERSION                 0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define CRYPTO_SW_PATCH_VERSION                 0x00U
/**@} end of group CRYPTO_Macros */
/*******************************************************************************
                             VERSION CHECK
*******************************************************************************/
/* Make sure the vendor id is the same between Crypto.c and Crypto.h */
#if (CRYPTO_VENDOR_ID != CRYPTO_H_VENDOR_ID)
    #error "Vendor id mismatch between Crypto.c and Crypto.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Crypto.c and Crypto.h */
#if (CRYPTO_AR_RELEASE_MAJOR_VERSION != CRYPTO_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR major version number mismatch between Crypto.c and Crypto.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Crypto.c and Crypto.h */
#if (CRYPTO_AR_RELEASE_MINOR_VERSION != CRYPTO_H_AR_RELEASE_MINOR_VERSION)
    #error "AUTOSAR minor version number mismatch between Crypto.c and Crypto.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Crypto.c and Crypto.h */
#if (CRYPTO_AR_RELEASE_REVISION_VERSION != CRYPTO_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR revision version number mismatch between Crypto.c and Crypto.h"
#endif
/* Make sure the software major version number is the same between Crypto.c and Crypto.h */
#if (CRYPTO_SW_MAJOR_VERSION != CRYPTO_H_SW_MAJOR_VERSION)
    #error "Software major version number mismatch between Crypto.c and Crypto.h"
#endif
/* Make sure the software minor version number is the same between Crypto.c and Crypto.h */
#if (CRYPTO_SW_MINOR_VERSION != CRYPTO_H_SW_MINOR_VERSION)
    #error "Software minor version number mismatch between Crypto.c and Crypto.h"
#endif
/* Make sure the software patch version number is the same between Crypto.c and Crypto.h */
#if (CRYPTO_SW_PATCH_VERSION != CRYPTO_H_SW_PATCH_VERSION)
    #error "Software patch version number mismatch between Crypto.c and Crypto.h"
#endif
/* Make sure the vendor id is the same between Crypto.c and Crypto_Impl.h */
#if (CRYPTO_VENDOR_ID != CRYPTO_IMPL_H_VENDOR_ID)
    #error "Vendor id mismatch between Crypto.c and Crypto_Impl.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Crypto.c and Crypto_Impl.h */
#if (CRYPTO_AR_RELEASE_MAJOR_VERSION != CRYPTO_IMPL_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR major version number mismatch between Crypto.c and Crypto_Impl.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Crypto.c and Crypto_Impl.h */
#if (CRYPTO_AR_RELEASE_MINOR_VERSION != CRYPTO_IMPL_H_AR_RELEASE_MINOR_VERSION)
    #error "AUTOSAR minor version number mismatch between Crypto.c and Crypto_Impl.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Crypto.c and Crypto_Impl.h */
#if (CRYPTO_AR_RELEASE_REVISION_VERSION != CRYPTO_IMPL_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR revision version number mismatch between Crypto.c and Crypto_Impl.h"
#endif
/* Make sure the software major version number is the same between Crypto.c and Crypto_Impl.h */
#if (CRYPTO_SW_MAJOR_VERSION != CRYPTO_IMPL_H_SW_MAJOR_VERSION)
    #error "Software major version number mismatch between Crypto.c and Crypto_Impl.h"
#endif
/* Make sure the software minor version number is the same between Crypto.c and Crypto_Impl.h */
#if (CRYPTO_SW_MINOR_VERSION != CRYPTO_IMPL_H_SW_MINOR_VERSION)
    #error "Software minor version number mismatch between Crypto.c and Crypto_Impl.h"
#endif
/* Make sure the software patch version number is the same between Crypto.c and Crypto_Impl.h */
#if (CRYPTO_SW_PATCH_VERSION != CRYPTO_IMPL_H_SW_PATCH_VERSION)
    #error "Software patch version number mismatch between Crypto.c and Crypto_Impl.h"
#endif

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

    #if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    /* Make sure the AUTOSAR major version number is the same between Crypto.c and Det.h */
    #if (CRYPTO_AR_RELEASE_MAJOR_VERSION != DET_H_AR_RELEASE_MAJOR_VERSION)
        #error "AUTOSAR major version number mismatch between Crypto.c and Det.h"
    #endif
    /* Make sure the AUTOSAR minor version number is the same between Crypto.c and Det.h */
    #if (CRYPTO_AR_RELEASE_MINOR_VERSION != DET_H_AR_RELEASE_MINOR_VERSION)
        #error "AUTOSAR minor version number mismatch between Crypto.c and Det.h"
    #endif
    #endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
#endif

/*******************************************************************************
                                LOCAL CONSTANTS
*******************************************************************************/
/** @defgroup CRYPTO_Variable
  @{
*/
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)

#define CRYPTO_START_SEC_CONST_UNSPECIFIED
#include "Crypto_MemMap.h"

/** Information about how the Crypto_ProcessJob() API should handle the parameters */
static const Crypto_JobParametersType g_cryptoJobParameters[] =
{
    {   /* CRYPTO_HASH 0x00 */
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        0x0U,
        0x0U,
        (uint8)CRYPTO_OPERATIONMODE_UPDATE,
        0x0U,
        0x0U,
        (boolean)FALSE
    },
    {   /* CRYPTO_MACGENERATE 0x01 */
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        0x0U,
        0x0U,
        (uint8)CRYPTO_OPERATIONMODE_UPDATE,
        0x0U,
        0x0U,
        (boolean)FALSE
    },
    {   /* CRYPTO_MACVERIFY 0x02 */
        0x0U,
        0x0U,
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        (uint8)CRYPTO_OPERATIONMODE_UPDATE,
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        0x0U,
        (boolean)FALSE
    },
    {   /* CRYPTO_ENCRYPT 0x03 */
        CRYPTO_OPERATIONMODE_UPDATE_FINISH,
        0x0U,
        0x0U,
        (uint8)CRYPTO_OPERATIONMODE_UPDATE,
        0x0U,
        0x0U,
        (boolean)FALSE
    },
    {   /* CRYPTO_DECRYPT 0x04 */
        CRYPTO_OPERATIONMODE_UPDATE_FINISH,
        0x0U,
        0x0U,
        (uint8)CRYPTO_OPERATIONMODE_UPDATE,
        0x0U,
        0x0U,
        (boolean)FALSE
    },
    {   /* CRYPTO_AEADENCRYPT 0x05 */
        CRYPTO_OPERATIONMODE_UPDATE_FINISH,
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        0x0U,
        (uint8)CRYPTO_OPERATIONMODE_UPDATE,
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        0x0U,
        (boolean)FALSE
    },
    {   /* CRYPTO_AEADDECRYPT 0x06 */
        CRYPTO_OPERATIONMODE_UPDATE_FINISH,
        0x0U,
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        (uint8)CRYPTO_OPERATIONMODE_UPDATE,
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        (boolean)FALSE
    },
    {   /* CRYPTO_SIGNATUREGENERATE 0x07 */
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        0x0U,
        0x0U,
        (uint8)CRYPTO_OPERATIONMODE_UPDATE,
        0x0U,
        0x0U,
        (boolean)FALSE
    },
    {   /* CRYPTO_SIGNATUREVERIFY 0x08 */
        0x0U,
        0x0U,
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        (uint8)CRYPTO_OPERATIONMODE_UPDATE,
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        0x0U,
        (boolean)FALSE
    },
    {   /* CRYPTO_SECCOUNTERINCREMENT 0x09 */
        0x0U,
        0x0U,
        0x0U,
        0x0U,
        0x0U,
        0x0U,
        (boolean)FALSE
    },
    {   /* CRYPTO_SECCOUNTERREAD 0x0A */
        0x0U,
        0x0U,
        0x0U,
        0x0U,
        0x0U,
        0x0U,
        (boolean)FALSE
    },
    {    /* CRYPTO_RANDOMGENERATE 0x0B */
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        0x0U,
        0x0U,
        0x0U,
        0x0U,
        0x0U,
        (boolean)TRUE
    },
    {    /* CRYPTO_MPCMGENERATE 0x0C */
        (uint8)CRYPTO_OPERATIONMODE_FINISH,
        0x0U,
        0x0U,
        0x0U,
        0x0U,
        0x0U,
        (boolean)FALSE
    }
};

#define CRYPTO_STOP_SEC_CONST_UNSPECIFIED
#include "Crypto_MemMap.h"

#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */

/*******************************************************************************
                            GLOBAL VARIABLES
*******************************************************************************/

#define CRYPTO_START_SEC_VAR_INIT_UNSPECIFIED
#include "Crypto_MemMap.h"

/**
* Status of the Crypto Driver.
* CRYPTO_DRIVER_UNINIT:  The driver was not initialized, or the CSEc hardware module
*                        was not properly configured.
* CRYPTO_DRIVER_READY: The driver was initialized successfully.
*/
static VAR(Crypto_DriverStatusType, CRYPTO_VAR) g_cryptoDriverStatus = CRYPTO_DRIVER_UNINIT;

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

#if (CRYPTO_KEYS_CONFIGURED == 1U)
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_CopyKeyMaterial(
    VAR(uint32, AUTOMATIC) KeyIndex,
    VAR(uint32, AUTOMATIC) TargetKeyIndex);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateKeyId(
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_CONST) Job);

LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_MemCopy(
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) SrcPtr,
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) DestPtr,
    VAR(uint32, AUTOMATIC) Size);
#endif /* CRYPTO_KEYS_CONFIGURED == 1U */

LOCAL_INLINE FUNC(Crypto_ObjectStatusType, CRYPTO_CODE) Crypto_ValidateObjectId(
    VAR(uint32, AUTOMATIC) ObjectId);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateKeyElementCopy(
    VAR(Crypto_ElementStatusType, AUTOMATIC) SrcElementStatus,
    VAR(Crypto_ElementStatusType, AUTOMATIC) DestElementStatus);

LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_RestKeyElementCopy(
    VAR(uint32, AUTOMATIC) keyIndex,
    VAR(uint32, AUTOMATIC) targetKeyIndex);

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_CheckJobPreconditions(
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) Job,
    P2VAR(Crypto_ObjectStatusType, AUTOMATIC, CRYPTO_APPL_DATA) ObjStatusPtr);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateDriverStatus(
    CONST(uint8, AUTOMATIC) ServiceId);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateNullPointer(
     CONST(uint8, AUTOMATIC) ServiceId,
     P2CONST(void, AUTOMATIC, CRYPTO_APPL_CONST) Ptr);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateParamHandle(
     CONST(uint8, AUTOMATIC) ServiceId,
     CONST(Std_ReturnType, AUTOMATIC) HandleStatus);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateNotEqual(
     CONST(uint8, AUTOMATIC) ServiceId,
     CONST(uint32, AUTOMATIC) Value1,
     CONST(uint32, AUTOMATIC) Value2);

LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateJobPrimitive(
    VAR(uint32, AUTOMATIC) ObjectIndex,
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_CONST) Job);

LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateJobParameters(
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_CONST) Job);

LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateJobInputOutput(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode);

LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateInputPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode);

LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateSecondaryInputPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode);

LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateTertiaryInputPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode);

LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateOutputPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode);

LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateSecondaryOutputPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode);

LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateVerifyResultPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */

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

/*!
* @brief     32-bit byte swap (big-endian <-> little-endian for one word).
*
* @param     value: 32-bit word to swap.
*
* @retval    Byte-swapped 32-bit value.
*/
FUNC(uint32, CRYPTO_CODE) Crypto_Bswap32(VAR(uint32, AUTOMATIC) value)
{
    return (((value & 0xFF000000U) >> 24U) |
            ((value & 0x00FF0000U) >> 8U) |
            ((value & 0x0000FF00U) << 8U) |
            ((value & 0x000000FFU) << 24U));
}

/*!
* @brief     16-bit byte swap.
*
* @param     value: 16-bit halfword to swap.
*
* @retval    Byte-swapped 16-bit value.
*/
FUNC(uint16, CRYPTO_CODE) Crypto_Bswap16(VAR(uint16, AUTOMATIC) value)
{
    return (uint16)((((uint32)value & 0xFF00U) >> 8U) |
                    (((uint32)value & 0x00FFU) << 8U));
}

/*!
* @brief     Pack 4 bytes (big-endian order in memory: b0..b3 -> MSB..LSB of word).
*
* @param     bytes: Pointer to 4 input bytes (bytes[0] is MSB of the word).
*
* @retval    32-bit word; numeric value equals big-endian interpretation of the 4 bytes.
*/
FUNC(uint32, CRYPTO_CODE) Crypto_BeU32FromBytes(P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) bytes)
{
    return (((uint32)bytes[0] << 24U) |
            ((uint32)bytes[1] << 16U) |
            ((uint32)bytes[2] << 8U) |
            ((uint32)bytes[3]));
}

/*!
* @brief     Pack 4 bytes (little-endian order in memory: b0..b3 -> LSB..MSB of word).
*
* @param     bytes: Pointer to 4 input bytes (bytes[0] is LSB of the word).
*
* @retval    32-bit word assembled in little-endian byte order.
*/
FUNC(uint32, CRYPTO_CODE) Crypto_LeU32FromBytes(P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) bytes)
{
    return (((uint32)bytes[0]) |
            (((uint32)bytes[1]) << 8U) |
            (((uint32)bytes[2]) << 16U) |
            (((uint32)bytes[3]) << 24U));
}

/*!
* @brief     Store 32-bit word to 4 bytes (big-endian: MSB first at bytes[0]).
*
* @param     value: 32-bit word to store.
* @param     bytes: Output buffer; at least 4 bytes (bytes[0] is MSB).
*
* @retval    None
*/
FUNC(void, CRYPTO_CODE) Crypto_BeU32ToBytes(VAR(uint32, AUTOMATIC) value, P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) bytes)
{
    bytes[0] = (uint8)(value >> 24U);
    bytes[1] = (uint8)(value >> 16U);
    bytes[2] = (uint8)(value >> 8U);
    bytes[3] = (uint8)(value);
}

/*!
* @brief     Store 32-bit word to 4 bytes (little-endian: LSB first at bytes[0]).
*
* @param     value: 32-bit word to store.
* @param     bytes: Output buffer; at least 4 bytes (bytes[0] is LSB).
*
* @retval    None
*/
FUNC(void, CRYPTO_CODE) Crypto_LeU32ToBytes(VAR(uint32, AUTOMATIC) value, P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) bytes)
{
    bytes[0] = (uint8)(value);
    bytes[1] = (uint8)(value >> 8U);
    bytes[2] = (uint8)(value >> 16U);
    bytes[3] = (uint8)(value >> 24U);
}

/*!
* @brief     In-place byte swap for each element of a uint32 buffer.
*
* @param     words: Pointer to uint32 buffer modified in place.
* @param     wordCount: Number of uint32 elements in words.
*
* @retval    None
*/
FUNC(void, CRYPTO_CODE) Crypto_SwapU32BufferInPlace(P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) words, VAR(uint32, AUTOMATIC) wordCount)
{
    VAR(uint32, AUTOMATIC) n = 0u;
    for (n = 0u; n < wordCount; n++)
    {
        words[n] = Crypto_Bswap32(words[n]);
    }
}

/*!
* @brief     Copy uint32 buffer applying byte swap per word (src -> dst).
*
* @param     src: Source uint32 buffer (read-only).
* @param     dst: Destination uint32 buffer (must not overlap src for correct copy).
* @param     wordCount: Number of uint32 words to copy with per-word byte swap.
*
* @retval    None
*/
FUNC(void, CRYPTO_CODE) Crypto_CopyU32BufferWithBswap(P2CONST(uint32, AUTOMATIC, CRYPTO_APPL_CONST) src,
    P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) dst, VAR(uint32, AUTOMATIC) wordCount)
{
    VAR(uint32, AUTOMATIC) n = 0u;
    for (n = 0u; n < wordCount; n++)
    {
        dst[n] = Crypto_Bswap32(src[n]);
    }
}

/*!
 * @brief    Initialize the Crypto Driver
 */
FUNC(void, CRYPTO_CODE) Crypto_Init(const Crypto_ConfigType* configPtr)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;

    /* Initialize Crypto Driver if not already initialized */
    if (CRYPTO_DRIVER_UNINIT == g_cryptoDriverStatus)
    {
        result = Crypto_Impl_Init();
        if ((Std_ReturnType)E_OK != result)
        {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
            (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                  (uint8)CRYPTO_SID_INIT, (uint8)CRYPTO_E_INIT_FAILED);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
        }
        else
        {
            /* The Crypto Driver is in IDLE state once initialized successfully */
            g_cryptoDriverStatus = CRYPTO_DRIVER_READY;
        }
    }
    else
    {
        /* nothing */
    }
    (void) configPtr;
}

/*!
* @brief    This function generates the internal seed state using the provided entropy source.
*           Furthermore, this function can be used to update the seed state with new entropy.
* @details  This function is not supported
* @param[in]  CryptoKeyId   Identifier of the key for which a new seed shall be generated
* @param[in]  SeedPtr       Pointer to the memory location which contains the data to feed the seed
* @param[out] SeedLength    Contains the length of the seed in bytes
*
* @retval   E_OK: Request was successful
* @retval   E_NOT_OK: Request was failed
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_RandomSeed(
    VAR(uint32, AUTOMATIC) CryptoKeyId,
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) SeedPtr,
    VAR(uint32, AUTOMATIC) SeedLength)
{
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus  = {(Std_ReturnType)E_OK,0U};
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if ((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_RANDOM_SEED)) 
    {
        result = Crypto_ValidateNullPointer((uint8)CRYPTO_SID_RANDOM_SEED, SeedPtr);
    }
    else
    {
        /* nothing */
    }
    if(E_OK == result)
    {
        result = Crypto_ValidateNotEqual((uint8)CRYPTO_SID_RANDOM_SEED, SeedLength, 0U);
    }
    else
    {
        /* nothing */
    }
    if(E_OK == result)
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    {
        keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);
        if ((Std_ReturnType)E_OK != keyStatus.status)
        {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
            (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                  (uint8)CRYPTO_SID_RANDOM_SEED, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif
            result = (Std_ReturnType)E_NOT_OK;
        }
        else
        {
            /* Nothing to do, the function is not supported on this device. */
            (void)SeedPtr;
            (void)SeedLength;
        }
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    else
    {
        /* nothing */
    }
#endif
    return result;
}

/*!
* @brief        Set the key state to valid
*
* @param[in]    CryptoKeyId Identifier of the key which shall be set to valid
*
* @retval       E_OK: E_OK: Request successful
* @retval       E_NOT_OK: Request failed
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeySetValid(
    VAR(uint32, AUTOMATIC) CryptoKeyId)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;

#if (CRYPTO_KEYS_CONFIGURED == 0U)
    (void)CryptoKeyId;
#else
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus = {(Std_ReturnType)E_OK,0U};
    VAR(uint32, AUTOMATIC) keyIndex = 0U;

    /* If the key is valid, save the key index */
    keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);
    if ((Std_ReturnType)E_OK == keyStatus.status)
    {
        keyIndex = keyStatus.index;
    }
    else
    {
        /* nothing */
    }
    
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if ((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_KEY_SET_VALID)) 
    {
        result = (Std_ReturnType)E_OK;
    }
    else
    {
        /* nothing */
    }
    if(E_OK == result)
    {
        result = Crypto_ValidateParamHandle((uint8)CRYPTO_SID_KEY_SET_VALID, keyStatus.status);
    }
    else
    {
        /* nothing */
    }
    if(E_OK == result)
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    {
        /* Set the key to valid */
        Crypto_KeyList[keyIndex]->valid = 1U;
        result = (Std_ReturnType)E_OK;
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    else
    {
        /* nothing */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
#endif /* CRYPTO_KEYS_CONFIGURED == 0U */

    return result;
}

/*!
* @brief        Set the key state to valid
*
* @param[in]    CryptoKeyId Identifier of the key which shall be set to valid
*
* @retval       E_OK: E_OK: Request successful
* @retval       E_NOT_OK: Request failed
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeyValidSet(
    VAR(uint32, AUTOMATIC) CryptoKeyId)
{
    return Crypto_KeySetValid(CryptoKeyId);
}

/*!
* @brief    Get a key element of the key
* @details  This interface shall be used to get a key element of the key
*           identified by the CryptoKeyId and store the key element in the
*           memory location pointed by the result pointer.
*
*           Note: If the actual key element is directly mapped to flash memory,
*           there could be a bigger delay when calling this function
*           (synchronous operation).
*
* @param[in]    CryptoKeyId     Identifier of the key whose key element shall be returned
* @param[in]    KeyElementId    Identifier of the key element which shall be returned
* @param[out]   ResultPtr       Pointer of the buffer for the returned key element
* @param[inout] ResultLengthPtr Pointer to a memory location in which the length information is stored
*
* @retval   E_OK: E_OK: Request successful
* @retval   E_NOT_OK: Request failed
* @retval   CRYPTO_E_KEY_READ_FAIL: Request failed because read access was denied
* @retval   CRYPTO_E_KEY_NOT_AVAILABLE: Request failed because the key is not available
* @retval   CRYPTO_E_SMALL_BUFFER: The provided buffer is too small to store the result
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeyElementGet(
    VAR(uint32, AUTOMATIC) CryptoKeyId,
    VAR(uint32, AUTOMATIC) KeyElementId,
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) ResultPtr,
    P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) ResultLengthPtr)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (uint8)E_NOT_OK;

#if (CRYPTO_KEYS_CONFIGURED == 0U)
    (void)CryptoKeyId;
    (void)KeyElementId;
    (void)ResultPtr;
    (void)ResultLengthPtr;
#else
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus = {(Std_ReturnType)E_OK,0U};
    VAR(Crypto_ElementStatusType, AUTOMATIC) keyElementStatus = {(Std_ReturnType)E_OK,0U};

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if ((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_KEY_ELEMENT_GET))
    {
        if((Std_ReturnType)E_OK == Crypto_ValidateNullPointer((uint8)CRYPTO_SID_KEY_ELEMENT_GET, ResultPtr))
        {
            if((Std_ReturnType)E_OK == Crypto_ValidateNullPointer((uint8)CRYPTO_SID_KEY_ELEMENT_GET, ResultLengthPtr))
            {
                if((Std_ReturnType)E_OK == Crypto_ValidateNotEqual((uint8)CRYPTO_SID_KEY_ELEMENT_GET, *ResultLengthPtr, 0U))
                {
                    result = (uint8)E_OK;
                }
                else
                {
                    result = (uint8)E_NOT_OK;
                }
            }
            else
            {
                result = (uint8)E_NOT_OK;
            }
        }
        else
        {
            result = (uint8)E_NOT_OK;
        }
    }
    else
    {
        result = (uint8)E_NOT_OK;
    }
    if(E_OK == result)
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    {
        /* Check if the parameter CryptoKeyId is out of range */
        keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);
        if ((Std_ReturnType)E_OK != keyStatus.status)
        {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
            (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                  (uint8)CRYPTO_SID_KEY_ELEMENT_GET, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
        }
        else
        {
            /* Check if the parameter KeyElementId is out of range */
            keyElementStatus = Crypto_Impl_CheckKeyElementId(keyStatus.index, KeyElementId);
            if ((Std_ReturnType)E_OK != keyElementStatus.status)
            {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
                (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                      (uint8)CRYPTO_SID_KEY_ELEMENT_GET, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
            }
            else
            {
                /* Check if the key element allows read access */
                if (CRYPTO_RA_DENIED == Crypto_KeyElementList[keyElementStatus.index]->readAccess)
                {
                    result = (Std_ReturnType)CRYPTO_E_KEY_READ_FAIL;
                }
                /* Check if the buffer size is too small to store the result of the request */
                else if (*ResultLengthPtr < Crypto_KeyElementList[keyElementStatus.index]->actualSize)
                {
                    result = (Std_ReturnType)CRYPTO_E_SMALL_BUFFER;

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
                    (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                          (uint8)CRYPTO_SID_KEY_ELEMENT_GET, (uint8)CRYPTO_E_SMALL_BUFFER);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
                }
                else
                {
                    /* If the key element is not key material, copy it from the buffer */
                    Crypto_MemCopy(Crypto_KeyElementList[keyElementStatus.index]->data,
                                   ResultPtr,
                                   Crypto_KeyElementList[keyElementStatus.index]->actualSize);

                    *ResultLengthPtr = Crypto_KeyElementList[keyElementStatus.index]->actualSize;
                    result = (Std_ReturnType)E_OK;
                }
            }
        }
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    else
    {
        /* nothing */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */

#endif /* CRYPTO_KEYS_CONFIGURED == 0U */
    
    return result;
}

/*!
* @brief    Set the given key element bytes to the key
*
* @param[in]    CryptoKeyId     Identifier of the key whose key element shall be set
* @param[in]    KeyElementId    Identifier of the key element which shall be set
* @param[in]    KeyPtr          Pointer to the key data which shall be set as key element
* @param[in]    KeyLength       Length of the key element in bytes
*
* @retval   E_OK: E_OK: Request successful
* @retval   E_NOT_OK: Request failed
* @retval   CRYPTO_E_BUSY: Request failed, Crypto Driver Object is busy
* @retval   CRYPTO_E_KEY_WRITE_FAIL: Request failed because write access was denied
* @retval   CRYPTO_E_KEY_NOT_AVAILABLE: Request failed because the key is not available
* @retval   CRYPTO_E_KEY_SIZE_MISMATCH: Request failed, key element size does not match size of provided data
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeyElementSet(
    VAR(uint32, AUTOMATIC) CryptoKeyId,
    VAR(uint32, AUTOMATIC) KeyElementId,
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) KeyPtr,
    VAR(uint32, AUTOMATIC) KeyLength)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;

#if (CRYPTO_KEYS_CONFIGURED == 0U)
    (void)CryptoKeyId;
    (void)KeyElementId;
    (void)KeyPtr;
    (void)KeyLength;
#else
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus = {(Std_ReturnType)E_OK,0U};
    VAR(Crypto_ElementStatusType, AUTOMATIC) keyElementStatus = {(Std_ReturnType)E_OK,0U};

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_KEY_ELEMENT_SET))
    {
        if((Std_ReturnType)E_OK == Crypto_ValidateNullPointer((uint8)CRYPTO_SID_KEY_ELEMENT_SET, KeyPtr))
        {
            if((Std_ReturnType)E_OK == Crypto_ValidateNotEqual((uint8)CRYPTO_SID_KEY_ELEMENT_SET, KeyLength, 0U))
            {
                result = (Std_ReturnType)E_OK;
            }
            else
            {
                result = (Std_ReturnType)E_NOT_OK;
            }
        }
        else
        {
            result = (Std_ReturnType)E_NOT_OK;
        }   
    }
    else
    {
        result = (Std_ReturnType)E_NOT_OK;
    }
    if(E_OK == result)
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    {
        /* Check if the parameter CryptoKeyId is out of range */
        keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);
        if ((Std_ReturnType)E_OK != keyStatus.status)
        {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
            (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                  (uint8)CRYPTO_SID_KEY_ELEMENT_SET, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
        }
        else
        {
            /* Check if the parameter KeyElementId is out of range */
            keyElementStatus = Crypto_Impl_CheckKeyElementId(keyStatus.index, KeyElementId);
            if ((Std_ReturnType)E_OK != keyElementStatus.status)
            {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
                (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                      (uint8)CRYPTO_SID_KEY_ELEMENT_SET, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
            }
            else
            {
                /* Check the parameter KeyLength */
                if (((0U == Crypto_KeyElementList[keyElementStatus.index]->allowPartialAccess) &&
                     (KeyLength < Crypto_KeyElementList[keyElementStatus.index]->maxSize)) ||
                    (KeyLength > Crypto_KeyElementList[keyElementStatus.index]->maxSize))
                {
                    result = (Std_ReturnType)CRYPTO_E_KEY_SIZE_MISMATCH;
                }
                else if (CRYPTO_WA_DENIED == Crypto_KeyElementList[keyElementStatus.index]->writeAccess)
                {
                    /* The key does not allow write access */
                    result = (Std_ReturnType)CRYPTO_E_KEY_WRITE_FAIL;
                }
                else
                {
                    /* Set the key state to invalid when Crypto_KeyElementSet() is called */
                    Crypto_KeyList[keyStatus.index]->valid = 0U;

                    /* copy key element to the buffer. */
                    Crypto_MemCopy(KeyPtr, Crypto_KeyElementList[keyElementStatus.index]->data, KeyLength);
                    /* Store the size of the key element */
                    Crypto_KeyElementList[keyElementStatus.index]->actualSize = KeyLength;
                    result = (Std_ReturnType)E_OK;
                }
            }
        }
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    else
    {
        /* nothing */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
#endif /* CRYPTO_KEYS_CONFIGURED == 0U */
    return result;
}

/*!
* @brief    Generates new key material store it in the key identified by CryptoKeyId
*
* @param[in]  CryptoKeyId Identifier of the key which is to be updated with the generated value
*
* @retval   E_OK: Request was successful
* @retval   E_NOT_OK: Request was failed
* @retval   E_BUSY: Request failed, Crypto Driver Object is busy
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeyGenerate(VAR(uint32, AUTOMATIC) CryptoKeyId)
{
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus = {(Std_ReturnType)E_OK,0U};
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;

    keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_KEY_GENERATE))
    {
        if((Std_ReturnType)E_OK == Crypto_ValidateParamHandle((uint8)CRYPTO_SID_KEY_GENERATE, keyStatus.status))
        {
            result = (Std_ReturnType)E_OK;
        }
        else
        {
            result = (Std_ReturnType)E_NOT_OK;
        }
    }
    else
    {
        result = (Std_ReturnType)E_NOT_OK;
    }
    if(E_OK == result)
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    {
        if ((Std_ReturnType)E_OK == keyStatus.status)
        {
#if (CRYPTO_KEY_GEN_CONFIGURED == STD_ON)
            result = Crypto_Impl_GenerateRandomKey(CryptoKeyId);
#endif /* CRYPTO_KEY_GEN_CONFIGURED == STD_ON */
        }
        else
        {
            /* nothing */
        }
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    else
    {
        /* nothing */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    return result;
}

/*!
* @brief    Derives a new key by using the key elements in the given key identified by the CryptoKeyId
*
* @param[in]  CryptoKeyId       Identifier of the key which is used for key derivation
* @param[in]  TargetCryptoKeyId Identifier of the key which is used to store the derived key
*
* @retval   E_OK: Request was successful
* @retval   E_NOT_OK: Request was failed
* @retval   E_BUSY: Request failed, Crypto Driver Object is busy
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeyDerive(
    VAR(uint32, AUTOMATIC) CryptoKeyId,
    VAR(uint32, AUTOMATIC) TargetCryptoKeyId)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus = {(Std_ReturnType)E_OK,0U};
    VAR(Crypto_KeyStatusType, AUTOMATIC) targetKeyStatus = {(Std_ReturnType)E_OK,0U};

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if ((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_KEY_DERIVE))
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    {
        keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);
        if ((Std_ReturnType)E_OK != keyStatus.status)
        {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
            (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                  (uint8)CRYPTO_SID_KEY_DERIVE, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
        }
        else
        {
            targetKeyStatus = Crypto_Impl_CheckKeyId(TargetCryptoKeyId);
            if ((Std_ReturnType)E_OK != targetKeyStatus.status)
            {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
                (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                      (uint8)CRYPTO_SID_KEY_DERIVE, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
            }
            else
            {
                /* Nothing to do, the function is not supported on this device. */
            }
        }
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    else
    {
        /* nothing */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    return result;
}

/*!
* @brief    Copy a key with all its elements to another key in the same crypto driver
*
* @param[in] CryptoKeyId       Identifier of the key whose key element shall be the source element
* @param[in] TargetCryptoKeyId Identifier of the key whose key element shall be the destination element
*
* @retval   E_OK: Request was successful
* @retval   E_NOT_OK: Request was failed
* @retval   CRYPTO_E_KEY_READ_FAIL: Request failed, not allowed to extract key element
* @retval   CRYPTO_E_KEY_WRITE_FAIL: Request failed, not allowed to write key element
* @retval   CRYPTO_E_KEY_SIZE_MISMATCH: Request failed, key element sizes are not compatible
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeyCopy(
    VAR(uint32, AUTOMATIC) CryptoKeyId,
    VAR(uint32, AUTOMATIC) TargetCryptoKeyId)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;

#if (CRYPTO_KEYS_CONFIGURED == 0U)
    (void)CryptoKeyId;
    (void)TargetCryptoKeyId;
#else
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus = {(Std_ReturnType)E_OK,0U};
    VAR(Crypto_KeyStatusType, AUTOMATIC) targetKeyStatus = {(Std_ReturnType)E_OK,0U};
    VAR(uint32, AUTOMATIC) keyIndex = 0U;
    VAR(uint32, AUTOMATIC) targetKeyIndex = 0U;

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if ((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_KEY_COPY))
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    {
        /* Check if the parameter CryptoKeyId is out of range */
        keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);
        if ((Std_ReturnType)E_OK != keyStatus.status)
        {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
            (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                  (uint8)CRYPTO_SID_KEY_COPY, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
            result = (Std_ReturnType)E_NOT_OK;
        }
        else
        {
            /* Check if the parameter TargetCryptoKeyId is out of range */
            targetKeyStatus = Crypto_Impl_CheckKeyId(TargetCryptoKeyId);
            if ((Std_ReturnType)E_OK != targetKeyStatus.status)
            {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
                (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                      (uint8)CRYPTO_SID_KEY_COPY, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
                result = (Std_ReturnType)E_NOT_OK;
            }
            else
            {
                keyIndex = keyStatus.index;
                targetKeyIndex = targetKeyStatus.index;

                /* Check if the two keys have the same amount of key elements */
                if (Crypto_KeyList[keyIndex]->elementList->count <= Crypto_KeyList[targetKeyIndex]->elementList->count)
                {
                    /* Check if all the key elements are compatible, and load the key material if exists. */
                    result = Crypto_CopyKeyMaterial(keyIndex, targetKeyIndex);

                    /* Copy the rest of the key elements */
                    if ((Std_ReturnType)E_OK == result)
                    {
                        Crypto_RestKeyElementCopy(keyIndex, targetKeyIndex);
                    }
                    else
                    {
                        /* nothing */
                    }
                }
                else
                {
                    result = (Std_ReturnType)E_NOT_OK;
                }
            }
        }
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    else
    {
        /* nothing */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
#endif /* CRYPTO_KEYS_CONFIGURED == 0U */
    return result;
}

/*!
* @brief    Copy a key element to another key element in the same crypto driver
*
* @param[in]    CryptoKeyId         Identifier of the key whose key element shall be the source element
* @param[in]    KeyElementId        Identifier of the key element which shall be the source for the copy operation
* @param[out]   TargetCryptoKeyId   Identifier of the key whose key element shall be the destination element
* @param[inout] TargetKeyElementId  Identifier of the key element which shall be the destination for the copy operation
*
* @retval   E_OK: E_OK: Request successful
* @retval   E_NOT_OK: Request failed
* @retval   E_BUSY: Request failed, Crypto Driver Object is busy
* @retval   CRYPTO_E_KEY_READ_FAIL: Request failed, not allowed to extract key element
* @retval   CRYPTO_E_KEY_WRITE_FAIL: Request failed, not allowed to write key element
* @retval   CRYPTO_E_KEY_SIZE_MISMATCH: Request failed, key element sizes are not compatible
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeyElementCopy(
    VAR(uint32, AUTOMATIC) CryptoKeyId,
    VAR(uint32, AUTOMATIC) KeyElementId,
    VAR(uint32, AUTOMATIC) TargetCryptoKeyId,
    VAR(uint32, AUTOMATIC) TargetKeyElementId)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (uint8)E_NOT_OK;

#if (CRYPTO_KEYS_CONFIGURED == 0U)
    (void)CryptoKeyId;
    (void)KeyElementId;
    (void)TargetCryptoKeyId;
    (void)TargetKeyElementId;
#else
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus = {(Std_ReturnType)E_OK,0U};
    VAR(Crypto_KeyStatusType, AUTOMATIC) targetKeyStatus = {(Std_ReturnType)E_OK,0U};
    VAR(Crypto_ElementStatusType, AUTOMATIC) keyElementStatus = {(Std_ReturnType)E_OK,0U};
    VAR(Crypto_ElementStatusType, AUTOMATIC) targetKeyElementStatus = {(Std_ReturnType)E_OK,0U};

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if ((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_KEY_ELEMENT_COPY))
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    {
        keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);
        targetKeyStatus = Crypto_Impl_CheckKeyId(TargetCryptoKeyId);

        /* Check if the parameter CryptoKeyId and TargetCryptoKeyId are out of range */
        if (((Std_ReturnType)E_OK != keyStatus.status) ||
            ((Std_ReturnType)E_OK != targetKeyStatus.status))
        {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
            (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                  (uint8)CRYPTO_SID_KEY_ELEMENT_COPY, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
        }
        else
        {
            keyElementStatus = Crypto_Impl_CheckKeyElementId(keyStatus.index, KeyElementId);
            targetKeyElementStatus = Crypto_Impl_CheckKeyElementId(targetKeyStatus.index, TargetKeyElementId);

            /* Check the key elements */
            result = Crypto_ValidateKeyElementCopy(keyElementStatus, targetKeyElementStatus);
            if ((Std_ReturnType)E_OK == result)
            {
                /* If the key element is not key material, copy it to the buffer. */
                Crypto_MemCopy(Crypto_KeyElementList[keyElementStatus.index]->data,
                               Crypto_KeyElementList[targetKeyElementStatus.index]->data,
                               Crypto_KeyElementList[keyElementStatus.index]->actualSize);

                /* Store the actual size of the key element */
                Crypto_KeyElementList[targetKeyElementStatus.index]->actualSize =
                                Crypto_KeyElementList[keyElementStatus.index]->actualSize;
            }
            else
            {
                /* nothing */
            }
        }
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    else
    {
        /* nothing */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
#endif /* CRYPTO_KEYS_CONFIGURED == 0U */
    return result;
}

/*!
* @brief    Retrieve information which key elements are available in a given key
*
* @param[in]  CryptoKeyId            Identifier of the key whose available element ids shall be exported
* @param[in]  KeyElementIdsLengthPtr Pointer to the memory location in which the number of key elements in the given key is stored
* @param[out] KeyElementIdsPtr       Pointer to the array where the ids of the key elements shall be stored
*
* @retval   E_OK: Request was successful
* @retval   E_NOT_OK: Request was failed
* @retval   E_BUSY: Request failed, Crypto Driver Object is busy
* @retval   CRYPTO_E_SMALL_BUFFER: The provided buffer is too small to store the result
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeyElementIdsGet(
    VAR(uint32, AUTOMATIC) CryptoKeyId,
    P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) KeyElementIdsPtr,
    P2VAR(uint32, AUTOMATIC, CRYPTO_APPL_DATA) KeyElementIdsLengthPtr)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;

#if (CRYPTO_KEYS_CONFIGURED == 0U) 
    (void)CryptoKeyId;
    (void)KeyElementIdsPtr;
    (void)KeyElementIdsLengthPtr;
#else
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus = {(Std_ReturnType)E_OK,0U};
    VAR(uint32, AUTOMATIC) keyIndex = 0U;
    VAR(uint32, AUTOMATIC) elementIndex = 0U;

    /* If the key is valid, save the key index */
    keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);
    if ((Std_ReturnType)E_OK == keyStatus.status)
    {
        keyIndex = keyStatus.index;
    }
    else
    {
        /* nothing */
    }
    if ((NULL_PTR != KeyElementIdsLengthPtr) && (NULL_PTR != KeyElementIdsPtr))
    {
        result = E_OK;
    }
    else
    {
        /* nothing */
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if(E_OK == result)
    {
        result = Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_KEY_ELEMENT_IDS_GET);
    }
    else
    {
        /* nothing */
    }
    
    if(E_OK == result)
    {
        result = Crypto_ValidateParamHandle((uint8)CRYPTO_SID_KEY_ELEMENT_IDS_GET, keyStatus.status);
    }
    else
    {
        /* nothing */
    }
    if ((Std_ReturnType)E_OK == result)
    {
        /* Check the size of the buffer */
        if (Crypto_KeyList[keyIndex]->elementList->count > *KeyElementIdsLengthPtr)
        {
            (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                  (uint8)CRYPTO_SID_KEY_ELEMENT_IDS_GET, (uint8)CRYPTO_E_SMALL_BUFFER);
            result = (Std_ReturnType)CRYPTO_E_SMALL_BUFFER;
        }
        else
        {
            *KeyElementIdsLengthPtr = Crypto_KeyList[keyIndex]->elementList->count;

            while (elementIndex < Crypto_KeyList[keyIndex]->elementList->count)
            {
                KeyElementIdsPtr[elementIndex] =
                    Crypto_KeyElementList[Crypto_KeyList[keyIndex]->elementList->elements[elementIndex]]->elementId;
                elementIndex++;
            }
            result = (Std_ReturnType)E_OK;
        }
    }
    else
    {
        /* nothing */
    }
#else  
    if ((Std_ReturnType)E_OK == result)
    {
        *KeyElementIdsLengthPtr = Crypto_KeyList[keyIndex]->elementList->count;

        while (elementIndex < Crypto_KeyList[keyIndex]->elementList->count)
        {
            KeyElementIdsPtr[elementIndex] =
                Crypto_KeyElementList[Crypto_KeyList[keyIndex]->elementList->elements[elementIndex]]->elementId;
        }
        result = (Std_ReturnType)E_OK;
    }
    else
    {
        /* nothing */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
#endif /* CRYPTO_KEYS_CONFIGURED == 0U */
    return result;
}

/*!
* @brief    Calculates the public value for the key exchange and stores the public
*           key in the memory location pointed by the public value pointer.
*
* @param[in]    CryptoKeyId          Identifier of the key which shall be used for the key exchange protocol
* @param[out]   PublicValuePtr       Pointer to the data where the public value shall be stored
* @param[inout] PublicValueLengthPtr Pointer to the memory location in which the public value length information is stored
*
* @retval   E_OK: Request was successful
* @retval   E_NOT_OK: Request was failed
* @retval   E_BUSY: Request failed, Crypto Driver Object is busy
* @retval   CRYPTO_E_SMALL_BUFFER: The provided buffer is too small to store the result
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeyExchangeCalcPubVal(
    VAR(uint32, AUTOMATIC) CryptoKeyId,
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) PublicValuePtr,
    P2CONST(uint32, AUTOMATIC, CRYPTO_APPL_CONST) PublicValueLengthPtr)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_OK;

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus;
    keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);

    if((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_KEY_EXCHANGE_CALC_PUB_VAL))
    {
        if((Std_ReturnType)E_OK == Crypto_ValidateParamHandle((uint8)CRYPTO_SID_KEY_EXCHANGE_CALC_PUB_VAL, keyStatus.status))
        {
            if((Std_ReturnType)E_OK == Crypto_ValidateNullPointer((uint8)CRYPTO_SID_KEY_EXCHANGE_CALC_PUB_VAL, PublicValuePtr))
            {
                if((Std_ReturnType)E_OK == Crypto_ValidateNullPointer((uint8)CRYPTO_SID_KEY_EXCHANGE_CALC_PUB_VAL, PublicValueLengthPtr))
                {
                    if((Std_ReturnType)E_OK == Crypto_ValidateNotEqual((uint8)CRYPTO_SID_KEY_EXCHANGE_CALC_PUB_VAL, *PublicValueLengthPtr, 0U))
                    {
                        result = (Std_ReturnType)E_OK;
                    }
                    else
                    {
                        result = (Std_ReturnType)E_NOT_OK;
                    }
                }
                else
                {
                    result = (Std_ReturnType)E_NOT_OK;
                }
            }
            else
            {
                result = (Std_ReturnType)E_NOT_OK;
            }
        }
        else
        {
            result = (Std_ReturnType)E_NOT_OK;
        }
    }
    else
    {
        result = (Std_ReturnType)E_NOT_OK;
    }
    if(E_OK == result)
    {
        /* Nothing to do, the function is not supported on this device. */
        (void)PublicValuePtr;
        (void)PublicValueLengthPtr;
    }
    else
    {
        /* nothing */
    }
#else
    /* Nothing to do, the function is not supported on this device. */
    (void)CryptoKeyId;
    (void)PublicValuePtr;
    (void)PublicValueLengthPtr;
#endif
    return result;
}

/*!
* @brief    Calculates the shared secret key for the key exchange with the key material
*           of the key identified by the CryptoKeyId and the partner public key.
*
* @param[in] CryptoKeyId              Identifier of the key which shall be used for the key exchange protocol
* @param[in] PartnerPublicValuePtr    Pointer to the memory location which contains the partner's public value
* @param[in] PartnerPublicValueLength Length of the partner's public value in bytes
*
* @retval   E_OK: Request was successful
* @retval   E_NOT_OK: Request was failed
* @retval   E_BUSY: Request failed, Crypto Driver Object is busy
* @retval   CRYPTO_E_SMALL_BUFFER: The provided buffer is too small to store the result
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_KeyExchangeCalcSecret(
    VAR(uint32, AUTOMATIC) CryptoKeyId,
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) PartnerPublicValuePtr,
    VAR(uint32, AUTOMATIC) PartnerPublicValueLength)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_OK;

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    VAR(Crypto_KeyStatusType, AUTOMATIC) keyStatus;
    keyStatus = Crypto_Impl_CheckKeyId(CryptoKeyId);

    if((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_KEY_EXCHANGE_CALC_SECRET))
    {
        if((Std_ReturnType)E_OK == Crypto_ValidateParamHandle((uint8)CRYPTO_SID_KEY_EXCHANGE_CALC_SECRET, keyStatus.status))
        {
            if((Std_ReturnType)E_OK == Crypto_ValidateNullPointer((uint8)CRYPTO_SID_KEY_EXCHANGE_CALC_SECRET, PartnerPublicValuePtr))
            {
                if((Std_ReturnType)E_OK == Crypto_ValidateNotEqual((uint8)CRYPTO_SID_KEY_EXCHANGE_CALC_SECRET, PartnerPublicValueLength, 0U))
                {
                    result = (Std_ReturnType)E_OK;
                }
                else
                {
                    result = (Std_ReturnType)E_NOT_OK;
                }
            }
            else
            {
                result = (Std_ReturnType)E_NOT_OK;
            }
        }
        else
        {
            result = (Std_ReturnType)E_NOT_OK;
        }
    }
    else
    {
        result = (Std_ReturnType)E_NOT_OK;
    }
    if(E_OK == result)
    {
        /* Nothing to do, the function is not supported on this device. */
        (void)PartnerPublicValuePtr;
        (void)PartnerPublicValueLength;
    }
    else
    {
        /* nothing */
    }
#else
    /* Nothing to do, the function is not supported on this device. */
    (void)CryptoKeyId;
    (void)PartnerPublicValuePtr;
    (void)PartnerPublicValueLength;
#endif
    return result;
}

/*!
* @brief        Parses the certificate data stored in the key element CRYPTO_KE_CERT_DATA
*               and fills the key elements CRYPTO_KE_CERT_SIGNEDDATA,
*               CRYPTO_KE_CERT_PARSEDPUBLICKEY and CRYPTO_KE_CERT_SIGNATURE.
* @details      This function is not supported
*
* @param[in]    CryptoKeyId Identifier of the key which shall be parsed
*
* @retval   E_OK: Request successful
* @retval   E_NOT_OK: Request failed
* @retval   E_BUSY: Request failed, Crypto Driver Object is busy
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_CertificateParse(
    VAR(uint32, AUTOMATIC) CryptoKeyId)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_OK;

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    VAR(Crypto_KeyStatusType, AUTOMATIC) verifyKey;
    verifyKey = Crypto_Impl_CheckKeyId(CryptoKeyId);

    if((Std_ReturnType)E_NOT_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_CERTIFICATE_PARSE))
    {
        result = (Std_ReturnType)E_NOT_OK;
    }
    else if((Std_ReturnType)E_NOT_OK == Crypto_ValidateParamHandle((uint8)CRYPTO_SID_CERTIFICATE_PARSE, verifyKey.status))
    {
        result = (Std_ReturnType)E_NOT_OK;
    }
    else
    {
        /* nothing */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */

    (void)CryptoKeyId;
    return result;
}

/*!
* @brief    Verifies the certificate
* @details  This function is not supported
*
* @param[in]  CryptoKeyId       Identifier of the key which shall be used to
*                               validate the certificate
* @param[in]  VerifyCryptoKeyId Identifier of the key contain
* @param[out] VerifyPtr         Pointer to the memory location which will contain
*                               the result of the certificate verification
*
* @retval   E_OK: Request successful
* @retval   E_NOT_OK: Request failed
* @retval   E_BUSY: Request failed, Crypto Driver Object is busy
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_CertificateVerify(
    VAR(uint32, AUTOMATIC) CryptoKeyId,
    VAR(uint32, AUTOMATIC) VerifyCryptoKeyId,
    P2CONST(Crypto_VerifyResultType, AUTOMATIC, CRYPTO_APPL_DATA) VerifyPtr)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;
    VAR(Crypto_KeyStatusType, AUTOMATIC) verifyKey = {(Std_ReturnType)E_OK,0U};
    VAR(Crypto_KeyStatusType, AUTOMATIC) verifyTargetKey = {(Std_ReturnType)E_OK,0U};

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_CERTIFICATE_VERIFY))
    {
        if((Std_ReturnType)E_OK == Crypto_ValidateNullPointer((uint8)CRYPTO_SID_CERTIFICATE_VERIFY, VerifyPtr))
        {
            result = (Std_ReturnType)E_OK;
        }
        else
        {
            result = (Std_ReturnType)E_NOT_OK;
        }
    }
    else
    {
        result = (Std_ReturnType)E_NOT_OK;
    }
    if(E_OK == result)
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    {
        /* Check if the parameter CryptoKeyId and VerifyCryptoKeyId */
        verifyKey = Crypto_Impl_CheckKeyId(CryptoKeyId);
        verifyTargetKey = Crypto_Impl_CheckKeyId(VerifyCryptoKeyId);
        if (((Std_ReturnType)E_OK != verifyKey.status) ||
            ((Std_ReturnType)E_OK != verifyTargetKey.status))
        {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
            (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                  (uint8)CRYPTO_SID_CERTIFICATE_VERIFY, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
        }
        else
        {
            /* This function is not supported by hardware, return E_OK directly. */
            result = (Std_ReturnType)E_OK;
        }
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    else
    {
        /* nothing */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    (void)VerifyPtr;
    return result;
}

/*!
* @brief        Performs the crypto primitive given in the parameter
*
* @param[in]    ObjectId    Identifier of the Crypto Driver Object
* @param[in]    Job         Pointer to the job configuration
*
* @retval   E_OK: Request successful
* @retval   E_NOT_OK: Request failed
* @retval   CRYPTO_E_BUSY: Request failed, Crypto Driver Object is busy
* @retval   CRYPTO_E_KEY_NOT_VALID: Request failed, the key is not valid
* @retval   CRYPTO_E_KEY_SIZE_MISMATCH: Request failed, a key element has the wrong size
* @retval   CRYPTO_E_QUEUE_FULL: Request failed, the queue is full
* @retval   CRYPTO_E_ENTROPY_EXHAUSTION: Request failed, the entropy is exhausted
* @retval   CRYPTO_E_SMALL_BUFFER: The provided buffer is too small to store the result
* @retval   CRYPTO_E_COUNTER_OVERFLOW: The counter is overflowed
* @retval   CRYPTO_E_JOB_CANCELED: The service request failed because the synchronous job has been canceled
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ProcessJob(
    VAR(uint32, AUTOMATIC) ObjectId,
    P2VAR(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) Job)
{
    VAR(Crypto_ObjectStatusType, AUTOMATIC) objStatus = {(Std_ReturnType)E_OK,0U};

    objStatus = Crypto_ValidateObjectId(ObjectId);

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if ((Std_ReturnType)E_OK == Crypto_CheckJobPreconditions(Job, &objStatus))
    {
    #if (CRYPTO_KEYS_CONFIGURED == 1U)
        /* If the service requires a key, check if the key is valid first. */
        objStatus.status = Crypto_ValidateKeyId(Job);
    #endif /* CRYPTO_KEYS_CONFIGURED == 1U */
        if ((Std_ReturnType)E_OK == objStatus.status)
        {
            objStatus.status = Crypto_Impl_ProcessJob(objStatus.index, Job);
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    }
#else 
    {
    #if (CRYPTO_KEYS_CONFIGURED == 1U)
        if ((Std_ReturnType)E_OK == objStatus.status)
        {
            /* If the service requires a key, check if the key is valid first. */
            objStatus.status = Crypto_ValidateKeyId(Job);
    #endif /* CRYPTO_KEYS_CONFIGURED == 1U */
            if ((Std_ReturnType)E_OK == objStatus.status)
            {
                objStatus.status = Crypto_Impl_ProcessJob(objStatus.index, Job);
            }
            else
            {
                /* nothing */
            }

    #if (CRYPTO_KEYS_CONFIGURED == 1U)
        }
        else
        {
            /* nothing */
        }
    #endif /* CRYPTO_KEYS_CONFIGURED == 1U */
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    /* Additionally report runtime error CRYPTO_E_RE_SMALL_BUFFER if the buffer is too small */
    if ((Std_ReturnType)CRYPTO_E_SMALL_BUFFER == objStatus.status)
    {
        (void)Det_ReportRuntimeError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                                     (uint8)CRYPTO_SID_PROCESS_JOB, (uint8)CRYPTO_E_RE_SMALL_BUFFER);
    }
    else
    {
        /* nothing */
    }
    return objStatus.status;
}

/*!
* @brief        Remove the job from the queue and cancel the processing of the job if possible
*
* @param[in]    ObjectId    Identifier of the Crypto Driver Object
* @param[in]    JobInfo     Pointer to the job information
*
* @retval   E_OK: Request successful, job has been removed
* @retval   E_NOT_OK: Request failed, job couldn't be removed
* @retval   CRYPTO_E_JOB_CANCELED: The job has been cancelled but is still processed.
*                                  No results will be returned to the application.
*/
FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_CancelJob(
    VAR(uint32, AUTOMATIC) ObjectId,
    P2CONST(Crypto_JobInfoType, AUTOMATIC, CRYPTO_APPL_DATA) JobInfo)
{
    VAR(Crypto_ObjectStatusType, AUTOMATIC) objStatus = {(Std_ReturnType)E_OK,0};
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;
#endif
    objStatus = Crypto_ValidateObjectId(ObjectId);
    
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if((Std_ReturnType)E_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_CANCEL_JOB))
    {
        if((Std_ReturnType)E_OK == Crypto_ValidateNullPointer((uint8)CRYPTO_SID_CANCEL_JOB, JobInfo)) 
        {
            if((Std_ReturnType)E_OK == Crypto_ValidateParamHandle((uint8)CRYPTO_SID_CANCEL_JOB, objStatus.status))
            {
                result = (Std_ReturnType)E_OK;
            }
            else
            {
                result = (Std_ReturnType)E_NOT_OK;
            }
        }
        else
        {
            result = (Std_ReturnType)E_NOT_OK;
        }
    }
    else
    {
        result = (Std_ReturnType)E_NOT_OK;
    }
    if(E_OK == result)
    {
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */

        objStatus.status = Crypto_Impl_CancelJob(objStatus.index, JobInfo);

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    }
    else
    {
        objStatus.status = (Std_ReturnType)E_NOT_OK;
    }
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    return objStatus.status;
}

/*!
* @brief    If asynchronous job processing is configured and there are job
*           queues, the function is called cyclically to process queued jobs.
*/
FUNC(void, CRYPTO_CODE) Crypto_MainFunction(void)
{
    Crypto_Impl_MainFunction();
}

#if (STD_ON == CRYPTO_VERSION_INFO_API_ENABLE)
/*!
* @brief        Get the version information of the Crypto Driver
*
* @param[in]    VersionInfo Pointer to where to store the version information
*
* @return       None
*/
FUNC(void, CRYPTO_CODE) Crypto_GetVersionInfo(
    P2VAR(Std_VersionInfoType, AUTOMATIC, CRYPTO_APPL_DATA) VersionInfo)
{
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    if ((Std_ReturnType)E_OK == Crypto_ValidateNullPointer((uint8)CRYPTO_SID_GET_VERSION_INFO, VersionInfo))
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
    {
        VersionInfo->sw_major_version = (uint8)CRYPTO_H_SW_MAJOR_VERSION;
        VersionInfo->sw_minor_version = (uint8)CRYPTO_H_SW_MINOR_VERSION;
        VersionInfo->sw_patch_version = (uint8)CRYPTO_H_SW_PATCH_VERSION;
        VersionInfo->vendorID = (uint16)CRYPTO_H_VENDOR_ID;
        VersionInfo->moduleID = (uint16)CRYPTO_H_MODULE_ID;
    }
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
    else
    {
        /* nothing */
    }  
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
}
#endif /* STD_ON == CRYPTO_VERSION_INFO_API_ENABLE */

/*******************************************************************************
                        LOCAL FUNCTIONS
*******************************************************************************/
#if (CRYPTO_KEYS_CONFIGURED == 1U)
/*!
* @brief        The function is called by Crypto_KeyCopy() to check if all the
*               key elements are compatible, and it will load the key material.
*
* @param[in]    KeyIndex        Source key index
* @param[in]    TargetKeyIndex  Target key index
*
* @retval   E_OK: Request was successful
* @retval   E_NOT_OK: Request was failed
* @retval   CRYPTO_E_KEY_READ_FAIL: Cannot read source key element
* @retval   CRYPTO_E_KEY_WRITE_FAIL: Cannot write target key element
* @retval   CRYPTO_E_KEY_SIZE_MISMATCH: Size of the key elements not match
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_CopyKeyMaterial(
    VAR(uint32, AUTOMATIC) KeyIndex,
    VAR(uint32, AUTOMATIC) TargetKeyIndex)
{
    VAR(uint32, AUTOMATIC) element1 = 0U;
    VAR(uint32, AUTOMATIC) element2 = 0U;
    VAR(boolean, AUTOMATIC) found = (boolean)FALSE;
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_OK;

    /**
    * Loop through the source key and target key, check if all the key elements
    * are compatible. Additionally, store the index of the key material, the
    * index will be used later to store the key material.
    */
    element1 = 0U;
    while (element1 < Crypto_KeyList[KeyIndex]->elementList->count)
    {
        element2 = 0U;
        found = (boolean)FALSE;
        while ((element2 < Crypto_KeyList[TargetKeyIndex]->elementList->count) &&
               ((boolean)FALSE == found))
        {
            if (Crypto_KeyElementList[Crypto_KeyList[KeyIndex]->elementList->elements[element1]]->elementId ==
                Crypto_KeyElementList[Crypto_KeyList[TargetKeyIndex]->elementList->elements[element2]]->elementId)
            {
                found = (boolean)TRUE;
                if (CRYPTO_RA_DENIED ==
                    Crypto_KeyElementList[Crypto_KeyList[KeyIndex]->elementList->elements[element1]]->readAccess)
                {
                    result = (Std_ReturnType)CRYPTO_E_KEY_READ_FAIL;
                }
                else if (CRYPTO_WA_DENIED ==
                         Crypto_KeyElementList[Crypto_KeyList[TargetKeyIndex]->elementList->elements[element2]]->writeAccess)
                {
                    result = (Std_ReturnType)CRYPTO_E_KEY_WRITE_FAIL;
                }
                else if ((Crypto_KeyElementList[Crypto_KeyList[KeyIndex]->elementList->elements[element1]]->actualSize >
                          Crypto_KeyElementList[Crypto_KeyList[TargetKeyIndex]->elementList->elements[element2]]->maxSize) ||
                         ((Crypto_KeyElementList[Crypto_KeyList[KeyIndex]->elementList->elements[element1]]->actualSize !=
                           Crypto_KeyElementList[Crypto_KeyList[TargetKeyIndex]->elementList->elements[element2]]->maxSize) &&
                          (0U == Crypto_KeyElementList[Crypto_KeyList[TargetKeyIndex]->elementList->elements[element2]]->allowPartialAccess)))
                {
                    result = (Std_ReturnType)CRYPTO_E_KEY_SIZE_MISMATCH;
                }
                else
                {
                    result = (Std_ReturnType)E_OK;
                }
                if ((result == (Std_ReturnType)CRYPTO_E_KEY_READ_FAIL) || 
                    (result == (Std_ReturnType)CRYPTO_E_KEY_WRITE_FAIL) || 
                    (result == (Std_ReturnType)CRYPTO_E_KEY_SIZE_MISMATCH))
                {
                    break;
                }
                else
                {
                    /* nothing */
                }
            }
            else
            {
                /* nothing */
            }
            element2++;
        }

        /* No compatible key element found, get out of the loop and return error. */
        if (((boolean)FALSE == found) || ((Std_ReturnType)E_OK != result))
        {
            result = (Std_ReturnType)E_NOT_OK;
            break;
        }
        else
        {
            /* nothing */
        }
        element1++;
    }

    return result;
}

/*!
* @brief        Verify if the key which required by the job is valid
*
* @param[in]    Job The job to be verified
*
* @retval       E_OK: Verification is successful
* @retval       E_NOT_OK: The key does not exist
* @retval       CRYPTO_E_KEY_NOT_VALID: The key is not valid
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateKeyId(
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_CONST) Job)
{
    VAR(Crypto_KeyStatusType, AUTOMATIC) verifyKey = {(Std_ReturnType)E_OK,0U};
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_OK;

    /* Some crypto services do not require a key, so skip them and return E_OK directly. */
    if ((CRYPTO_RANDOMGENERATE != Job->jobPrimitiveInfo->primitiveInfo->service) &&
        (CRYPTO_HASH != Job->jobPrimitiveInfo->primitiveInfo->service) &&
        (CRYPTO_SECCOUNTERINCREMENT != Job->jobPrimitiveInfo->primitiveInfo->service) &&
        (CRYPTO_SECCOUNTERREAD != Job->jobPrimitiveInfo->primitiveInfo->service))
    {
        /* Verify if the key exists */
        verifyKey = Crypto_Impl_CheckKeyId(Job->cryptoKeyId);
        if ((Std_ReturnType)E_OK != verifyKey.status)
        {
            result = (Std_ReturnType)E_NOT_OK;
        }
        else
        {
            /* Verify if the key is valid */
            result = (0U == Crypto_KeyList[verifyKey.index]->valid) ?
                     (Std_ReturnType)CRYPTO_E_KEY_NOT_VALID : (Std_ReturnType)E_OK;
        }
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Memory copy
*
* @param[in]    SrcPtr  Source address
* @param[in]    DestPtr Destination address
* @param[in]    Size    Size to be copied
*
* @return       None
*/
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_MemCopy(
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_CONST) SrcPtr,
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) DestPtr,
    VAR(uint32, AUTOMATIC) Size)
{
    VAR(uint32, AUTOMATIC) i = 0U;

    if ((NULL_PTR != SrcPtr) && (NULL_PTR != DestPtr))
    {
        for (i = 0U; i < Size; i++)
        {
            DestPtr[i] = SrcPtr[i];
        }
    }
    else
    {
        /* nothing */
    }
}
#endif /* CRYPTO_KEYS_CONFIGURED == 1U */

/*!
* @brief        Verify if the given Crypto Driver Object is valid
*
* @param[in]    ObjectId Identifier of the Crypto Driver Object
*
* @return       Verification result
*/
LOCAL_INLINE FUNC(Crypto_ObjectStatusType, CRYPTO_CODE) Crypto_ValidateObjectId(
    VAR(uint32, AUTOMATIC) ObjectId)
{
    VAR(Crypto_ObjectStatusType, AUTOMATIC) verifyResult = {(Std_ReturnType)E_NOT_OK, 0U};
    VAR(uint32, AUTOMATIC) objectIndex = 0U;

    while (objectIndex < CRYPTO_DRIVER_OBJECT_NUMBER)
    {
        if (ObjectId == Crypto_ListObject[objectIndex]->objectId)
        {
            verifyResult.status = (Std_ReturnType)E_OK;
            verifyResult.index = objectIndex;
            break;
        }
        else
        {
            /* nothing */
        }
        objectIndex++;
    }
    return verifyResult;
}

/*!
* @brief    Verify the key elements
*
* @param[in] SrcElementStatus  Status of the source key element
* @param[in] DestElementStatus Status of the target key element
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateKeyElementCopy(
    VAR(Crypto_ElementStatusType, AUTOMATIC) SrcElementStatus,
    VAR(Crypto_ElementStatusType, AUTOMATIC) DestElementStatus)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_OK;

    /* Check if the parameter KeyElementId and TargetKeyElementId are out of range */
    if (((Std_ReturnType)E_OK != SrcElementStatus.status) ||
        ((Std_ReturnType)E_OK != DestElementStatus.status))
    {
#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
        (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                              (uint8)CRYPTO_SID_KEY_ELEMENT_COPY, (uint8)CRYPTO_E_PARAM_HANDLE);
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */
        result = (uint8)E_NOT_OK;
    }
    else
    {
        /* Check if the source key element allows read access */
        if (CRYPTO_RA_DENIED == Crypto_KeyElementList[SrcElementStatus.index]->readAccess)
        {
            result = (Std_ReturnType)CRYPTO_E_KEY_READ_FAIL;
        }
        /* Check if the target key element allows write access */
        else if (CRYPTO_WA_DENIED == Crypto_KeyElementList[DestElementStatus.index]->writeAccess)
        {
            result = (Std_ReturnType)CRYPTO_E_KEY_WRITE_FAIL;
        }
        /* Check the size of the key elements */
        else if ((Crypto_KeyElementList[SrcElementStatus.index]->actualSize >
                  Crypto_KeyElementList[DestElementStatus.index]->maxSize) ||
                 ((Crypto_KeyElementList[SrcElementStatus.index]->actualSize !=
                   Crypto_KeyElementList[DestElementStatus.index]->maxSize) &&
                  (0U == Crypto_KeyElementList[DestElementStatus.index]->allowPartialAccess)))
        {
            result = (Std_ReturnType)CRYPTO_E_KEY_SIZE_MISMATCH;
        }
        else
        {
            result = (Std_ReturnType)E_OK;
        }
    }
    return result;
}

/*!
* @brief    Copy the rest of the key elements 
*
* @param[in] keyIndex: source key index
* @param[in] targetKeyIndex: target key index
*/
LOCAL_INLINE FUNC(void, CRYPTO_CODE) Crypto_RestKeyElementCopy(
    VAR(uint32, AUTOMATIC) keyIndex,
    VAR(uint32, AUTOMATIC) targetKeyIndex)
{
    VAR(uint32, AUTOMATIC) element1 = 0U;
    VAR(uint32, AUTOMATIC) element2 = 0U;
    VAR(boolean, AUTOMATIC) found = (boolean)FALSE;
    while (element1 < Crypto_KeyList[keyIndex]->elementList->count)
    {
        found = (boolean)FALSE;
        element2 = 0U;
        while (((boolean)FALSE == found) && (element2 < Crypto_KeyList[targetKeyIndex]->elementList->count))
        {
            if ((Crypto_KeyElementList[Crypto_KeyList[keyIndex]->elementList->elements[element1]]->elementId ==
                 Crypto_KeyElementList[Crypto_KeyList[targetKeyIndex]->elementList->elements[element2]]->elementId))
            {
                found = (boolean)TRUE;
                Crypto_MemCopy(Crypto_KeyElementList[Crypto_KeyList[keyIndex]->elementList->elements[element1]]->data,
                               Crypto_KeyElementList[Crypto_KeyList[targetKeyIndex]->elementList->elements[element2]]->data,
                               Crypto_KeyElementList[Crypto_KeyList[keyIndex]->elementList->elements[element1]]->actualSize);

                Crypto_KeyElementList[Crypto_KeyList[targetKeyIndex]->elementList->elements[element2]]->actualSize =
                        Crypto_KeyElementList[Crypto_KeyList[keyIndex]->elementList->elements[element1]]->actualSize;
            }
            else
            {
                /* nothing */
            }
            element2++;
        }
        element1++;
    }
}

#if (STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE)
/*!
* @brief        Check job preconditions
*
* @param[in]    Job             Pointer to the job configuration
* @param[in]    ObjStatusPtr    Pointer to the object status
*
* @retval   E_OK: Request successful
* @retval   E_NOT_OK: Request failed
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_CheckJobPreconditions(
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) Job,
    P2VAR(Crypto_ObjectStatusType, AUTOMATIC, CRYPTO_APPL_DATA) ObjStatusPtr)
{
    VAR(Crypto_ReturnType, AUTOMATIC) verifyJobParams = CRYPTO_RET_OK;

    if((Std_ReturnType)E_NOT_OK == Crypto_ValidateDriverStatus((uint8)CRYPTO_SID_PROCESS_JOB))
    {
        ObjStatusPtr->status = (Std_ReturnType)E_NOT_OK;
    }
    else if((Std_ReturnType)E_NOT_OK == Crypto_ValidateNullPointer((uint8)CRYPTO_SID_PROCESS_JOB, Job))
    {
        ObjStatusPtr->status = (Std_ReturnType)E_NOT_OK;
    }
    else if((Std_ReturnType)E_NOT_OK == Crypto_ValidateParamHandle((uint8)CRYPTO_SID_PROCESS_JOB, ObjStatusPtr->status))
    {
        ObjStatusPtr->status = (Std_ReturnType)E_NOT_OK;
    }
    else if((Std_ReturnType)E_NOT_OK == Crypto_ValidateJobPrimitive(ObjStatusPtr->index, Job))
    {
        ObjStatusPtr->status = (Std_ReturnType)E_NOT_OK;
    }
    else
    {
        verifyJobParams = Crypto_ValidateJobParameters(Job);
        if (((Crypto_ReturnType)CRYPTO_RET_NULL_PTR == verifyJobParams) ||
            ((Crypto_ReturnType)CRYPTO_RET_INVALID_LEN == verifyJobParams))
        {
            ObjStatusPtr->status = (Std_ReturnType)E_NOT_OK;
        }
        else
        {
            /* nothing */
        }
    }
    return ObjStatusPtr->status;
}

/*!
* @brief        Check if the driver was initialzed
*
* @param[in]    ServiceId Service ID
*
* @retval   E_OK: Driver was initialized
* @retval   E_NOT_OK: Driver was not initialized
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateDriverStatus(
    CONST(uint8, AUTOMATIC) ServiceId)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_OK;

    if (CRYPTO_DRIVER_UNINIT == g_cryptoDriverStatus)
    {
        (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                              (uint8)ServiceId, (uint8)CRYPTO_E_UNINIT);
         result = (Std_ReturnType)E_NOT_OK;
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Check if the given pointer is null
*
* @param[in]    ServiceId Service ID
* @param[in]    Ptr Pointer to be verified
*
* @retval   E_OK: The given pointer is not null
* @retval   E_NOT_OK: The given pointer is null
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateNullPointer(
     CONST(uint8, AUTOMATIC) ServiceId,
     P2CONST(void, AUTOMATIC, CRYPTO_APPL_CONST) Ptr)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_OK;

    if (NULL_PTR == Ptr)
    {
        (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                              (uint8)ServiceId, (uint8)CRYPTO_E_PARAM_POINTER);
         result = (Std_ReturnType)E_NOT_OK;
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Check if the given handle status is valid
*
* @param[in]    ServiceId Service ID
* @param[in]    HandleStatus Handle status to be verified
*
* @retval   E_OK: The given handle status is valid
* @retval   E_NOT_OK: The given handle status is invalid
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateParamHandle(
     CONST(uint8, AUTOMATIC) ServiceId,
     CONST(Std_ReturnType, AUTOMATIC) HandleStatus)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_OK;

    if ((Std_ReturnType)E_NOT_OK == HandleStatus)
    {
        (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                              (uint8)ServiceId, (uint8)CRYPTO_E_PARAM_HANDLE);
         result = (Std_ReturnType)E_NOT_OK;
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Check if the given two values are not equal
*
* @param[in]    ServiceId Service ID
* @param[in]    Value1 The first value to be compared
* @param[in]    Value2 The second value to be compared
*
* @retval   E_OK: The given two value are not equal
* @retval   E_NOT_OK: The given two value are equal
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateNotEqual(
     CONST(uint8, AUTOMATIC) ServiceId,
     CONST(uint32, AUTOMATIC) Value1,
     CONST(uint32, AUTOMATIC) Value2)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_OK;

    if (Value1 == Value2)
    {
        (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                              (uint8)ServiceId, (uint8)CRYPTO_E_PARAM_VALUE);
         result = (Std_ReturnType)E_NOT_OK;
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Verify if the job primitive is supported by the Crypto Driver Object
*
* @param[in]    ObjectId    Index of the Crypto Driver Object
* @param[in]    Job         Pointer to the job configuration
*
* @retval       E_OK: Job primitive is supported
* @retval       E_NOT_OK: Job primitive is not supported
*/
LOCAL_INLINE FUNC(Std_ReturnType, CRYPTO_CODE) Crypto_ValidateJobPrimitive(
    VAR(uint32, AUTOMATIC) ObjectIndex,
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_CONST) Job)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;
    VAR(uint32, AUTOMATIC) primitiveIndex = 0U;

    while (primitiveIndex < Crypto_ListObject[ObjectIndex]->primitiveCount)
    {
        if ((Job->jobPrimitiveInfo->primitiveInfo->service ==
             Crypto_ListObject[ObjectIndex]->primitives[primitiveIndex].serviceInfo) &&
            (Job->jobPrimitiveInfo->primitiveInfo->algorithm.family ==
             Crypto_ListObject[ObjectIndex]->primitives[primitiveIndex].algoFamily) &&
            (Job->jobPrimitiveInfo->primitiveInfo->algorithm.mode ==
             Crypto_ListObject[ObjectIndex]->primitives[primitiveIndex].algoMode))
        {
            result = (Std_ReturnType)E_OK;
            break;
        }
        else
        {
            /* nothing */
        }
        primitiveIndex++;
    }

    if ((Std_ReturnType)E_NOT_OK == result)
    {
        (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                              (uint8)CRYPTO_SID_PROCESS_JOB, (uint8)CRYPTO_E_PARAM_HANDLE);
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Verify if the job's parameters are valid
*
* @param[in]    Job Pointer to the job configuration
*
* @retval       CRYPTO_RET_NOT_OK: Request failed, only SINGLECALL mode supported
* @retval       CRYPTO_RET_NULL_PTR: Null pointer
* @retval       CRYPTO_RET_INVALID_LEN: Invalid input or output length
* @retval       CRYPTO_RET_OK: Verification is successful
*/
LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateJobParameters(
    P2CONST(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_CONST) Job)
{
    VAR(Crypto_ReturnType, AUTOMATIC) result = CRYPTO_RET_OK;
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) jobInputOutput = &Job->jobPrimitiveInputOutput;
    CONST(Crypto_OperationModeType, AUTOMATIC) operationMode = jobInputOutput->mode;
    CONST(Crypto_ServiceInfoType, AUTOMATIC) serviceType = Job->jobPrimitiveInfo->primitiveInfo->service;

    result = Crypto_ValidateJobInputOutput(serviceType, jobInputOutput, operationMode);

    if ((Crypto_ReturnType)CRYPTO_RET_NULL_PTR == result)
    {
        (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                              (uint8)CRYPTO_SID_PROCESS_JOB, (uint8)CRYPTO_E_PARAM_POINTER);
    }
    else
    {
        /* nothing */
    }
    /* Check the length of the input/output buffers */
    if ((Crypto_ReturnType)CRYPTO_RET_INVALID_LEN == result)
    {
        (void)Det_ReportError((uint16)CRYPTO_H_MODULE_ID, (uint8)CRYPTO_INSTANCE_ID,
                              (uint8)CRYPTO_SID_PROCESS_JOB, (uint8)CRYPTO_E_PARAM_VALUE);
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Verify if the job's input parameters and output parameters are valid
*
* @param[in]    ServiceType     Service type of the job
* @param[in]    JobInputOutput  Pointer to the job's input output structure
* @param[in]    OperationMode   Operation mode of the job
*
* @retval       CRYPTO_RET_NOT_OK: Request failed, only SINGLECALL mode supported
* @retval       CRYPTO_RET_NULL_PTR: Null pointer
* @retval       CRYPTO_RET_INVALID_LEN: Invalid input or output length
* @retval       CRYPTO_RET_OK: Verification is successful
*/
LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateJobInputOutput(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode)
{
    VAR(Crypto_ReturnType, AUTOMATIC) result = CRYPTO_RET_OK;

    /* Check if the service supports only SINGLECALL mode */
    if (((boolean)TRUE == g_cryptoJobParameters[(uint8)ServiceType].singleCallOnly) &&
        (CRYPTO_OPERATIONMODE_SINGLECALL != OperationMode))
    {
        result = CRYPTO_RET_NOT_OK;
    }
    else
    {
        /* nothing */
    }
    /* Check all the input parameters and output parameters */
    if (CRYPTO_RET_OK == result)
    {
        result = Crypto_ValidateInputPtr(ServiceType, JobInputOutput, OperationMode);
    }
    else
    {
        /* nothing */
    }
    if (CRYPTO_RET_OK == result)
    {
        result = Crypto_ValidateSecondaryInputPtr(ServiceType, JobInputOutput, OperationMode);
    }
    else
    {
        /* nothing */
    }
    if (CRYPTO_RET_OK == result)
    {
        result = Crypto_ValidateTertiaryInputPtr(ServiceType, JobInputOutput, OperationMode);
    }
    else
    {
        /* nothing */
    }
    if (CRYPTO_RET_OK == result)
    {
        result = Crypto_ValidateOutputPtr(ServiceType, JobInputOutput, OperationMode);
    }
    else
    {
        /* nothing */
    }
    if (CRYPTO_RET_OK == result)
    {
        result = Crypto_ValidateSecondaryOutputPtr(ServiceType, JobInputOutput, OperationMode);
    }
    else
    {
        /* nothing */
    }
    if (CRYPTO_RET_OK == result)
    {
        result = Crypto_ValidateVerifyResultPtr(ServiceType, JobInputOutput, OperationMode);
    }
    else
    {
        /* nothing */
    }
    
    return result;
}

/*!
* @brief        Verify if the input pointer (and length) in the job are valid
*
* @param[in]    ServiceType     Service type of the job
* @param[in]    JobInputOutput  Pointer to the job's input output structure
* @param[in]    OperationMode   Operation mode of the job
*
* @retval       CRYPTO_RET_NULL_PTR: Input pointer is null
* @retval       CRYPTO_RET_INVALID_LEN: Invalid input length
* @retval       CRYPTO_RET_OK: Verification is successful
*/
LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateInputPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode)
{
    VAR(Crypto_ReturnType, AUTOMATIC) result = CRYPTO_RET_OK;

    /* Check the inputPtr and inputLength parameters */
    if (0x0U != ((uint8)OperationMode & (g_cryptoJobParameters[ServiceType].inputModeMask)))
    {
        result = (NULL_PTR == JobInputOutput->inputPtr) ? CRYPTO_RET_NULL_PTR : CRYPTO_RET_OK;
        if (CRYPTO_RET_OK == result)
        {
            result = (0U == JobInputOutput->inputLength) ? CRYPTO_RET_INVALID_LEN : CRYPTO_RET_OK;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    }
    
    return result;
}

/*!
* @brief        Verify if the secondary input pointer (and length) in the job are valid
*
* @param[in]    ServiceType     Service type of the job
* @param[in]    JobInputOutput  Pointer to the job's input output structure
* @param[in]    OperationMode   Operation mode of the job
*
* @retval       CRYPTO_RET_NULL_PTR: Input pointer is null
* @retval       CRYPTO_RET_INVALID_LEN: Invalid input length
* @retval       CRYPTO_RET_OK: Verification is successful
*/
LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateSecondaryInputPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode)
{
    VAR(Crypto_ReturnType, AUTOMATIC) result = CRYPTO_RET_OK;

    /* Check the secondaryInputPtr and secondaryInputLength parameters */
    if (0x0U != ((uint8)OperationMode & (g_cryptoJobParameters[ServiceType].secondaryInputModeMask)))
    {
        result = (NULL_PTR == JobInputOutput->secondaryInputPtr) ? CRYPTO_RET_NULL_PTR : CRYPTO_RET_OK;
        if (CRYPTO_RET_OK == result)
        {
            result = (0U == JobInputOutput->secondaryInputLength) ? CRYPTO_RET_INVALID_LEN : CRYPTO_RET_OK;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Verify if the tertiary input pointer (and length) in the job are valid
*
* @param[in]    ServiceType     Service type of the job
* @param[in]    JobInputOutput  Pointer to the job's input output structure
* @param[in]    OperationMode   Operation mode of the job
*
* @retval       CRYPTO_RET_NULL_PTR: Input pointer is null
* @retval       CRYPTO_RET_INVALID_LEN: Invalid input length
* @retval       CRYPTO_RET_OK: Verification is successful
*/
LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateTertiaryInputPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode)
{
    VAR(Crypto_ReturnType, AUTOMATIC) result = CRYPTO_RET_OK;

    /* Check the tertiaryInputPtr and tertiaryInputLength parameters */
    if (0x0U != ((uint8)OperationMode & (g_cryptoJobParameters[ServiceType].tertiaryInputModeMask)))
    {
        result = (NULL_PTR == JobInputOutput->tertiaryInputPtr) ? CRYPTO_RET_NULL_PTR : CRYPTO_RET_OK;
        if (CRYPTO_RET_OK == result)
        {
            result = (0U == JobInputOutput->tertiaryInputLength) ? CRYPTO_RET_INVALID_LEN : CRYPTO_RET_OK;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Verify if the output pointer (and length) in the job are valid
*
* @param[in]    ServiceType     Service type of the job
* @param[in]    JobInputOutput  Pointer to the job's input output structure
* @param[in]    OperationMode   Operation mode of the job
*
* @retval       CRYPTO_RET_NULL_PTR: Null pointer
* @retval       CRYPTO_RET_INVALID_LEN: Invalid output length
* @retval       CRYPTO_RET_OK: Verification is successful
*/
LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateOutputPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode)
{
    VAR(Crypto_ReturnType, AUTOMATIC) result = CRYPTO_RET_OK;

    /**
    * The outputPtr and outputLengthPtr must not be null pointers.
    * The outputLengthPtr must not point to a zero value.
    */
    if (0x0U != ((uint8)OperationMode & (g_cryptoJobParameters[ServiceType].outputModeMask)))
    {
        result = ((NULL_PTR == JobInputOutput->outputPtr) || (NULL_PTR == JobInputOutput->outputLengthPtr)) ?
                 CRYPTO_RET_NULL_PTR : CRYPTO_RET_OK;
        if (CRYPTO_RET_OK == result)
        {
            result = (0U == *(JobInputOutput->outputLengthPtr)) ? CRYPTO_RET_INVALID_LEN : CRYPTO_RET_OK;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Verify if the secondary output pointer (and length) in the job are valid
*
* @param[in]    ServiceType     Service type of the job
* @param[in]    JobInputOutput  Pointer to the job's input output structure
* @param[in]    OperationMode   Operation mode of the job
*
* @retval       CRYPTO_RET_NULL_PTR: Null pointer
* @retval       CRYPTO_RET_INVALID_LEN: Invalid output length
* @retval       CRYPTO_RET_OK: Verification is successful
*/
LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateSecondaryOutputPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode)
{
    VAR(Crypto_ReturnType, AUTOMATIC) result = CRYPTO_RET_OK;

    /**
    * The secondaryOutputPtr and secondaryOutputLengthPtr must not be null pointers.
    * The secondaryOutputLengthPtr must not point to a zero value.
    */
    if (0x0U != ((uint8)OperationMode & (g_cryptoJobParameters[ServiceType].secondaryOutputModeMask)))
    {
        result = ((NULL_PTR == JobInputOutput->secondaryOutputPtr) || (NULL_PTR == JobInputOutput->secondaryOutputLengthPtr)) ?
                 CRYPTO_RET_NULL_PTR : CRYPTO_RET_OK;
        if (CRYPTO_RET_OK == result)
        {
            result = (0U == *(JobInputOutput->secondaryOutputLengthPtr)) ? CRYPTO_RET_INVALID_LEN : CRYPTO_RET_OK;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    }
    return result;
}

/*!
* @brief        Verify if the parameter verifyPtr is null pointer in the job
*
* @param[in]    ServiceType     Service type of the job
* @param[in]    JobInputOutput  Pointer to the job's input output structure
* @param[in]    OperationMode   Operation mode of the job
*
* @retval       CRYPTO_RET_NULL_PTR: Null pointer
* @retval       CRYPTO_RET_OK: Verification is successful
*/
LOCAL_INLINE FUNC(Crypto_ReturnType, CRYPTO_CODE) Crypto_ValidateVerifyResultPtr(
    CONST(Crypto_ServiceInfoType, AUTOMATIC) ServiceType,
    CONSTP2CONST(Crypto_JobPrimitiveInputOutputType, AUTOMATIC, CRYPTO_APPL_CONST) JobInputOutput,
    CONST(Crypto_OperationModeType, AUTOMATIC) OperationMode)
{
    VAR(Crypto_ReturnType, AUTOMATIC) result = CRYPTO_RET_OK;

    /* Check the parameter verifyPtr */
    if (0x0U != ((uint8)OperationMode & (g_cryptoJobParameters[ServiceType].verifyPtrModeMask)))
    {
        result = (NULL_PTR == JobInputOutput->verifyPtr) ? CRYPTO_RET_NULL_PTR : CRYPTO_RET_OK;
    }
    else
    {
        /* nothing */
    }
    return result;
}
#endif /* STD_ON == CRYPTO_DEV_ERR_DETECT_ENABLE */

#define CRYPTO_STOP_SEC_CODE
#include "Crypto_MemMap.h"
/**@} end of group CRYPTO_Fuctions */

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