/**
  *
  * @file    apm32f4xx_dal_cryp.c
  * @brief   CRYP DAL module driver.
  *          This file provides firmware functions to manage the following
  *          functionalities of the Cryptography (CRYP) peripheral:
  *           + Initialization, de-initialization, set config and get config  functions
  *           + DES/TDES, AES processing functions
  *           + DMA callback functions
  *           + CRYP IRQ handler management
  *           + Peripheral State functions
  *
  *
  * @attention
  *
  * Redistribution and use in source and binary forms, with or without modification, 
  * are permitted provided that the following conditions are met:
  *
  * 1. Redistributions of source code must retain the above copyright notice,
  *    this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
  *    and/or other materials provided with the distribution.
  * 3. Neither the name of the copyright holder nor the names of its contributors
  *    may be used to endorse or promote products derived from this software without
  *    specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * The original code has been modified by Geehy Semiconductor.
  *
  * Copyright (c) 2016 STMicroelectronics.
  * Copyright (C) 2023 Geehy Semiconductor.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  *
  @verbatim
  ==============================================================================
                     ##### How to use this driver #####
  ==============================================================================
    [..]
      The CRYP DAL driver can be used in CRYP or TinyAES IP as follows:

      (#)Initialize the CRYP low level resources by implementing the DAL_CRYP_MspInit():
         (##) Enable the CRYP interface clock using __DAL_RCM_CRYP_CLK_ENABLE()or __DAL_RCM_AES_CLK_ENABLE for TinyAES IP
         (##) In case of using interrupts (e.g. DAL_CRYP_Encrypt_IT())
             (+++) Configure the CRYP interrupt priority using DAL_NVIC_SetPriority()
             (+++) Enable the CRYP IRQ handler using DAL_NVIC_EnableIRQ()
             (+++) In CRYP IRQ handler, call DAL_CRYP_IRQHandler()
         (##) In case of using DMA to control data transfer (e.g. DAL_CRYP_Encrypt_DMA())
             (+++) Enable the DMAx interface clock using __RCM_DMAx_CLK_ENABLE()
             (+++) Configure and enable two DMA streams one for managing data transfer from
                 memory to peripheral (input stream) and another stream for managing data
                 transfer from peripheral to memory (output stream)
             (+++) Associate the initialized DMA handle to the CRYP DMA handle
                 using  __DAL_LINKDMA()
             (+++) Configure the priority and enable the NVIC for the transfer complete
                 interrupt on the two DMA Streams. The output stream should have higher
                 priority than the input stream DAL_NVIC_SetPriority() and DAL_NVIC_EnableIRQ()

      (#)Initialize the CRYP according to the specified parameters :
         (##) The data type: 1-bit, 8-bit, 16-bit or 32-bit.
         (##) The key size: 128, 192 or 256.
         (##) The AlgoMode DES/ TDES Algorithm ECB/CBC or AES Algorithm ECB/CBC/CTR/GCM or CCM.
         (##) The initialization vector (counter). It is not used in ECB mode.
         (##) The key buffer used for encryption/decryption.
         (##) The Header used only in AES GCM and CCM Algorithm for authentication.
         (##) The HeaderSize The size of header buffer in word.
         (##) The B0 block is the first authentication block used only  in AES CCM mode.

      (#)Three processing (encryption/decryption) functions are available:
         (##) Polling mode: encryption and decryption APIs are blocking functions
              i.e. they process the data and wait till the processing is finished,
              e.g. DAL_CRYP_Encrypt & DAL_CRYP_Decrypt
         (##) Interrupt mode: encryption and decryption APIs are not blocking functions
              i.e. they process the data under interrupt,
              e.g. DAL_CRYP_Encrypt_IT & DAL_CRYP_Decrypt_IT
         (##) DMA mode: encryption and decryption APIs are not blocking functions
              i.e. the data transfer is ensured by DMA,
              e.g. DAL_CRYP_Encrypt_DMA & DAL_CRYP_Decrypt_DMA

      (#)When the processing function is called at first time after DAL_CRYP_Init()
         the CRYP peripheral is configured and processes the buffer in input.
         At second call, no need to Initialize the CRYP, user have to get current configuration via
         DAL_CRYP_GetConfig() API, then only  DAL_CRYP_SetConfig() is requested to set
         new parametres, finally user can  start encryption/decryption.

       (#)Call DAL_CRYP_DeInit() to deinitialize the CRYP peripheral.

       (#)To process a single message with consecutive calls to DAL_CRYP_Encrypt() or DAL_CRYP_Decrypt()
          without having to configure again the Key or the Initialization Vector between each API call,
          the field KeyIVConfigSkip of the initialization structure must be set to CRYP_KEYIVCONFIG_ONCE.
          Same is true for consecutive calls of DAL_CRYP_Encrypt_IT(), DAL_CRYP_Decrypt_IT(), DAL_CRYP_Encrypt_DMA()
          or DAL_CRYP_Decrypt_DMA().

    [..]
      The cryptographic processor supports following standards:
      (#) The data encryption standard (DES) and Triple-DES (TDES) supported only by CRYP1 IP:
         (##)64-bit data block processing
         (##) chaining modes supported :
             (+++)  Electronic Code Book(ECB)
             (+++)  Cipher Block Chaining (CBC)
         (##) keys length supported :64-bit, 128-bit and 192-bit.
      (#) The advanced encryption standard (AES) supported  by CRYP1 & TinyAES IP:
         (##)128-bit data block processing
         (##) chaining modes supported :
             (+++)  Electronic Code Book(ECB)
             (+++)  Cipher Block Chaining (CBC)
             (+++)  Counter mode (CTR)
             (+++)  Galois/counter mode (GCM/GMAC)
             (+++)  Counter with Cipher Block Chaining-Message(CCM)
         (##) keys length Supported :
             (+++) for CRYP1 IP: 128-bit, 192-bit and 256-bit.
             (+++) for TinyAES IP:  128-bit and 256-bit

    [..]  This section describes the AES Galois/counter mode (GCM) supported by both CRYP1 IP:
      (#)  Algorithm supported :
         (##) Galois/counter mode (GCM)
         (##) Galois message authentication code (GMAC) :is exactly the same as
              GCM algorithm composed only by an header.
      (#)  Four phases are performed in GCM :
         (##) Init phase: IP prepares the GCM hash subkey (H) and do the IV processing
         (##) Header phase: IP processes the Additional Authenticated Data (AAD), with hash
          computation only.
         (##) Payload phase: IP processes the plaintext (P) with hash computation + keystream
          encryption + data XORing. It works in a similar way for ciphertext (C).
         (##) Final phase: IP generates the authenticated tag (T) using the last block of data.
      (#)  structure of message construction in GCM is defined as below  :
         (##) 16 bytes Initial Counter Block (ICB)composed of IV and counter
         (##) The authenticated header A (also knows as Additional Authentication Data AAD)
          this part of the message is only authenticated, not encrypted.
         (##) The plaintext message P is both authenticated and encrypted as ciphertext.
          GCM standard specifies that ciphertext has same bit length as the plaintext.
         (##) The last block is composed of the length of A (on 64 bits) and the length of ciphertext
          (on 64 bits)

    [..]  This section describe The AES Counter with Cipher Block Chaining-Message
          Authentication Code (CCM) supported by both CRYP1 IP:
      (#)  Specific parameters for CCM  :

         (##) B0 block  : According to NIST Special Publication 800-38C,
            The first block B0 is formatted as follows, where l(m) is encoded in
            most-significant-byte first order(see below table 3)

              (+++)  Q: a bit string representation of the octet length of P (plaintext)
              (+++)  q The octet length of the binary representation of the octet length of the payload
              (+++)  A nonce (N), n The octet length of the where n+q=15.
              (+++)  Flags: most significant octet containing four flags for control information,
              (+++)  t The octet length of the MAC.
         (##) B1 block (header) : associated data length(a) concatenated with Associated Data (A)
              the associated data length expressed in bytes (a) defined as below:
            (+++)  If 0 < a < 216-28, then it is encoded as [a]16, i.e. two octets
            (+++)  If 216-28 < a < 232, then it is encoded as 0xff || 0xfe || [a]32, i.e. six octets
            (+++)  If 232 < a < 264, then it is encoded as 0xff || 0xff || [a]64, i.e. ten octets
         (##) CTRx block  : control blocks
            (+++) Generation of CTR1 from first block B0 information :
              equal to B0 with first 5 bits zeroed and most significant bits storing octet
              length of P also zeroed, then incremented by one ( see below Table 4)
            (+++) Generation of CTR0: same as CTR1 with bit[0] set to zero.

      (#)  Four phases are performed in CCM for CRYP1 IP:
         (##) Init phase: IP prepares the GCM hash subkey (H) and do the IV processing
         (##) Header phase: IP processes the Additional Authenticated Data (AAD), with hash
          computation only.
         (##) Payload phase: IP processes the plaintext (P) with hash computation + keystream
          encryption + data XORing. It works in a similar way for ciphertext (C).
         (##) Final phase: IP generates the authenticated tag (T) using the last block of data.

  *** Callback registration ***
  =============================================

  The compilation define  USE_DAL_CRYP_REGISTER_CALLBACKS when set to 1
  allows the user to configure dynamically the driver callbacks.
  Use Functions DAL_CRYP_RegisterCallback() or DAL_CRYP_RegisterXXXCallback()
  to register an interrupt callback.

  Function DAL_CRYP_RegisterCallback() allows to register following callbacks:
    (+) InCpltCallback     :  Input FIFO transfer completed callback.
    (+) OutCpltCallback    : Output FIFO transfer completed callback.
    (+) ErrorCallback      : callback for error detection.
    (+) MspInitCallback    : CRYP MspInit.
    (+) MspDeInitCallback  : CRYP MspDeInit.
  This function takes as parameters the DAL peripheral handle, the Callback ID
  and a pointer to the user callback function.

  Use function DAL_CRYP_UnRegisterCallback() to reset a callback to the default
  weak function.
  DAL_CRYP_UnRegisterCallback() takes as parameters the DAL peripheral handle,
  and the Callback ID.
  This function allows to reset following callbacks:
    (+) InCpltCallback     :  Input FIFO transfer completed callback.
    (+) OutCpltCallback    : Output FIFO transfer completed callback.
    (+) ErrorCallback      : callback for error detection.
    (+) MspInitCallback    : CRYP MspInit.
    (+) MspDeInitCallback  : CRYP MspDeInit.

  By default, after the DAL_CRYP_Init() and when the state is DAL_CRYP_STATE_RESET
  all callbacks are set to the corresponding weak functions :
  examples DAL_CRYP_InCpltCallback() , DAL_CRYP_OutCpltCallback().
  Exception done for MspInit and MspDeInit functions that are
  reset to the legacy weak function in the DAL_CRYP_Init()/ DAL_CRYP_DeInit() only when
  these callbacks are null (not registered beforehand).
  if not, MspInit or MspDeInit are not null, the DAL_CRYP_Init() / DAL_CRYP_DeInit()
  keep and use the user MspInit/MspDeInit functions (registered beforehand)

  Callbacks can be registered/unregistered in DAL_CRYP_STATE_READY state only.
  Exception done MspInit/MspDeInit callbacks that can be registered/unregistered
  in DAL_CRYP_STATE_READY or DAL_CRYP_STATE_RESET state,
  thus registered (user) MspInit/DeInit callbacks can be used during the Init/DeInit.
  In that case first register the MspInit/MspDeInit user callbacks
  using DAL_CRYP_RegisterCallback() before calling DAL_CRYP_DeInit()
  or DAL_CRYP_Init() function.

  When The compilation define USE_DAL_CRYP_REGISTER_CALLBACKS is set to 0 or
  not defined, the callback registration feature is not available and all callbacks
  are set to the corresponding weak functions.

  Table 1. Initial Counter Block (ICB)
          +-------------------------------------------------------+
          |       Initialization vector (IV)      |  Counter      |
          |----------------|----------------|-----------|---------|
         127              95                63            31       0


              Bit Number    Register           Contents
              ----------   ---------------       -----------
              127 ...96    CRYP_IV1R[31:0]     ICB[127:96]
              95  ...64    CRYP_IV1L[31:0]     B0[95:64]
              63 ... 32    CRYP_IV0R[31:0]     ICB[63:32]
              31 ... 0     CRYP_IV0L[31:0]     ICB[31:0], where 32-bit counter= 0x2

  Table 2.  GCM last block definition

          +-------------------------------------------------------------------+
          |  Bit[0]   |  Bit[32]           |  Bit[64]  | Bit[96]              |
          |-----------|--------------------|-----------|----------------------|
          |   0x0     | Header length[31:0]|     0x0   | Payload length[31:0] |
          |-----------|--------------------|-----------|----------------------|

  Table 3. B0 block
                Octet Number   Contents
                ------------   ---------
                0              Flags
                1 ... 15-q     Nonce N
                16-q ... 15    Q

            the Flags field is formatted as follows:

                Bit Number   Contents
                ----------   ----------------------
                7            Reserved (always zero)
                6            Adata
                5 ... 3      (t-2)/2
                2 ... 0      [q-1]3

 Table 4. CTRx block
                Bit Number    Register           Contents
                ----------   ---------------       -----------
                127 ...96    CRYP_IV1R[31:0]     B0[127:96], where Q length bits are set to 0, except for
                                                 bit 0 that is set to 1
                95  ...64    CRYP_IV1L[31:0]     B0[95:64]
                63 ... 32    CRYP_IV0R[31:0]     B0[63:32]
                31 ... 0     CRYP_IV0L[31:0]     B0[31:0], where flag bits set to 0

  @endverbatim
  *
  */

/* Includes ------------------------------------------------------------------*/
#include "apm32f4xx_dal.h"

/** @addtogroup APM32F4xx_DAL_Driver
  * @{
  */

#if defined (AES)  || defined (CRYP)

/** @defgroup CRYP CRYP
  * @brief CRYP DAL module driver.
  * @{
  */


#ifdef DAL_CRYP_MODULE_ENABLED

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup CRYP_Private_Defines
  * @{
  */
#define CRYP_TIMEOUT_KEYPREPARATION      82U         /*The latency of key preparation operation is 82 clock cycles.*/
#define CRYP_TIMEOUT_GCMCCMINITPHASE     299U        /*  The latency of  GCM/CCM init phase to prepare hash subkey is 299 clock cycles.*/
#define CRYP_TIMEOUT_GCMCCMHEADERPHASE   290U        /*  The latency of  GCM/CCM header phase is 290 clock cycles.*/

#define  CRYP_PHASE_READY                0x00000001U /*!< CRYP peripheral is ready for initialization. */
#define  CRYP_PHASE_PROCESS              0x00000002U /*!< CRYP peripheral is in processing phase */

#if defined(AES)
#define CRYP_OPERATINGMODE_ENCRYPT                   0x00000000U     /*!< Encryption mode(Mode 1)  */
#define CRYP_OPERATINGMODE_KEYDERIVATION             AES_CR_MODE_0   /*!< Key derivation mode  only used when performing ECB and CBC decryptions (Mode 2) */
#define CRYP_OPERATINGMODE_DECRYPT                   AES_CR_MODE_1   /*!< Decryption    (Mode 3)    */
#define CRYP_OPERATINGMODE_KEYDERIVATION_DECRYPT     AES_CR_MODE     /*!< Key derivation and decryption only used when performing ECB and CBC decryptions (Mode 4) */
#define CRYP_PHASE_INIT                              0x00000000U        /*!< GCM/GMAC (or CCM) init phase */
#define CRYP_PHASE_HEADER                            AES_CR_GCMPH_0     /*!< GCM/GMAC or CCM header phase */
#define CRYP_PHASE_PAYLOAD                           AES_CR_GCMPH_1     /*!< GCM(/CCM) payload phase      */
#define CRYP_PHASE_FINAL                             AES_CR_GCMPH       /*!< GCM/GMAC or CCM  final phase */
#else  /* CRYP */
#define CRYP_PHASE_INIT                              0x00000000U             /*!< GCM/GMAC (or CCM) init phase */
#define CRYP_PHASE_HEADER                            CRYP_CTRL_GCM_CCMPH_0     /*!< GCM/GMAC or CCM header phase */
#define CRYP_PHASE_PAYLOAD                           CRYP_CTRL_GCM_CCMPH_1     /*!< GCM(/CCM) payload phase      */
#define CRYP_PHASE_FINAL                             CRYP_CTRL_GCM_CCMPH       /*!< GCM/GMAC or CCM  final phase */
#define CRYP_OPERATINGMODE_ENCRYPT                   0x00000000U             /*!< Encryption mode   */
#define CRYP_OPERATINGMODE_DECRYPT                   CRYP_CTRL_ALGODIRSEL         /*!< Decryption        */
#endif /* End CRYP or  AES */

/*  CTR1 information to use in CCM algorithm */
#define CRYP_CCM_CTR1_0                  0x07FFFFFFU
#define CRYP_CCM_CTR1_1                  0xFFFFFF00U
#define CRYP_CCM_CTR1_2                  0x00000001U


/**
  * @}
  */


/* Private macro -------------------------------------------------------------*/
/** @addtogroup CRYP_Private_Macros
  * @{
  */

#if defined(CRYP)

#define CRYP_SET_PHASE(__HANDLE__, __PHASE__)  do{(__HANDLE__)->Instance->CTRL &= (uint32_t)(~CRYP_CTRL_GCM_CCMPH);\
                                                        (__HANDLE__)->Instance->CTRL |= (uint32_t)(__PHASE__);\
                                                       }while(0)

#define DAL_CRYP_FIFO_FLUSH(__HANDLE__) ((__HANDLE__)->Instance->CTRL |=  CRYP_CTRL_FFLUSH)

#else /*AES*/
#define CRYP_SET_PHASE(__HANDLE__, __PHASE__)  do{(__HANDLE__)->Instance->CTRL &= (uint32_t)(~AES_CR_GCMPH);\
                                                        (__HANDLE__)->Instance->CTRL |= (uint32_t)(__PHASE__);\
                                                       }while(0)
#endif /* End AES or CRYP*/


/**
  * @}
  */

/* Private struct -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @addtogroup CRYP_Private_Functions_prototypes
  * @{
  */

static void CRYP_SetDMAConfig(CRYP_HandleTypeDef *hcryp, uint32_t inputaddr, uint16_t Size, uint32_t outputaddr);
static void CRYP_DMAInCplt(DMA_HandleTypeDef *hdma);
static void CRYP_DMAOutCplt(DMA_HandleTypeDef *hdma);
static void CRYP_DMAError(DMA_HandleTypeDef *hdma);
static void CRYP_SetKey(CRYP_HandleTypeDef *hcryp, uint32_t KeySize);
static void CRYP_AES_IT(CRYP_HandleTypeDef *hcryp);
#if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)|| defined (AES)
static DAL_StatusTypeDef CRYP_GCMCCM_SetHeaderPhase(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
static void CRYP_GCMCCM_SetPayloadPhase_IT(CRYP_HandleTypeDef *hcryp);
static void CRYP_GCMCCM_SetHeaderPhase_IT(CRYP_HandleTypeDef *hcryp);
static DAL_StatusTypeDef CRYP_GCMCCM_SetHeaderPhase_DMA(CRYP_HandleTypeDef *hcryp);
static void CRYP_Workaround(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
static DAL_StatusTypeDef CRYP_AESGCM_Process_DMA(CRYP_HandleTypeDef *hcryp);
static DAL_StatusTypeDef CRYP_AESGCM_Process_IT(CRYP_HandleTypeDef *hcryp);
static DAL_StatusTypeDef CRYP_AESGCM_Process(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
static DAL_StatusTypeDef CRYP_AESCCM_Process(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
static DAL_StatusTypeDef CRYP_AESCCM_Process_IT(CRYP_HandleTypeDef *hcryp);
static DAL_StatusTypeDef CRYP_AESCCM_Process_DMA(CRYP_HandleTypeDef *hcryp);
#endif /* AES or GCM CCM defined*/
static void CRYP_AES_ProcessData(CRYP_HandleTypeDef *hcrypt, uint32_t Timeout);
static DAL_StatusTypeDef CRYP_AES_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
static DAL_StatusTypeDef CRYP_AES_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
static DAL_StatusTypeDef CRYP_AES_Decrypt_IT(CRYP_HandleTypeDef *hcryp);
static DAL_StatusTypeDef CRYP_AES_Encrypt_IT(CRYP_HandleTypeDef *hcryp);
static DAL_StatusTypeDef CRYP_AES_Decrypt_DMA(CRYP_HandleTypeDef *hcryp);
#if defined (CRYP)
static void CRYP_TDES_IT(CRYP_HandleTypeDef *hcryp);
#if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)
static DAL_StatusTypeDef CRYP_WaitOnIFEMFlag(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
#endif /* GCM CCM defined*/
static DAL_StatusTypeDef CRYP_WaitOnBUSYFlag(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
static DAL_StatusTypeDef CRYP_WaitOnOFNEFlag(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
static DAL_StatusTypeDef CRYP_TDES_Process(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
#else /*AES*/
static DAL_StatusTypeDef CRYP_WaitOnCCFlag(CRYP_HandleTypeDef *hcryp, uint32_t Timeout);
#endif /* End CRYP or AES */

/**
  * @}
  */

/* Exported functions ---------------------------------------------------------*/

/** @defgroup CRYP_Exported_Functions CRYP Exported Functions
  * @{
  */


/** @defgroup CRYP_Exported_Functions_Group1 Initialization and de-initialization functions
  *  @brief    Initialization and Configuration functions.
  *
@verbatim
  ========================================================================================
     ##### Initialization, de-initialization and Set and Get configuration functions #####
  ========================================================================================
    [..]  This section provides functions allowing to:
      (+) Initialize the CRYP
      (+) DeInitialize the CRYP
      (+) Initialize the CRYP MSP
      (+) DeInitialize the CRYP MSP
      (+) configure CRYP (DAL_CRYP_SetConfig) with the specified parameters in the CRYP_ConfigTypeDef
          Parameters which are configured in This section are :
          (+) Key size
          (+) Data Type : 32,16, 8 or 1bit
          (+) AlgoMode :
              - for CRYP1 IP :
                 ECB and CBC in DES/TDES Standard
                 ECB,CBC,CTR,GCM/GMAC and CCM in AES Standard.
              - for TinyAES2 IP, only ECB,CBC,CTR,GCM/GMAC and CCM in AES Standard are supported.
      (+) Get CRYP configuration (DAL_CRYP_GetConfig) from the specified parameters in the CRYP_HandleTypeDef


@endverbatim
  * @{
  */


/**
  * @brief  Initializes the CRYP according to the specified
  *         parameters in the CRYP_ConfigTypeDef and creates the associated handle.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
DAL_StatusTypeDef DAL_CRYP_Init(CRYP_HandleTypeDef *hcryp)
{
  /* Check the CRYP handle allocation */
  if (hcryp == NULL)
  {
    return DAL_ERROR;
  }

  /* Check parameters */
  ASSERT_PARAM(IS_CRYP_KEYSIZE(hcryp->Init.KeySize));
  ASSERT_PARAM(IS_CRYP_DATATYPE(hcryp->Init.DataType));
  ASSERT_PARAM(IS_CRYP_ALGORITHM(hcryp->Init.Algorithm));
  ASSERT_PARAM(IS_CRYP_INIT(hcryp->Init.KeyIVConfigSkip));

#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
  if (hcryp->State == DAL_CRYP_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hcryp->Lock = DAL_UNLOCKED;

    hcryp->InCpltCallback  = DAL_CRYP_InCpltCallback;  /* Legacy weak InCpltCallback   */
    hcryp->OutCpltCallback = DAL_CRYP_OutCpltCallback; /* Legacy weak OutCpltCallback  */
    hcryp->ErrorCallback   = DAL_CRYP_ErrorCallback;   /* Legacy weak ErrorCallback    */

    if (hcryp->MspInitCallback == NULL)
    {
      hcryp->MspInitCallback = DAL_CRYP_MspInit; /* Legacy weak MspInit  */
    }

    /* Init the low level hardware */
    hcryp->MspInitCallback(hcryp);
  }
#else
  if (hcryp->State == DAL_CRYP_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hcryp->Lock = DAL_UNLOCKED;

    /* Init the low level hardware */
    DAL_CRYP_MspInit(hcryp);
  }
#endif /* (USE_DAL_CRYP_REGISTER_CALLBACKS) */

  /* Set the key size(This bit field is don't care in the DES or TDES modes) data type and Algorithm */
#if defined (CRYP)

  MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_DTSEL | CRYP_CTRL_KSIZESEL | CRYP_CTRL_ALGOMSEL,
             hcryp->Init.DataType | hcryp->Init.KeySize | hcryp->Init.Algorithm);

#else /*AES*/

  MODIFY_REG(hcryp->Instance->CTRL, AES_CR_DATATYPE | AES_CR_KEYSIZE | AES_CR_CHMOD,
             hcryp->Init.DataType | hcryp->Init.KeySize | hcryp->Init.Algorithm);

#endif  /* End AES or CRYP*/

  /* Reset Error Code field */
  hcryp->ErrorCode = DAL_CRYP_ERROR_NONE;

  /* Change the CRYP state */
  hcryp->State = DAL_CRYP_STATE_READY;

  /* Set the default CRYP phase */
  hcryp->Phase = CRYP_PHASE_READY;

  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  De-Initializes the CRYP peripheral.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
DAL_StatusTypeDef DAL_CRYP_DeInit(CRYP_HandleTypeDef *hcryp)
{
  /* Check the CRYP handle allocation */
  if (hcryp == NULL)
  {
    return DAL_ERROR;
  }

  /* Set the default CRYP phase */
  hcryp->Phase = CRYP_PHASE_READY;

  /* Reset CrypInCount and CrypOutCount */
  hcryp->CrypInCount = 0;
  hcryp->CrypOutCount = 0;
  hcryp->CrypHeaderCount = 0;

  /* Disable the CRYP peripheral clock */
  __DAL_CRYP_DISABLE(hcryp);

#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)

  if (hcryp->MspDeInitCallback == NULL)
  {
    hcryp->MspDeInitCallback = DAL_CRYP_MspDeInit; /* Legacy weak MspDeInit  */
  }
  /* DeInit the low level hardware */
  hcryp->MspDeInitCallback(hcryp);

#else

  /* DeInit the low level hardware: CLOCK, NVIC.*/
  DAL_CRYP_MspDeInit(hcryp);

#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */

  /* Change the CRYP state */
  hcryp->State = DAL_CRYP_STATE_RESET;

  /* Release Lock */
  __DAL_UNLOCK(hcryp);

  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  Configure the CRYP according to the specified
  *         parameters in the CRYP_ConfigTypeDef
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure
  * @param  pConf: pointer to a CRYP_ConfigTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
DAL_StatusTypeDef DAL_CRYP_SetConfig(CRYP_HandleTypeDef *hcryp, CRYP_ConfigTypeDef *pConf)
{
  /* Check the CRYP handle allocation */
  if ((hcryp == NULL) || (pConf == NULL))
  {
    return DAL_ERROR;
  }

  /* Check parameters */
  ASSERT_PARAM(IS_CRYP_KEYSIZE(pConf->KeySize));
  ASSERT_PARAM(IS_CRYP_DATATYPE(pConf->DataType));
  ASSERT_PARAM(IS_CRYP_ALGORITHM(pConf->Algorithm));

  if (hcryp->State == DAL_CRYP_STATE_READY)
  {
    /* Change the CRYP state */
    hcryp->State = DAL_CRYP_STATE_BUSY;

    /* Process locked */
    __DAL_LOCK(hcryp);

    /* Set  CRYP parameters  */
    hcryp->Init.DataType   = pConf->DataType;
    hcryp->Init.pKey       = pConf->pKey;
    hcryp->Init.Algorithm  = pConf->Algorithm;
    hcryp->Init.KeySize    = pConf->KeySize;
    hcryp->Init.pInitVect  = pConf->pInitVect;
    hcryp->Init.Header     = pConf->Header;
    hcryp->Init.HeaderSize = pConf->HeaderSize;
    hcryp->Init.B0         = pConf->B0;
    hcryp->Init.DataWidthUnit = pConf->DataWidthUnit;
    hcryp->Init.KeyIVConfigSkip = pConf->KeyIVConfigSkip;
    hcryp->Init.HeaderWidthUnit = pConf->HeaderWidthUnit;

    /* Set the key size(This bit field is don't care in the DES or TDES modes) data type, AlgoMode and operating mode*/
#if defined (CRYP)

    MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_DTSEL | CRYP_CTRL_KSIZESEL | CRYP_CTRL_ALGOMSEL,
               hcryp->Init.DataType | hcryp->Init.KeySize | hcryp->Init.Algorithm);

#else /*AES*/
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_DATATYPE | AES_CR_KEYSIZE | AES_CR_CHMOD,
               hcryp->Init.DataType | hcryp->Init.KeySize | hcryp->Init.Algorithm);

    /*clear error flags*/
    __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_ERR_CLEAR);

#endif  /* End AES or CRYP */

    /* Process Unlocked */
    __DAL_UNLOCK(hcryp);

    /* Reset Error Code field */
    hcryp->ErrorCode = DAL_CRYP_ERROR_NONE;

    /* Change the CRYP state */
    hcryp->State = DAL_CRYP_STATE_READY;

    /* Set the default CRYP phase */
    hcryp->Phase = CRYP_PHASE_READY;

    /* Return function status */
    return DAL_OK;
  }
  else
  {
    /* Process Unlocked */
    __DAL_UNLOCK(hcryp);

    /* Busy error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_BUSY;
    return DAL_ERROR;
  }
}

/**
  * @brief  Get CRYP Configuration parameters in associated handle.
  * @param  pConf: pointer to a CRYP_ConfigTypeDef structure
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
DAL_StatusTypeDef DAL_CRYP_GetConfig(CRYP_HandleTypeDef *hcryp, CRYP_ConfigTypeDef *pConf)
{
  /* Check the CRYP handle allocation */
  if ((hcryp == NULL) || (pConf == NULL))
  {
    return DAL_ERROR;
  }

  if (hcryp->State == DAL_CRYP_STATE_READY)
  {
    /* Change the CRYP state */
    hcryp->State = DAL_CRYP_STATE_BUSY;

    /* Process locked */
    __DAL_LOCK(hcryp);

    /* Get  CRYP parameters  */
    pConf->DataType        = hcryp->Init.DataType;
    pConf->pKey            = hcryp->Init.pKey;
    pConf->Algorithm       = hcryp->Init.Algorithm;
    pConf->KeySize         = hcryp->Init.KeySize ;
    pConf->pInitVect       = hcryp->Init.pInitVect;
    pConf->Header          = hcryp->Init.Header ;
    pConf->HeaderSize      = hcryp->Init.HeaderSize;
    pConf->B0              = hcryp->Init.B0;
    pConf->DataWidthUnit   = hcryp->Init.DataWidthUnit;
    pConf->KeyIVConfigSkip = hcryp->Init.KeyIVConfigSkip;
    pConf->HeaderWidthUnit = hcryp->Init.HeaderWidthUnit;

    /* Process Unlocked */
    __DAL_UNLOCK(hcryp);

    /* Change the CRYP state */
    hcryp->State = DAL_CRYP_STATE_READY;

    /* Return function status */
    return DAL_OK;
  }
  else
  {
    /* Process Unlocked */
    __DAL_UNLOCK(hcryp);

    /* Busy error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_BUSY;
    return DAL_ERROR;
  }
}
/**
  * @brief  Initializes the CRYP MSP.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval None
  */
__weak void DAL_CRYP_MspInit(CRYP_HandleTypeDef *hcryp)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hcryp);

  /* NOTE : This function should not be modified, when the callback is needed,
            the DAL_CRYP_MspInit can be implemented in the user file
   */
}

/**
  * @brief  DeInitializes CRYP MSP.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval None
  */
__weak void DAL_CRYP_MspDeInit(CRYP_HandleTypeDef *hcryp)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hcryp);

  /* NOTE : This function should not be modified, when the callback is needed,
            the DAL_CRYP_MspDeInit can be implemented in the user file
   */
}

#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
/**
  * @brief  Register a User CRYP Callback
  *         To be used instead of the weak predefined callback
  * @param hcryp cryp handle
  * @param CallbackID ID of the callback to be registered
  *        This parameter can be one of the following values:
  *          @arg @ref DAL_CRYP_INPUT_COMPLETE_CB_ID Input FIFO transfer completed callback ID
  *          @arg @ref DAL_CRYP_OUTPUT_COMPLETE_CB_ID Output FIFO transfer completed callback ID
  *          @arg @ref DAL_CRYP_ERROR_CB_ID Error callback ID
  *          @arg @ref DAL_CRYP_MSPINIT_CB_ID MspInit callback ID
  *          @arg @ref DAL_CRYP_MSPDEINIT_CB_ID MspDeInit callback ID
  * @param pCallback pointer to the Callback function
  * @retval status
  */
DAL_StatusTypeDef DAL_CRYP_RegisterCallback(CRYP_HandleTypeDef *hcryp, DAL_CRYP_CallbackIDTypeDef CallbackID,
                                            pCRYP_CallbackTypeDef pCallback)
{
  DAL_StatusTypeDef status = DAL_OK;

  if (pCallback == NULL)
  {
    /* Update the error code */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_INVALID_CALLBACK;

    return DAL_ERROR;
  }
  /* Process locked */
  __DAL_LOCK(hcryp);

  if (hcryp->State == DAL_CRYP_STATE_READY)
  {
    switch (CallbackID)
    {
      case DAL_CRYP_INPUT_COMPLETE_CB_ID :
        hcryp->InCpltCallback = pCallback;
        break;

      case DAL_CRYP_OUTPUT_COMPLETE_CB_ID :
        hcryp->OutCpltCallback = pCallback;
        break;

      case DAL_CRYP_ERROR_CB_ID :
        hcryp->ErrorCallback = pCallback;
        break;

      case DAL_CRYP_MSPINIT_CB_ID :
        hcryp->MspInitCallback = pCallback;
        break;

      case DAL_CRYP_MSPDEINIT_CB_ID :
        hcryp->MspDeInitCallback = pCallback;
        break;

      default :
        /* Update the error code */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_INVALID_CALLBACK;
        /* Return error status */
        status =  DAL_ERROR;
        break;
    }
  }
  else if (hcryp->State == DAL_CRYP_STATE_RESET)
  {
    switch (CallbackID)
    {
      case DAL_CRYP_MSPINIT_CB_ID :
        hcryp->MspInitCallback = pCallback;
        break;

      case DAL_CRYP_MSPDEINIT_CB_ID :
        hcryp->MspDeInitCallback = pCallback;
        break;

      default :
        /* Update the error code */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_INVALID_CALLBACK;
        /* Return error status */
        status =  DAL_ERROR;
        break;
    }
  }
  else
  {
    /* Update the error code */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_INVALID_CALLBACK;
    /* Return error status */
    status =  DAL_ERROR;
  }

  /* Release Lock */
  __DAL_UNLOCK(hcryp);

  return status;
}

/**
  * @brief  Unregister an CRYP Callback
  *         CRYP callback is redirected to the weak predefined callback
  * @param hcryp cryp handle
  * @param CallbackID ID of the callback to be unregistered
  *        This parameter can be one of the following values:
  *          @arg @ref DAL_CRYP_INPUT_COMPLETE_CB_ID Input FIFO transfer completed callback ID
  *          @arg @ref DAL_CRYP_OUTPUT_COMPLETE_CB_ID Output FIFO transfer completed callback ID
  *          @arg @ref DAL_CRYP_ERROR_CB_ID Error callback ID
  *          @arg @ref DAL_CRYP_MSPINIT_CB_ID MspInit callback ID
  *          @arg @ref DAL_CRYP_MSPDEINIT_CB_ID MspDeInit callback ID
  * @retval status
  */
DAL_StatusTypeDef DAL_CRYP_UnRegisterCallback(CRYP_HandleTypeDef *hcryp, DAL_CRYP_CallbackIDTypeDef CallbackID)
{
  DAL_StatusTypeDef status = DAL_OK;

  /* Process locked */
  __DAL_LOCK(hcryp);

  if (hcryp->State == DAL_CRYP_STATE_READY)
  {
    switch (CallbackID)
    {
      case DAL_CRYP_INPUT_COMPLETE_CB_ID :
        hcryp->InCpltCallback = DAL_CRYP_InCpltCallback;  /* Legacy weak  InCpltCallback  */
        break;

      case DAL_CRYP_OUTPUT_COMPLETE_CB_ID :
        hcryp->OutCpltCallback = DAL_CRYP_OutCpltCallback;         /* Legacy weak OutCpltCallback       */
        break;

      case DAL_CRYP_ERROR_CB_ID :
        hcryp->ErrorCallback = DAL_CRYP_ErrorCallback;           /* Legacy weak ErrorCallback        */
        break;

      case DAL_CRYP_MSPINIT_CB_ID :
        hcryp->MspInitCallback = DAL_CRYP_MspInit;
        break;

      case DAL_CRYP_MSPDEINIT_CB_ID :
        hcryp->MspDeInitCallback = DAL_CRYP_MspDeInit;
        break;

      default :
        /* Update the error code */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_INVALID_CALLBACK;
        /* Return error status */
        status =  DAL_ERROR;
        break;
    }
  }
  else if (hcryp->State == DAL_CRYP_STATE_RESET)
  {
    switch (CallbackID)
    {
      case DAL_CRYP_MSPINIT_CB_ID :
        hcryp->MspInitCallback = DAL_CRYP_MspInit;
        break;

      case DAL_CRYP_MSPDEINIT_CB_ID :
        hcryp->MspDeInitCallback = DAL_CRYP_MspDeInit;
        break;

      default :
        /* Update the error code */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_INVALID_CALLBACK;
        /* Return error status */
        status =  DAL_ERROR;
        break;
    }
  }
  else
  {
    /* Update the error code */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_INVALID_CALLBACK;
    /* Return error status */
    status =  DAL_ERROR;
  }

  /* Release Lock */
  __DAL_UNLOCK(hcryp);

  return status;
}
#endif /* USE_DAL_UART_REGISTER_CALLBACKS */
/**
  * @}
  */

/** @defgroup CRYP_Exported_Functions_Group2  Encrypt Decrypt functions
  *  @brief   processing functions.
  *
@verbatim
  ==============================================================================
                      ##### Encrypt Decrypt  functions #####
  ==============================================================================
    [..]  This section provides API allowing to Encrypt/Decrypt Data following
          Standard DES/TDES or AES, and Algorithm configured by the user:
      (+) Standard DES/TDES only supported by CRYP1 IP, below list of Algorithm supported :
           - Electronic Code Book(ECB)
           - Cipher Block Chaining (CBC)
      (+) Standard AES  supported by CRYP1 IP & TinyAES, list of Algorithm supported:
           - Electronic Code Book(ECB)
           - Cipher Block Chaining (CBC)
           - Counter mode (CTR)
           - Cipher Block Chaining (CBC)
           - Counter mode (CTR)
           - Galois/counter mode (GCM)
           - Counter with Cipher Block Chaining-Message(CCM)
    [..]  Three processing functions are available:
      (+) Polling mode : DAL_CRYP_Encrypt & DAL_CRYP_Decrypt
      (+) Interrupt mode : DAL_CRYP_Encrypt_IT & DAL_CRYP_Decrypt_IT
      (+) DMA mode : DAL_CRYP_Encrypt_DMA & DAL_CRYP_Decrypt_DMA

@endverbatim
  * @{
  */


/**
  * @brief  Encryption mode.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Input: Pointer to the input buffer (plaintext)
  * @param  Size: Length of the plaintext buffer in word.
  * @param  Output: Pointer to the output buffer(ciphertext)
  * @param  Timeout: Specify Timeout value
  * @retval DAL status
  */
DAL_StatusTypeDef DAL_CRYP_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
                                   uint32_t Timeout)
{
  uint32_t algo;
  DAL_StatusTypeDef status;

  if (hcryp->State == DAL_CRYP_STATE_READY)
  {
    /* Change state Busy */
    hcryp->State = DAL_CRYP_STATE_BUSY;

    /* Process locked */
    __DAL_LOCK(hcryp);

    /*  Reset CrypInCount, CrypOutCount and Initialize pCrypInBuffPtr and pCrypOutBuffPtr parameters*/
    hcryp->CrypInCount = 0U;
    hcryp->CrypOutCount = 0U;
    hcryp->pCrypInBuffPtr = Input;
    hcryp->pCrypOutBuffPtr = Output;

    /*  Calculate Size parameter in Byte*/
    if (hcryp->Init.DataWidthUnit == CRYP_DATAWIDTHUNIT_WORD)
    {
      hcryp->Size = Size * 4U;
    }
    else
    {
      hcryp->Size = Size;
    }

#if defined (CRYP)
    /* Set Encryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGODIRSEL, CRYP_OPERATINGMODE_ENCRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & CRYP_CTRL_ALGOMSEL;

    switch (algo)
    {
      case CRYP_DES_ECB:
      case CRYP_DES_CBC:
      case CRYP_TDES_ECB:
      case CRYP_TDES_CBC:

        /*Set Key */
        hcryp->Instance->K1L = *(uint32_t *)(hcryp->Init.pKey);
        hcryp->Instance->K1R = *(uint32_t *)(hcryp->Init.pKey + 1);
        if ((hcryp->Init.Algorithm == CRYP_TDES_ECB) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->K2L = *(uint32_t *)(hcryp->Init.pKey + 2);
          hcryp->Instance->K2R = *(uint32_t *)(hcryp->Init.pKey + 3);
          hcryp->Instance->K3L = *(uint32_t *)(hcryp->Init.pKey + 4);
          hcryp->Instance->K3R = *(uint32_t *)(hcryp->Init.pKey + 5);
        }

        /*Set Initialization Vector (IV)*/
        if ((hcryp->Init.Algorithm == CRYP_DES_CBC) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
          hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
        }

        /* Flush FIFO */
        DAL_CRYP_FIFO_FLUSH(hcryp);

        /* Set the phase */
        hcryp->Phase = CRYP_PHASE_PROCESS;

        /* Statrt DES/TDES encryption process */
        status = CRYP_TDES_Process(hcryp, Timeout);
        break;

      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        /* AES encryption */
        status = CRYP_AES_Encrypt(hcryp, Timeout);
        break;
        #if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)
      case CRYP_AES_GCM:

        /* AES GCM encryption */
        status = CRYP_AESGCM_Process(hcryp, Timeout);

        break;

      case CRYP_AES_CCM:

        /* AES CCM encryption */
        status = CRYP_AESCCM_Process(hcryp, Timeout);
        break;
        #endif /* GCM CCM defined*/
      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
    }

#else /*AES*/

    /* Set the operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_ENCRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & AES_CR_CHMOD;

    switch (algo)
    {

      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        /* AES encryption */
        status = CRYP_AES_Encrypt(hcryp, Timeout);
        break;

      case CRYP_AES_GCM_GMAC:

        /* AES GCM encryption */
        status = CRYP_AESGCM_Process(hcryp, Timeout) ;
        break;

      case CRYP_AES_CCM:

        /* AES CCM encryption */
        status = CRYP_AESCCM_Process(hcryp, Timeout);
        break;

      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
    }
#endif /*end AES or CRYP */

    if (status == DAL_OK)
    {
      /* Change the CRYP peripheral state */
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process unlocked */
      __DAL_UNLOCK(hcryp);
    }
  }
  else
  {
    /* Busy error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_BUSY;
    return DAL_ERROR;
  }

  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  Decryption mode.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Input: Pointer to the input buffer (ciphertext )
  * @param  Size: Length of the plaintext buffer in word.
  * @param  Output: Pointer to the output buffer(plaintext)
  * @param  Timeout: Specify Timeout value
  * @retval DAL status
  */
DAL_StatusTypeDef DAL_CRYP_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output,
                                   uint32_t Timeout)
{
  DAL_StatusTypeDef status;
  uint32_t algo;

  if (hcryp->State == DAL_CRYP_STATE_READY)
  {
    /* Change state Busy */
    hcryp->State = DAL_CRYP_STATE_BUSY;

    /* Process locked */
    __DAL_LOCK(hcryp);

    /*  Reset CrypInCount, CrypOutCount and Initialize pCrypInBuffPtr and pCrypOutBuffPtr  parameters*/
    hcryp->CrypInCount = 0U;
    hcryp->CrypOutCount = 0U;
    hcryp->pCrypInBuffPtr = Input;
    hcryp->pCrypOutBuffPtr = Output;

    /*  Calculate Size parameter in Byte*/
    if (hcryp->Init.DataWidthUnit == CRYP_DATAWIDTHUNIT_WORD)
    {
      hcryp->Size = Size * 4U;
    }
    else
    {
      hcryp->Size = Size;
    }

#if defined (CRYP)

    /* Set Decryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGODIRSEL, CRYP_OPERATINGMODE_DECRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & CRYP_CTRL_ALGOMSEL;

    switch (algo)
    {
      case CRYP_DES_ECB:
      case CRYP_DES_CBC:
      case CRYP_TDES_ECB:
      case CRYP_TDES_CBC:

        /*Set Key */
        hcryp->Instance->K1L = *(uint32_t *)(hcryp->Init.pKey);
        hcryp->Instance->K1R = *(uint32_t *)(hcryp->Init.pKey + 1);
        if ((hcryp->Init.Algorithm == CRYP_TDES_ECB) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->K2L = *(uint32_t *)(hcryp->Init.pKey + 2);
          hcryp->Instance->K2R = *(uint32_t *)(hcryp->Init.pKey + 3);
          hcryp->Instance->K3L = *(uint32_t *)(hcryp->Init.pKey + 4);
          hcryp->Instance->K3R = *(uint32_t *)(hcryp->Init.pKey + 5);
        }

        /*Set Initialization Vector (IV)*/
        if ((hcryp->Init.Algorithm == CRYP_DES_CBC) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
          hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
        }

        /* Flush FIFO */
        DAL_CRYP_FIFO_FLUSH(hcryp);

        /* Set the phase */
        hcryp->Phase = CRYP_PHASE_PROCESS;

        /* Start DES/TDES decryption process */
        status = CRYP_TDES_Process(hcryp, Timeout);

        break;

      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        /* AES decryption */
        status = CRYP_AES_Decrypt(hcryp, Timeout);
        break;
        #if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)
      case CRYP_AES_GCM:

        /* AES GCM decryption */
        status = CRYP_AESGCM_Process(hcryp, Timeout) ;
        break;

      case CRYP_AES_CCM:

        /* AES CCM decryption */
        status = CRYP_AESCCM_Process(hcryp, Timeout);
        break;
        #endif /* GCM CCM defined*/
      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
    }

#else /*AES*/

    /* Set Decryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_DECRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & AES_CR_CHMOD;

    switch (algo)
    {

      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        /* AES decryption */
        status = CRYP_AES_Decrypt(hcryp, Timeout);
        break;

      case CRYP_AES_GCM_GMAC:

        /* AES GCM decryption */
        status = CRYP_AESGCM_Process(hcryp, Timeout) ;
        break;

      case CRYP_AES_CCM:

        /* AES CCM decryption */
        status = CRYP_AESCCM_Process(hcryp, Timeout);
        break;

      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
    }
#endif /* End AES or CRYP */

    if (status == DAL_OK)
    {
      /* Change the CRYP peripheral state */
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process unlocked */
      __DAL_UNLOCK(hcryp);
    }
  }
  else
  {
    /* Busy error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_BUSY;
    return DAL_ERROR;
  }

  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  Encryption in interrupt mode.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Input: Pointer to the input buffer (plaintext)
  * @param  Size: Length of the plaintext buffer in word
  * @param  Output: Pointer to the output buffer(ciphertext)
  * @retval DAL status
  */
DAL_StatusTypeDef DAL_CRYP_Encrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output)
{
  uint32_t algo;
  DAL_StatusTypeDef status = DAL_OK;

  if (hcryp->State == DAL_CRYP_STATE_READY)
  {
    /* Change state Busy */
    hcryp->State = DAL_CRYP_STATE_BUSY;

    /* Process locked */
    __DAL_LOCK(hcryp);

    /*  Reset CrypInCount, CrypOutCount and Initialize pCrypInBuffPtr and pCrypOutBuffPtr parameters*/
    hcryp->CrypInCount = 0U;
    hcryp->CrypOutCount = 0U;
    hcryp->pCrypInBuffPtr = Input;
    hcryp->pCrypOutBuffPtr = Output;

    /*  Calculate Size parameter in Byte*/
    if (hcryp->Init.DataWidthUnit == CRYP_DATAWIDTHUNIT_WORD)
    {
      hcryp->Size = Size * 4U;
    }
    else
    {
      hcryp->Size = Size;
    }

#if defined (CRYP)

    /* Set encryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGODIRSEL, CRYP_OPERATINGMODE_ENCRYPT);

    /* algo get algorithm selected */
    algo = (hcryp->Instance->CTRL & CRYP_CTRL_ALGOMSEL);

    switch (algo)
    {
      case CRYP_DES_ECB:
      case CRYP_DES_CBC:
      case CRYP_TDES_ECB:
      case CRYP_TDES_CBC:

        /*Set Key */
        hcryp->Instance->K1L = *(uint32_t *)(hcryp->Init.pKey);
        hcryp->Instance->K1R = *(uint32_t *)(hcryp->Init.pKey + 1);
        if ((hcryp->Init.Algorithm == CRYP_TDES_ECB) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->K2L = *(uint32_t *)(hcryp->Init.pKey + 2);
          hcryp->Instance->K2R = *(uint32_t *)(hcryp->Init.pKey + 3);
          hcryp->Instance->K3L = *(uint32_t *)(hcryp->Init.pKey + 4);
          hcryp->Instance->K3R = *(uint32_t *)(hcryp->Init.pKey + 5);
        }
        /* Set the Initialization Vector*/
        if ((hcryp->Init.Algorithm == CRYP_DES_CBC) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
          hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
        }

        /* Flush FIFO */
        DAL_CRYP_FIFO_FLUSH(hcryp);

        /* Set the phase */
        hcryp->Phase = CRYP_PHASE_PROCESS;

        /* Enable interrupts */
        __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_INI | CRYP_IT_OUTI);

        /* Enable CRYP to start DES/TDES process*/
        __DAL_CRYP_ENABLE(hcryp);
        break;

      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        status = CRYP_AES_Encrypt_IT(hcryp);
        break;
        #if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)
      case CRYP_AES_GCM:

        status = CRYP_AESGCM_Process_IT(hcryp) ;
        break;

      case CRYP_AES_CCM:

        status = CRYP_AESCCM_Process_IT(hcryp);
        break;
        #endif /* GCM CCM defined*/
      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        status =  DAL_ERROR;
        break;
    }

#else /* AES */

    /* Set encryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_ENCRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & AES_CR_CHMOD;

    switch (algo)
    {
      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        /* AES encryption */
        status = CRYP_AES_Encrypt_IT(hcryp);
        break;

      case CRYP_AES_GCM_GMAC:

        /* AES GCM encryption */
        status = CRYP_AESGCM_Process_IT(hcryp) ;
        break;

      case CRYP_AES_CCM:

        /* AES CCM encryption */
        status = CRYP_AESCCM_Process_IT(hcryp);
        break;

      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        status =  DAL_ERROR;
        break;
    }
#endif /*end AES or CRYP*/

  }
  else
  {
    /* Busy error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_BUSY;
    status =  DAL_ERROR;
  }

  /* Return function status */
  return status;
}

/**
  * @brief  Decryption in itnterrupt mode.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Input: Pointer to the input buffer (ciphertext )
  * @param  Size: Length of the plaintext buffer in word.
  * @param  Output: Pointer to the output buffer(plaintext)
  * @retval DAL status
  */
DAL_StatusTypeDef DAL_CRYP_Decrypt_IT(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output)
{
  uint32_t algo;
  DAL_StatusTypeDef status = DAL_OK;

  if (hcryp->State == DAL_CRYP_STATE_READY)
  {
    /* Change state Busy */
    hcryp->State = DAL_CRYP_STATE_BUSY;

    /* Process locked */
    __DAL_LOCK(hcryp);

    /*  Reset CrypInCount, CrypOutCount and Initialize pCrypInBuffPtr and pCrypOutBuffPtr parameters*/
    hcryp->CrypInCount = 0U;
    hcryp->CrypOutCount = 0U;
    hcryp->pCrypInBuffPtr = Input;
    hcryp->pCrypOutBuffPtr = Output;

    /*  Calculate Size parameter in Byte*/
    if (hcryp->Init.DataWidthUnit == CRYP_DATAWIDTHUNIT_WORD)
    {
      hcryp->Size = Size * 4U;
    }
    else
    {
      hcryp->Size = Size;
    }

#if defined (CRYP)

    /* Set decryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGODIRSEL, CRYP_OPERATINGMODE_DECRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & CRYP_CTRL_ALGOMSEL;

    switch (algo)
    {
      case CRYP_DES_ECB:
      case CRYP_DES_CBC:
      case CRYP_TDES_ECB:
      case CRYP_TDES_CBC:

        /*Set Key */
        hcryp->Instance->K1L = *(uint32_t *)(hcryp->Init.pKey);
        hcryp->Instance->K1R = *(uint32_t *)(hcryp->Init.pKey + 1);
        if ((hcryp->Init.Algorithm == CRYP_TDES_ECB) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->K2L = *(uint32_t *)(hcryp->Init.pKey + 2);
          hcryp->Instance->K2R = *(uint32_t *)(hcryp->Init.pKey + 3);
          hcryp->Instance->K3L = *(uint32_t *)(hcryp->Init.pKey + 4);
          hcryp->Instance->K3R = *(uint32_t *)(hcryp->Init.pKey + 5);
        }

        /* Set the Initialization Vector*/
        if ((hcryp->Init.Algorithm == CRYP_DES_CBC) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
          hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
        }
        /* Flush FIFO */
        DAL_CRYP_FIFO_FLUSH(hcryp);

        /* Set the phase */
        hcryp->Phase = CRYP_PHASE_PROCESS;

        /* Enable interrupts */
        __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_INI | CRYP_IT_OUTI);

        /* Enable CRYP and start DES/TDES process*/
        __DAL_CRYP_ENABLE(hcryp);

        break;

      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        /* AES decryption */
        status = CRYP_AES_Decrypt_IT(hcryp);
        break;
        #if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)
      case CRYP_AES_GCM:

        /* AES GCM decryption */
        status = CRYP_AESGCM_Process_IT(hcryp) ;
        break;

      case CRYP_AES_CCM:

        /* AES CCMdecryption */
        status = CRYP_AESCCM_Process_IT(hcryp);
        break;
        #endif /* GCM CCM defined*/
      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        status =  DAL_ERROR;
        break;
    }

#else /*AES*/

    /* Set decryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_DECRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & AES_CR_CHMOD;

    switch (algo)
    {
      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        /* AES decryption */
        status = CRYP_AES_Decrypt_IT(hcryp);
        break;

      case CRYP_AES_GCM_GMAC:

        /* AES GCM decryption */
        status = CRYP_AESGCM_Process_IT(hcryp) ;
        break;

      case CRYP_AES_CCM:

        /* AES CCM decryption */
        status = CRYP_AESCCM_Process_IT(hcryp);
        break;

      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        status =  DAL_ERROR;
        break;
    }
#endif /* End AES or CRYP */

  }
  else
  {
    /* Busy error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_BUSY;
    status =  DAL_ERROR;
  }

  /* Return function status */
  return status;
}

/**
  * @brief  Encryption in DMA mode.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Input: Pointer to the input buffer (plaintext)
  * @param  Size: Length of the plaintext buffer in word.
  * @param  Output: Pointer to the output buffer(ciphertext)
  * @retval DAL status
  */
DAL_StatusTypeDef DAL_CRYP_Encrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output)
{
  uint32_t algo;
  DAL_StatusTypeDef status = DAL_OK;
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */

  if (hcryp->State == DAL_CRYP_STATE_READY)
  {
    /* Change state Busy */
    hcryp->State = DAL_CRYP_STATE_BUSY;

    /* Process locked */
    __DAL_LOCK(hcryp);

    /*  Reset CrypInCount, CrypOutCount and Initialize pCrypInBuffPtr and pCrypOutBuffPtr parameters*/
    hcryp->CrypInCount = 0U;
    hcryp->CrypOutCount = 0U;
    hcryp->pCrypInBuffPtr = Input;
    hcryp->pCrypOutBuffPtr = Output;

    /*  Calculate Size parameter in Byte*/
    if (hcryp->Init.DataWidthUnit == CRYP_DATAWIDTHUNIT_WORD)
    {
      hcryp->Size = Size * 4U;
    }
    else
    {
      hcryp->Size = Size;
    }

#if defined (CRYP)

    /* Set encryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGODIRSEL, CRYP_OPERATINGMODE_ENCRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & CRYP_CTRL_ALGOMSEL;

    switch (algo)
    {
      case CRYP_DES_ECB:
      case CRYP_DES_CBC:
      case CRYP_TDES_ECB:
      case CRYP_TDES_CBC:

        /*Set Key */
        hcryp->Instance->K1L = *(uint32_t *)(hcryp->Init.pKey);
        hcryp->Instance->K1R = *(uint32_t *)(hcryp->Init.pKey + 1);
        if ((hcryp->Init.Algorithm == CRYP_TDES_ECB) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->K2L = *(uint32_t *)(hcryp->Init.pKey + 2);
          hcryp->Instance->K2R = *(uint32_t *)(hcryp->Init.pKey + 3);
          hcryp->Instance->K3L = *(uint32_t *)(hcryp->Init.pKey + 4);
          hcryp->Instance->K3R = *(uint32_t *)(hcryp->Init.pKey + 5);
        }

        /* Set the Initialization Vector*/
        if ((hcryp->Init.Algorithm == CRYP_DES_CBC) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
          hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
        }

        /* Flush FIFO */
        DAL_CRYP_FIFO_FLUSH(hcryp);

        /* Set the phase */
        hcryp->Phase = CRYP_PHASE_PROCESS;

        /* Start DMA process transfer for DES/TDES */
        CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), ((uint16_t)(hcryp->Size) / 4U),
                          (uint32_t)(hcryp->pCrypOutBuffPtr));
        break;

      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
        {
          if (hcryp->KeyIVConfig == 1U)
          {
            /* If the Key and IV configuration has to be done only once
            and if it has already been done, skip it */
            DoKeyIVConfig = 0U;
          }
          else
          {
            /* If the Key and IV configuration has to be done only once
            and if it has not been done already, do it and set KeyIVConfig
            to keep track it won't have to be done again next time */
            hcryp->KeyIVConfig = 1U;
          }
        }

        if (DoKeyIVConfig == 1U)
        {
          /*  Set the Key*/
          CRYP_SetKey(hcryp, hcryp->Init.KeySize);

          /* Set the Initialization Vector*/
          if (hcryp->Init.Algorithm != CRYP_AES_ECB)
          {
            hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
            hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1U);
            hcryp->Instance->IV1L = *(uint32_t *)(hcryp->Init.pInitVect + 2U);
            hcryp->Instance->IV1R = *(uint32_t *)(hcryp->Init.pInitVect + 3U);
          }
        } /* if (DoKeyIVConfig == 1U) */

        /* Set the phase */
        hcryp->Phase = CRYP_PHASE_PROCESS;

        /* Start DMA process transfer for AES */
        CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), ((uint16_t)(hcryp->Size) / 4U),
                          (uint32_t)(hcryp->pCrypOutBuffPtr));
        break;
        #if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)
      case CRYP_AES_GCM:
        /* AES GCM encryption */
        status = CRYP_AESGCM_Process_DMA(hcryp) ;
        break;

      case CRYP_AES_CCM:
        /* AES CCM encryption */
        status = CRYP_AESCCM_Process_DMA(hcryp);
        break;
        #endif /* GCM CCM defined*/
      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        status =  DAL_ERROR;
        break;
    }

#else /*AES*/
    /* Set encryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_ENCRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & AES_CR_CHMOD;

    switch (algo)
    {

      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
        {
          if (hcryp->KeyIVConfig == 1U)
          {
            /* If the Key and IV configuration has to be done only once
            and if it has already been done, skip it */
            DoKeyIVConfig = 0U;
          }
          else
          {
            /* If the Key and IV configuration has to be done only once
            and if it has not been done already, do it and set KeyIVConfig
            to keep track it won't have to be done again next time */
            hcryp->KeyIVConfig = 1U;
          }
        }

        if (DoKeyIVConfig == 1U)
        {
          /*  Set the Key*/
          CRYP_SetKey(hcryp, hcryp->Init.KeySize);

          /* Set the Initialization Vector*/
          if (hcryp->Init.Algorithm != CRYP_AES_ECB)
          {
            hcryp->Instance->IVR3 = *(uint32_t *)(hcryp->Init.pInitVect);
            hcryp->Instance->IVR2 = *(uint32_t *)(hcryp->Init.pInitVect + 1);
            hcryp->Instance->IVR1 = *(uint32_t *)(hcryp->Init.pInitVect + 2);
            hcryp->Instance->IVR0 = *(uint32_t *)(hcryp->Init.pInitVect + 3);
          }
        } /* if (DoKeyIVConfig == 1U) */
        /* Set the phase */
        hcryp->Phase = CRYP_PHASE_PROCESS;

        /* Start DMA process transfer for AES */
        CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), (hcryp->Size / 4U), (uint32_t)(hcryp->pCrypOutBuffPtr));
        break;

      case CRYP_AES_GCM_GMAC:
        /* AES GCM encryption */
        status = CRYP_AESGCM_Process_DMA(hcryp) ;
        break;

      case CRYP_AES_CCM:
        /* AES CCM encryption */
        status = CRYP_AESCCM_Process_DMA(hcryp);
        break;

      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        status =  DAL_ERROR;
        break;
    }
#endif /* End AES or CRYP */

  }
  else
  {
    /* Busy error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_BUSY;
    status =  DAL_ERROR;
  }

  /* Return function status */
  return status;
}

/**
  * @brief  Decryption in DMA mode.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Input: Pointer to the input buffer (ciphertext )
  * @param  Size: Length of the plaintext buffer in word
  * @param  Output: Pointer to the output buffer(plaintext)
  * @retval DAL status
  */
DAL_StatusTypeDef DAL_CRYP_Decrypt_DMA(CRYP_HandleTypeDef *hcryp, uint32_t *Input, uint16_t Size, uint32_t *Output)
{
  uint32_t algo;
  DAL_StatusTypeDef status = DAL_OK;

  if (hcryp->State == DAL_CRYP_STATE_READY)
  {

    /* Change state Busy */
    hcryp->State = DAL_CRYP_STATE_BUSY;

    /* Process locked */
    __DAL_LOCK(hcryp);

    /*  Reset CrypInCount, CrypOutCount and Initialize pCrypInBuffPtr, pCrypOutBuffPtr and Size parameters*/
    hcryp->CrypInCount = 0U;
    hcryp->CrypOutCount = 0U;
    hcryp->pCrypInBuffPtr = Input;
    hcryp->pCrypOutBuffPtr = Output;

    /*  Calculate Size parameter in Byte*/
    if (hcryp->Init.DataWidthUnit == CRYP_DATAWIDTHUNIT_WORD)
    {
      hcryp->Size = Size * 4U;
    }
    else
    {
      hcryp->Size = Size;
    }

#if defined (CRYP)

    /* Set decryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGODIRSEL, CRYP_OPERATINGMODE_DECRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & CRYP_CTRL_ALGOMSEL;

    switch (algo)
    {
      case CRYP_DES_ECB:
      case CRYP_DES_CBC:
      case CRYP_TDES_ECB:
      case CRYP_TDES_CBC:

        /*Set Key */
        hcryp->Instance->K1L = *(uint32_t *)(hcryp->Init.pKey);
        hcryp->Instance->K1R = *(uint32_t *)(hcryp->Init.pKey + 1);
        if ((hcryp->Init.Algorithm == CRYP_TDES_ECB) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->K2L = *(uint32_t *)(hcryp->Init.pKey + 2);
          hcryp->Instance->K2R = *(uint32_t *)(hcryp->Init.pKey + 3);
          hcryp->Instance->K3L = *(uint32_t *)(hcryp->Init.pKey + 4);
          hcryp->Instance->K3R = *(uint32_t *)(hcryp->Init.pKey + 5);
        }

        /* Set the Initialization Vector*/
        if ((hcryp->Init.Algorithm == CRYP_DES_CBC) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
        {
          hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
          hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
        }

        /* Flush FIFO */
        DAL_CRYP_FIFO_FLUSH(hcryp);

        /* Set the phase */
        hcryp->Phase = CRYP_PHASE_PROCESS;

        /* Start DMA process transfer for DES/TDES */
        CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), ((uint16_t)(hcryp->Size) / 4U),
                          (uint32_t)(hcryp->pCrypOutBuffPtr));
        break;

      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        /* AES decryption */
        status = CRYP_AES_Decrypt_DMA(hcryp);
        break;
        #if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)
      case CRYP_AES_GCM:
        /* AES GCM decryption */
        status = CRYP_AESGCM_Process_DMA(hcryp) ;
        break;

      case CRYP_AES_CCM:
        /* AES CCM decryption */
        status = CRYP_AESCCM_Process_DMA(hcryp);
        break;
        #endif /* GCM CCM defined*/
      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        status =  DAL_ERROR;
        break;
    }

#else /*AES*/

    /* Set decryption operating mode*/
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_DECRYPT);

    /* algo get algorithm selected */
    algo = hcryp->Instance->CTRL & AES_CR_CHMOD;

    switch (algo)
    {

      case CRYP_AES_ECB:
      case CRYP_AES_CBC:
      case CRYP_AES_CTR:

        /* AES decryption */
        status = CRYP_AES_Decrypt_DMA(hcryp);
        break;

      case CRYP_AES_GCM_GMAC:
        /* AES GCM decryption */
        status = CRYP_AESGCM_Process_DMA(hcryp) ;
        break;

      case CRYP_AES_CCM:
        /* AES CCM decryption */
        status = CRYP_AESCCM_Process_DMA(hcryp);
        break;

      default:
        hcryp->ErrorCode |= DAL_CRYP_ERROR_NOT_SUPPORTED;
        /* Change the CRYP peripheral state */
        hcryp->State = DAL_CRYP_STATE_READY;
        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        status =  DAL_ERROR;
        break;
    }
#endif /* End AES or CRYP */
  }
  else
  {
    /* Busy error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_BUSY;
    status =  DAL_ERROR;
  }

  /* Return function status */
  return status;
}

/**
  * @}
  */

/** @defgroup CRYP_Exported_Functions_Group3 CRYP IRQ handler management
  *  @brief   CRYP IRQ handler.
  *
@verbatim
  ==============================================================================
                ##### CRYP IRQ handler management #####
  ==============================================================================
[..]  This section provides CRYP IRQ handler and callback functions.
      (+) DAL_CRYP_IRQHandler CRYP interrupt request
      (+) DAL_CRYP_InCpltCallback input data transfer complete callback
      (+) DAL_CRYP_OutCpltCallback output data transfer complete callback
      (+) DAL_CRYP_ErrorCallback  CRYP error callback
      (+) DAL_CRYP_GetState return the CRYP state
      (+) DAL_CRYP_GetError return the CRYP error code
@endverbatim
  * @{
  */

/**
  * @brief  This function handles cryptographic interrupt request.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval None
  */
void DAL_CRYP_IRQHandler(CRYP_HandleTypeDef *hcryp)
{

#if defined (CRYP)

  uint32_t itstatus = hcryp->Instance->MINTSTS;

  if ((itstatus & (CRYP_IT_INI | CRYP_IT_OUTI)) != 0U)
  {
    if ((hcryp->Init.Algorithm == CRYP_DES_ECB) || (hcryp->Init.Algorithm == CRYP_DES_CBC)
        || (hcryp->Init.Algorithm == CRYP_TDES_ECB) || (hcryp->Init.Algorithm == CRYP_TDES_CBC))
    {
      CRYP_TDES_IT(hcryp); /* DES or TDES*/
    }
    else if ((hcryp->Init.Algorithm == CRYP_AES_ECB) || (hcryp->Init.Algorithm == CRYP_AES_CBC)
             || (hcryp->Init.Algorithm == CRYP_AES_CTR))
    {
      CRYP_AES_IT(hcryp); /*AES*/
    }
    #if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)
    else if ((hcryp->Init.Algorithm == CRYP_AES_GCM) || (hcryp->Init.Algorithm == CRYP_CTRL_ALGOMSEL_AES_CCM))
    {
      /* if header phase */
      if ((hcryp->Instance->CTRL & CRYP_PHASE_HEADER) == CRYP_PHASE_HEADER)
      {
        CRYP_GCMCCM_SetHeaderPhase_IT(hcryp);
      }
      else  /* if payload phase */
      {
        CRYP_GCMCCM_SetPayloadPhase_IT(hcryp);
      }
    }
    #endif /* GCM CCM defined*/
    else
    {
      /* Nothing to do */
    }
  }

#else /*AES*/
  if (__DAL_CRYP_GET_FLAG(hcryp, CRYP_IT_CCF) != RESET)
  {
    if (__DAL_CRYP_GET_IT_SOURCE(hcryp, CRYP_IT_CCFIE) != RESET)
    {

      /* Clear computation complete flag */
      __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

      if (hcryp->Init.Algorithm == CRYP_AES_GCM_GMAC)
      {

        /* if header phase */
        if ((hcryp->Instance->CTRL & CRYP_PHASE_HEADER) == CRYP_PHASE_HEADER)
        {
          CRYP_GCMCCM_SetHeaderPhase_IT(hcryp);
        }
        else  /* if payload phase */
        {
          CRYP_GCMCCM_SetPayloadPhase_IT(hcryp);
        }
      }
      else if (hcryp->Init.Algorithm == CRYP_AES_CCM)
      {
        /* if header phase */
        if (hcryp->Init.HeaderSize >=  hcryp->CrypHeaderCount)
        {
          CRYP_GCMCCM_SetHeaderPhase_IT(hcryp);
        }
        else   /* if payload phase */
        {
          CRYP_GCMCCM_SetPayloadPhase_IT(hcryp);
        }
      }
      else  /* AES Algorithm ECB,CBC or CTR*/
      {
        CRYP_AES_IT(hcryp);
      }
    }
  }
  /* Check if error occurred */
  if (__DAL_CRYP_GET_IT_SOURCE(hcryp, CRYP_IT_ERRIE) != RESET)
  {
    /* If write Error occurred */
    if (__DAL_CRYP_GET_FLAG(hcryp, CRYP_IT_WRERR) != RESET)
    {
      hcryp->ErrorCode |= DAL_CRYP_ERROR_WRITE;
    }
    /* If read Error occurred */
    if (__DAL_CRYP_GET_FLAG(hcryp, CRYP_IT_RDERR) != RESET)
    {
      hcryp->ErrorCode |= DAL_CRYP_ERROR_READ;
    }
  }
#endif /* End AES or CRYP */
}

/**
  * @brief  Return the CRYP error code.
  * @param  hcryp : pointer to a CRYP_HandleTypeDef structure that contains
  *                 the configuration information for the  CRYP IP
  * @retval CRYP error code
  */
uint32_t DAL_CRYP_GetError(CRYP_HandleTypeDef *hcryp)
{
  return hcryp->ErrorCode;
}

/**
  * @brief  Returns the CRYP state.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module.
  * @retval DAL state
  */
DAL_CRYP_STATETypeDef DAL_CRYP_GetState(CRYP_HandleTypeDef *hcryp)
{
  return hcryp->State;
}

/**
  * @brief  Input FIFO transfer completed callback.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module.
  * @retval None
  */
__weak void DAL_CRYP_InCpltCallback(CRYP_HandleTypeDef *hcryp)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hcryp);

  /* NOTE : This function should not be modified, when the callback is needed,
            the DAL_CRYP_InCpltCallback can be implemented in the user file
   */
}

/**
  * @brief  Output FIFO transfer completed callback.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module.
  * @retval None
  */
__weak void DAL_CRYP_OutCpltCallback(CRYP_HandleTypeDef *hcryp)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hcryp);

  /* NOTE : This function should not be modified, when the callback is needed,
            the DAL_CRYP_OutCpltCallback can be implemented in the user file
   */
}

/**
  * @brief  CRYP error callback.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module.
  * @retval None
  */
__weak void DAL_CRYP_ErrorCallback(CRYP_HandleTypeDef *hcryp)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hcryp);

  /* NOTE : This function Should not be modified, when the callback is needed,
            the DAL_CRYP_ErrorCallback could be implemented in the user file
   */
}
/**
  * @}
  */

/* Private functions ---------------------------------------------------------*/
/** @addtogroup CRYP_Private_Functions
  * @{
  */

#if defined (CRYP)

/**
  * @brief  Encryption in ECB/CBC Algorithm with DES/TDES standard.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Timeout: specify Timeout value
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_TDES_Process(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint32_t temp[2];  /* Temporary CrypOutBuff */
  uint16_t incount; /* Temporary CrypInCount Value */
  uint16_t outcount;  /* Temporary CrypOutCount Value */
  uint32_t i;

  /* Enable CRYP */
  __DAL_CRYP_ENABLE(hcryp);
  /*Temporary CrypOutCount Value*/
  outcount = hcryp->CrypOutCount;

  /*Start processing*/
  while ((hcryp->CrypInCount < (hcryp->Size / 4U)) && (outcount < (hcryp->Size / 4U)))
  {
    /* Temporary CrypInCount Value */
    incount = hcryp->CrypInCount;
    /* Write plain data and get cipher data */
    if (((hcryp->Instance->STS & CRYP_FLAG_IFNF) != 0x0U) && (incount < (hcryp->Size / 4U)))
    {
      /* Write the input block in the IN FIFO */
      hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
    }

    /* Wait for OFNE flag to be raised */
    if (CRYP_WaitOnOFNEFlag(hcryp, Timeout) != DAL_OK)
    {
      /* Disable the CRYP peripheral clock */
      __DAL_CRYP_DISABLE(hcryp);

      /* Change state & errorCode*/
      hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process unlocked */
      __DAL_UNLOCK(hcryp);
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
      /*Call registered error callback*/
      hcryp->ErrorCallback(hcryp);
#else
      /*Call legacy weak error callback*/
      DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
    }

    /*Temporary CrypOutCount Value*/
    outcount = hcryp->CrypOutCount;

    if (((hcryp->Instance->STS & CRYP_FLAG_OFNE) != 0x0U) && (outcount < (hcryp->Size / 4U)))
    {
      /* Read the output block from the Output FIFO and put them in temporary Buffer then get CrypOutBuff from temporary buffer  */
      for (i = 0U; i < 2U; i++)
      {
        temp[i] = hcryp->Instance->DATAOUT;
      }
      i = 0U;
      while (((hcryp->CrypOutCount < ((hcryp->Size) / 4U))) && (i < 2U))
      {
        *(uint32_t *)(hcryp->pCrypOutBuffPtr + hcryp->CrypOutCount) = temp[i];
        hcryp->CrypOutCount++;
        i++;
      }
    }
    /*Temporary CrypOutCount Value*/
    outcount = hcryp->CrypOutCount;
  }
  /* Disable CRYP */
  __DAL_CRYP_DISABLE(hcryp);
  /* Change the CRYP state */
  hcryp->State = DAL_CRYP_STATE_READY;

  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  CRYP block input/output data handling under interruption with DES/TDES standard.
  * @note   The function is called under interruption only, once
  *         interruptions have been enabled by CRYP_Decrypt_IT() and CRYP_Encrypt_IT().
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module.
  * @retval none
  */
static void CRYP_TDES_IT(CRYP_HandleTypeDef *hcryp)
{
  uint32_t temp[2];  /* Temporary CrypOutBuff */
  uint32_t i;

  if (hcryp->State == DAL_CRYP_STATE_BUSY)
  {
    if (__DAL_CRYP_GET_IT(hcryp, CRYP_IT_INI) != 0x0U)
    {
      if (__DAL_CRYP_GET_FLAG(hcryp, CRYP_FLAG_INRIS) != 0x0U)
      {
        /* Write input block in the IN FIFO */
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
        hcryp->CrypInCount++;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
        hcryp->CrypInCount++;

        if (hcryp->CrypInCount == ((uint16_t)(hcryp->Size) / 4U))
        {
          /* Disable interruption */
          __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_INI);
          /* Call the input data transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1U)
          /*Call registered Input complete callback*/
          hcryp->InCpltCallback(hcryp);
#else
          /*Call legacy weak Input complete callback*/
          DAL_CRYP_InCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
        }
      }
    }
    if (__DAL_CRYP_GET_IT(hcryp, CRYP_IT_OUTI) != 0x0U)
    {
      if (__DAL_CRYP_GET_FLAG(hcryp, CRYP_FLAG_OUTRIS) != 0x0U)
      {
        /* Read the output block from the Output FIFO and put them in temporary Buffer then get CrypOutBuff from temporary buffer  */
        for (i = 0U; i < 2U; i++)
        {
          temp[i] = hcryp->Instance->DATAOUT;
        }
        i = 0U;
        while (((hcryp->CrypOutCount < ((hcryp->Size) / 4U))) && (i < 2U))
        {
          *(uint32_t *)(hcryp->pCrypOutBuffPtr + hcryp->CrypOutCount) = temp[i];
          hcryp->CrypOutCount++;
          i++;
        }
        if (hcryp->CrypOutCount == ((uint16_t)(hcryp->Size) / 4U))
        {
          /* Disable interruption */
          __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_OUTI);

          /* Disable CRYP */
          __DAL_CRYP_DISABLE(hcryp);

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);

          /* Change the CRYP state */
          hcryp->State = DAL_CRYP_STATE_READY;
          /* Call output transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
          /*Call registered Output complete callback*/
          hcryp->OutCpltCallback(hcryp);
#else
          /*Call legacy weak Output complete callback*/
          DAL_CRYP_OutCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
        }
      }
    }
  }
  else
  {
    /* Process unlocked */
    __DAL_UNLOCK(hcryp);
    /* Busy error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_BUSY;
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
    /*Call registered error callback*/
    hcryp->ErrorCallback(hcryp);
#else
    /*Call legacy weak error callback*/
    DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
  }
}

#endif /* CRYP */

/**
  * @brief  Encryption in ECB/CBC & CTR Algorithm with AES Standard
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure
  * @param  Timeout: specify Timeout value
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AES_Encrypt(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint16_t outcount;  /* Temporary CrypOutCount Value */
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
    }
  }

  if (DoKeyIVConfig == 1U)
  {

    /*  Set the Key*/
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

    if (hcryp->Init.Algorithm != CRYP_AES_ECB)
    {
      /* Set the Initialization Vector*/
#if defined (AES)
      hcryp->Instance->IVR3 = *(uint32_t *)(hcryp->Init.pInitVect);
      hcryp->Instance->IVR2 = *(uint32_t *)(hcryp->Init.pInitVect + 1);
      hcryp->Instance->IVR1 = *(uint32_t *)(hcryp->Init.pInitVect + 2);
      hcryp->Instance->IVR0 = *(uint32_t *)(hcryp->Init.pInitVect + 3);
#else /* CRYP */
      hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
      hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
      hcryp->Instance->IV1L = *(uint32_t *)(hcryp->Init.pInitVect + 2);
      hcryp->Instance->IV1R = *(uint32_t *)(hcryp->Init.pInitVect + 3);
#endif /* End AES or CRYP */
    }
  } /* if (DoKeyIVConfig == 1U) */

  /* Set the phase */
  hcryp->Phase = CRYP_PHASE_PROCESS;

  /* Enable CRYP */
  __DAL_CRYP_ENABLE(hcryp);

  /*Temporary CrypOutCount Value*/
  outcount = hcryp->CrypOutCount;

  while ((hcryp->CrypInCount < (hcryp->Size / 4U)) && (outcount < (hcryp->Size / 4U)))
  {
    /* Write plain Ddta and get cipher data */
    CRYP_AES_ProcessData(hcryp, Timeout);
    /*Temporary CrypOutCount Value*/
    outcount = hcryp->CrypOutCount;
  }

  /* Disable CRYP */
  __DAL_CRYP_DISABLE(hcryp);

  /* Change the CRYP state */
  hcryp->State = DAL_CRYP_STATE_READY;

  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  Encryption in ECB/CBC & CTR mode with AES Standard using interrupt mode
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AES_Encrypt_IT(CRYP_HandleTypeDef *hcryp)
{
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
    }
  }

  if (DoKeyIVConfig == 1U)
  {
    /*  Set the Key*/
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

    if (hcryp->Init.Algorithm != CRYP_AES_ECB)
    {
      /* Set the Initialization Vector*/
#if defined (AES)
      hcryp->Instance->IVR3 = *(uint32_t *)(hcryp->Init.pInitVect);
      hcryp->Instance->IVR2 = *(uint32_t *)(hcryp->Init.pInitVect + 1);
      hcryp->Instance->IVR1 = *(uint32_t *)(hcryp->Init.pInitVect + 2);
      hcryp->Instance->IVR0 = *(uint32_t *)(hcryp->Init.pInitVect + 3);

#else /* CRYP */
      hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
      hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
      hcryp->Instance->IV1L = *(uint32_t *)(hcryp->Init.pInitVect + 2);
      hcryp->Instance->IV1R = *(uint32_t *)(hcryp->Init.pInitVect + 3);
#endif /* End AES or CRYP */
    }
  } /* if (DoKeyIVConfig == 1U) */

  /* Set the phase */
  hcryp->Phase = CRYP_PHASE_PROCESS;

  if (hcryp->Size != 0U)
  {
#if defined (AES)

    /* Enable computation complete flag and error interrupts */
    __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_CCFIE | CRYP_IT_ERRIE);

    /* Enable CRYP */
    __DAL_CRYP_ENABLE(hcryp);

    /* Write the input block in the IN FIFO */
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;

#else /* CRYP */

    /* Enable interrupts */
    __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_INI | CRYP_IT_OUTI);

    /* Enable CRYP */
    __DAL_CRYP_ENABLE(hcryp);

#endif /*  End AES or CRYP  */
  }
  else
  {
    /* Change the CRYP state */
    hcryp->State = DAL_CRYP_STATE_READY;

    /* Process unlocked */
    __DAL_UNLOCK(hcryp);
  }

  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  Decryption in ECB/CBC & CTR mode with AES Standard
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure
  * @param  Timeout: Specify Timeout value
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AES_Decrypt(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint16_t outcount;  /* Temporary CrypOutCount Value */
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
    }
  }

  if (DoKeyIVConfig == 1U)
  {
    /*  Key preparation for ECB/CBC */
    if (hcryp->Init.Algorithm != CRYP_AES_CTR)
    {
#if defined (AES)
      if (hcryp->AutoKeyDerivation == DISABLE)/*Mode 2 Key preparation*/
      {
        /* Set key preparation for decryption operating mode*/
        MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_KEYDERIVATION);

        /*  Set the Key*/
        CRYP_SetKey(hcryp, hcryp->Init.KeySize);

        /* Enable CRYP */
        __DAL_CRYP_ENABLE(hcryp);

        /* Wait for CCF flag to be raised */
        if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state & error code*/
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
        /* Clear CCF Flag */
        __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

        /* Return to decryption operating mode(Mode 3)*/
        MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_DECRYPT);
      }
      else /*Mode 4 : decryption & Key preparation*/
      {
        /*  Set the Key*/
        CRYP_SetKey(hcryp, hcryp->Init.KeySize);

        /* Set decryption & Key preparation operating mode*/
        MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_KEYDERIVATION_DECRYPT);
      }
#else /* CRYP */
      /* change ALGOMODE to key preparation for decryption*/
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGOMSEL, CRYP_CTRL_ALGOMSEL_AES_KEY);

      /*  Set the Key*/
      CRYP_SetKey(hcryp, hcryp->Init.KeySize);

      /* Enable CRYP */
      __DAL_CRYP_ENABLE(hcryp);

      /* Wait for BUSY flag to be raised */
      if (CRYP_WaitOnBUSYFlag(hcryp, Timeout) != DAL_OK)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
      /* Turn back to ALGOMODE of the configuration */
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGOMSEL, hcryp->Init.Algorithm);

#endif /* End AES or CRYP  */
    }
    else  /*Algorithm CTR */
    {
      /*  Set the Key*/
      CRYP_SetKey(hcryp, hcryp->Init.KeySize);
    }

    /* Set IV */
    if (hcryp->Init.Algorithm != CRYP_AES_ECB)
    {
      /* Set the Initialization Vector*/
#if defined (AES)
      hcryp->Instance->IVR3 = *(uint32_t *)(hcryp->Init.pInitVect);
      hcryp->Instance->IVR2 = *(uint32_t *)(hcryp->Init.pInitVect + 1);
      hcryp->Instance->IVR1 = *(uint32_t *)(hcryp->Init.pInitVect + 2);
      hcryp->Instance->IVR0 = *(uint32_t *)(hcryp->Init.pInitVect + 3);
#else /* CRYP */
      hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
      hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
      hcryp->Instance->IV1L = *(uint32_t *)(hcryp->Init.pInitVect + 2);
      hcryp->Instance->IV1R = *(uint32_t *)(hcryp->Init.pInitVect + 3);
#endif /* End AES or CRYP */
    }
  } /* if (DoKeyIVConfig == 1U) */
  /* Set the phase */
  hcryp->Phase = CRYP_PHASE_PROCESS;

  /* Enable CRYP */
  __DAL_CRYP_ENABLE(hcryp);

  /*Temporary CrypOutCount Value*/
  outcount = hcryp->CrypOutCount;

  while ((hcryp->CrypInCount < (hcryp->Size / 4U)) && (outcount < (hcryp->Size / 4U)))
  {
    /* Write plain data and get cipher data */
    CRYP_AES_ProcessData(hcryp, Timeout);
    /*Temporary CrypOutCount Value*/
    outcount = hcryp->CrypOutCount;
  }

  /* Disable CRYP */
  __DAL_CRYP_DISABLE(hcryp);

  /* Change the CRYP state */
  hcryp->State = DAL_CRYP_STATE_READY;

  /* Return function status */
  return DAL_OK;
}
/**
  * @brief  Decryption in ECB/CBC & CTR mode with AES Standard using interrupt mode
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AES_Decrypt_IT(CRYP_HandleTypeDef *hcryp)
{
  __IO uint32_t count = 0U;
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
    }
  }

  if (DoKeyIVConfig == 1U)
  {
    /*  Key preparation for ECB/CBC */
    if (hcryp->Init.Algorithm != CRYP_AES_CTR)
    {
#if defined (AES)
      if (hcryp->AutoKeyDerivation == DISABLE)/*Mode 2 Key preparation*/
      {
        /* Set key preparation for decryption operating mode*/
        MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_KEYDERIVATION);

        /*  Set the Key*/
        CRYP_SetKey(hcryp, hcryp->Init.KeySize);

        /* Enable CRYP */
        __DAL_CRYP_ENABLE(hcryp);

        /* Wait for CCF flag to be raised */
        count = CRYP_TIMEOUT_KEYPREPARATION;
        do
        {
          count-- ;
          if (count == 0U)
          {
            /* Disable the CRYP peripheral clock */
            __DAL_CRYP_DISABLE(hcryp);

            /* Change state */
            hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
            hcryp->State = DAL_CRYP_STATE_READY;

            /* Process unlocked */
            __DAL_UNLOCK(hcryp);
            return DAL_ERROR;
          }
        } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));

        /* Clear CCF Flag */
        __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

        /* Return to decryption operating mode(Mode 3)*/
        MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_DECRYPT);
      }
      else /*Mode 4 : decryption & key preparation*/
      {
        /*  Set the Key*/
        CRYP_SetKey(hcryp, hcryp->Init.KeySize);

        /* Set decryption & key preparation operating mode*/
        MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_KEYDERIVATION_DECRYPT);
      }
#else /* CRYP */

      /* change ALGOMODE to key preparation for decryption*/
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGOMSEL, CRYP_CTRL_ALGOMSEL_AES_KEY);

      /*  Set the Key*/
      CRYP_SetKey(hcryp, hcryp->Init.KeySize);

      /* Enable CRYP */
      __DAL_CRYP_ENABLE(hcryp);

      /* Wait for BUSY flag to be raised */
      count = CRYP_TIMEOUT_KEYPREPARATION;
      do
      {
        count-- ;
        if (count == 0U)
        {
          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
      } while (DAL_IS_BIT_SET(hcryp->Instance->STS, CRYP_FLAG_BUSY));

      /* Turn back to ALGOMODE of the configuration */
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGOMSEL, hcryp->Init.Algorithm);

#endif /* End AES or CRYP */
    }

    else  /*Algorithm CTR */
    {
      /*  Set the Key*/
      CRYP_SetKey(hcryp, hcryp->Init.KeySize);
    }

    /* Set IV */
    if (hcryp->Init.Algorithm != CRYP_AES_ECB)
    {
      /* Set the Initialization Vector*/
#if defined (AES)
      hcryp->Instance->IVR3 = *(uint32_t *)(hcryp->Init.pInitVect);
      hcryp->Instance->IVR2 = *(uint32_t *)(hcryp->Init.pInitVect + 1);
      hcryp->Instance->IVR1 = *(uint32_t *)(hcryp->Init.pInitVect + 2);
      hcryp->Instance->IVR0 = *(uint32_t *)(hcryp->Init.pInitVect + 3);
#else /* CRYP */
      hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
      hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
      hcryp->Instance->IV1L = *(uint32_t *)(hcryp->Init.pInitVect + 2);
      hcryp->Instance->IV1R = *(uint32_t *)(hcryp->Init.pInitVect + 3);
#endif /* End AES or CRYP */
    }
  } /* if (DoKeyIVConfig == 1U) */

  /* Set the phase */
  hcryp->Phase = CRYP_PHASE_PROCESS;
  if (hcryp->Size != 0U)
  {

#if defined (AES)

    /* Enable computation complete flag and error interrupts */
    __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_CCFIE | CRYP_IT_ERRIE);

    /* Enable CRYP */
    __DAL_CRYP_ENABLE(hcryp);

    /* Write the input block in the IN FIFO */
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;

#else /* CRYP */

    /* Enable interrupts */
    __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_INI | CRYP_IT_OUTI);

    /* Enable CRYP */
    __DAL_CRYP_ENABLE(hcryp);

#endif /* End AES or CRYP */
  }
  else
  {
    /* Process locked */
    __DAL_UNLOCK(hcryp);

    /* Change the CRYP state */
    hcryp->State = DAL_CRYP_STATE_READY;
  }

  /* Return function status */
  return DAL_OK;
}
/**
  * @brief  Decryption in ECB/CBC & CTR mode with AES Standard using DMA mode
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AES_Decrypt_DMA(CRYP_HandleTypeDef *hcryp)
{
  __IO uint32_t count = 0U;
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
    }
  }
  if (DoKeyIVConfig == 1U)
  {
    /*  Key preparation for ECB/CBC */
    if (hcryp->Init.Algorithm != CRYP_AES_CTR)
    {
#if defined (AES)
      if (hcryp->AutoKeyDerivation == DISABLE)/*Mode 2 key preparation*/
      {
        /* Set key preparation for decryption operating mode*/
        MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_KEYDERIVATION);

        /*  Set the Key*/
        CRYP_SetKey(hcryp, hcryp->Init.KeySize);

        /* Enable CRYP */
        __DAL_CRYP_ENABLE(hcryp);

        /* Wait for CCF flag to be raised */
        count = CRYP_TIMEOUT_KEYPREPARATION;
        do
        {
          count-- ;
          if (count == 0U)
          {
            /* Disable the CRYP peripheral clock */
            __DAL_CRYP_DISABLE(hcryp);

            /* Change state */
            hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
            hcryp->State = DAL_CRYP_STATE_READY;

            /* Process unlocked */
            __DAL_UNLOCK(hcryp);
            return DAL_ERROR;
          }
        } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));

        /* Clear CCF Flag */
        __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

        /* Return to decryption operating mode(Mode 3)*/
        MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_DECRYPT);
      }
      else /*Mode 4 : decryption & key preparation*/
      {
        /*  Set the Key*/
        CRYP_SetKey(hcryp, hcryp->Init.KeySize);

        /* Set decryption & Key preparation operating mode*/
        MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_KEYDERIVATION_DECRYPT);
      }
#else /* CRYP */
      /* change ALGOMODE to key preparation for decryption*/
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGOMSEL, CRYP_CTRL_ALGOMSEL_AES_KEY);

      /*  Set the Key*/
      CRYP_SetKey(hcryp, hcryp->Init.KeySize);

      /* Enable CRYP */
      __DAL_CRYP_ENABLE(hcryp);

      /* Wait for BUSY flag to be raised */
      count = CRYP_TIMEOUT_KEYPREPARATION;
      do
      {
        count-- ;
        if (count == 0U)
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
      } while (DAL_IS_BIT_SET(hcryp->Instance->STS, CRYP_FLAG_BUSY));

      /* Turn back to ALGOMODE of the configuration */
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGOMSEL, hcryp->Init.Algorithm);

#endif /* End AES or CRYP  */
    }
    else  /*Algorithm CTR */
    {
      /*  Set the Key*/
      CRYP_SetKey(hcryp, hcryp->Init.KeySize);
    }

    if (hcryp->Init.Algorithm != CRYP_AES_ECB)
    {
      /* Set the Initialization Vector*/
#if defined (AES)
      hcryp->Instance->IVR3 = *(uint32_t *)(hcryp->Init.pInitVect);
      hcryp->Instance->IVR2 = *(uint32_t *)(hcryp->Init.pInitVect + 1);
      hcryp->Instance->IVR1 = *(uint32_t *)(hcryp->Init.pInitVect + 2);
      hcryp->Instance->IVR0 = *(uint32_t *)(hcryp->Init.pInitVect + 3);
#else /* CRYP */
      hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
      hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
      hcryp->Instance->IV1L = *(uint32_t *)(hcryp->Init.pInitVect + 2);
      hcryp->Instance->IV1R = *(uint32_t *)(hcryp->Init.pInitVect + 3);
#endif /* End AES or CRYP  */
    }
  } /* if (DoKeyIVConfig == 1U) */

  /* Set the phase */
  hcryp->Phase = CRYP_PHASE_PROCESS;

  if (hcryp->Size != 0U)
  {
    /* Set the input and output addresses and start DMA transfer */
    CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), (hcryp->Size / 4U), (uint32_t)(hcryp->pCrypOutBuffPtr));
  }
  else
  {
    /* Process unlocked */
    __DAL_UNLOCK(hcryp);

    /* Change the CRYP state */
    hcryp->State = DAL_CRYP_STATE_READY;
  }

  /* Return function status */
  return DAL_OK;
}


/**
  * @brief  DMA CRYP input data process complete callback.
  * @param  hdma: DMA handle
  * @retval None
  */
static void CRYP_DMAInCplt(DMA_HandleTypeDef *hdma)
{
  CRYP_HandleTypeDef *hcryp = (CRYP_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

  /* Disable the DMA transfer for input FIFO request by resetting the DIEN bit
  in the DMACR register */
#if defined (CRYP)
  hcryp->Instance->DMACTRL &= (uint32_t)(~CRYP_DMACTRL_INEN);

#else /* AES */
  CLEAR_BIT(hcryp->Instance->CTRL, AES_CR_DMAINEN);

  /* TinyAES2, No output on CCM AES, unlock should be done when input data process complete */
  if ((hcryp->Init.Algorithm & CRYP_AES_CCM) == CRYP_AES_CCM)
  {
    /* Clear CCF flag */
    __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

    /* Change the CRYP state to ready */
    hcryp->State = DAL_CRYP_STATE_READY;

    /* Process Unlocked */
    __DAL_UNLOCK(hcryp);
  }
#endif /* End AES or CRYP */

  /* Call input data transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
  /*Call registered Input complete callback*/
  hcryp->InCpltCallback(hcryp);
#else
  /*Call legacy weak Input complete callback*/
  DAL_CRYP_InCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
}

/**
  * @brief  DMA CRYP output data process complete callback.
  * @param  hdma: DMA handle
  * @retval None
  */
static void CRYP_DMAOutCplt(DMA_HandleTypeDef *hdma)
{
  CRYP_HandleTypeDef *hcryp = (CRYP_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

  /* Disable the DMA transfer for output FIFO request by resetting
  the DOEN bit in the DMACR register */

#if defined (CRYP)

  hcryp->Instance->DMACTRL &= (uint32_t)(~CRYP_DMACTRL_OUTEN);
  #if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)
  if ((hcryp->Init.Algorithm & CRYP_AES_GCM) != CRYP_AES_GCM)
  {
    /* Disable CRYP  (not allowed in  GCM)*/
    __DAL_CRYP_DISABLE(hcryp);
  }

  #else /*NO GCM CCM */
  /* Disable CRYP */
  __DAL_CRYP_DISABLE(hcryp);
  #endif /* GCM CCM defined*/
#else /* AES */

  CLEAR_BIT(hcryp->Instance->CTRL, AES_CR_DMAOUTEN);

  /* Clear CCF flag */
  __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

  if ((hcryp->Init.Algorithm & CRYP_AES_GCM_GMAC) != CRYP_AES_GCM_GMAC)
  {
    /* Disable CRYP (not allowed in  GCM)*/
    __DAL_CRYP_DISABLE(hcryp);
  }
#endif /* End AES or CRYP */

  /* Change the CRYP state to ready */
  hcryp->State = DAL_CRYP_STATE_READY;

  /* Process unlocked */
  __DAL_UNLOCK(hcryp);
  /* Call output data transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
  /*Call registered Output complete callback*/
  hcryp->OutCpltCallback(hcryp);
#else
  /*Call legacy weak Output complete callback*/
  DAL_CRYP_OutCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
}

/**
  * @brief  DMA CRYP communication error callback.
  * @param  hdma: DMA handle
  * @retval None
  */
static void CRYP_DMAError(DMA_HandleTypeDef *hdma)
{
  CRYP_HandleTypeDef *hcryp = (CRYP_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

  /* Change the CRYP peripheral state */
  hcryp->State = DAL_CRYP_STATE_READY;

  /* DMA error code field */
  hcryp->ErrorCode |= DAL_CRYP_ERROR_DMA;

#if defined (AES)

  /* Clear CCF flag */
  __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

#endif /* AES */

  /* Call error callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
  /*Call registered error callback*/
  hcryp->ErrorCallback(hcryp);
#else
  /*Call legacy weak error callback*/
  DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
}

/**
  * @brief  Set the DMA configuration and start the DMA transfer
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  inputaddr: address of the input buffer
  * @param  Size: size of the input buffer, must be a multiple of 16.
  * @param  outputaddr: address of the output buffer
  * @retval None
  */
static void CRYP_SetDMAConfig(CRYP_HandleTypeDef *hcryp, uint32_t inputaddr, uint16_t Size, uint32_t outputaddr)
{
  /* Set the CRYP DMA transfer complete callback */
  hcryp->hdmain->XferCpltCallback = CRYP_DMAInCplt;

  /* Set the DMA input error callback */
  hcryp->hdmain->XferErrorCallback = CRYP_DMAError;

  /* Set the CRYP DMA transfer complete callback */
  hcryp->hdmaout->XferCpltCallback = CRYP_DMAOutCplt;

  /* Set the DMA output error callback */
  hcryp->hdmaout->XferErrorCallback = CRYP_DMAError;

#if defined (CRYP)

  /* Enable CRYP */
  __DAL_CRYP_ENABLE(hcryp);

  /* Enable the input DMA Stream */
  if (DAL_DMA_Start_IT(hcryp->hdmain, inputaddr, (uint32_t)&hcryp->Instance->DATAIN, Size) != DAL_OK)
  {
    /* DMA error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_DMA;

    /* Call error callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
    /*Call registered error callback*/
    hcryp->ErrorCallback(hcryp);
#else
    /*Call legacy weak error callback*/
    DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
  }
  /* Enable the output DMA Stream */
  if (DAL_DMA_Start_IT(hcryp->hdmaout, (uint32_t)&hcryp->Instance->DATAOUT, outputaddr, Size) != DAL_OK)
  {
    /* DMA error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_DMA;

    /* Call error callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
    /*Call registered error callback*/
    hcryp->ErrorCallback(hcryp);
#else
    /*Call legacy weak error callback*/
    DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
  }
  /* Enable In/Out DMA request */
  hcryp->Instance->DMACTRL = CRYP_DMACTRL_OUTEN | CRYP_DMACTRL_INEN;

#else /* AES */

  if (((hcryp->Init.Algorithm & CRYP_AES_GCM_GMAC) != CRYP_AES_GCM_GMAC)
      && ((hcryp->Init.Algorithm & CRYP_AES_CCM) != CRYP_AES_CCM))
  {
    /* Enable CRYP (not allowed in  GCM & CCM)*/
    __DAL_CRYP_ENABLE(hcryp);
  }

  /* Enable the DMA input stream */
  if (DAL_DMA_Start_IT(hcryp->hdmain, inputaddr, (uint32_t)&hcryp->Instance->DATAINR, Size) != DAL_OK)
  {
    /* DMA error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_DMA;

    /* Call error callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
    /*Call registered error callback*/
    hcryp->ErrorCallback(hcryp);
#else
    /*Call legacy weak error callback*/
    DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
  }
  /* Enable the DMA output stream */
  if (DAL_DMA_Start_IT(hcryp->hdmaout, (uint32_t)&hcryp->Instance->DATAOUTR, outputaddr, Size) != DAL_OK)
  {
    /* DMA error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_DMA;

    /* Call error callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
    /*Call registered error callback*/
    hcryp->ErrorCallback(hcryp);
#else
    /*Call legacy weak error callback*/
    DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
  }
  /*AES2v1.1.1 : CCM authentication : no init phase, only header and final phase */
  /* Enable In and Out DMA requests */
  if ((hcryp->Init.Algorithm & CRYP_AES_CCM) == CRYP_AES_CCM)
  {
    /* Enable only In DMA requests for CCM*/
    SET_BIT(hcryp->Instance->CTRL, (AES_CR_DMAINEN));
  }
  else
  {
    /* Enable In and Out DMA requests */
    SET_BIT(hcryp->Instance->CTRL, (AES_CR_DMAINEN | AES_CR_DMAOUTEN));
  }
#endif /* End AES or CRYP */
}

/**
  * @brief  Process Data: Write Input data in polling mode and used in AES functions.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Timeout: Specify Timeout value
  * @retval None
  */
static void CRYP_AES_ProcessData(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{

  uint32_t temp[4];  /* Temporary CrypOutBuff */
  uint32_t i;
#if defined (CRYP)
  uint16_t incount;  /* Temporary CrypInCount Value */
  uint16_t outcount;  /* Temporary CrypOutCount Value */
#endif

#if defined (CRYP)

  /*Temporary CrypOutCount Value*/
  incount = hcryp->CrypInCount;

  if (((hcryp->Instance->STS & CRYP_FLAG_IFNF) != 0x0U) && (incount < (hcryp->Size / 4U)))
  {
    /* Write the input block in the IN FIFO */
    hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
  }

  /* Wait for OFNE flag to be raised */
  if (CRYP_WaitOnOFNEFlag(hcryp, Timeout) != DAL_OK)
  {
    /* Disable the CRYP peripheral clock */
    __DAL_CRYP_DISABLE(hcryp);

    /* Change state & error code*/
    hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
    hcryp->State = DAL_CRYP_STATE_READY;

    /* Process unlocked */
    __DAL_UNLOCK(hcryp);
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
    /*Call registered error callback*/
    hcryp->ErrorCallback(hcryp);
#else
    /*Call legacy weak error callback*/
    DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
  }

  /*Temporary CrypOutCount Value*/
  outcount = hcryp->CrypOutCount;

  if (((hcryp->Instance->STS & CRYP_FLAG_OFNE) != 0x0U) && (outcount < (hcryp->Size / 4U)))
  {
    /* Read the output block from the Output FIFO and put them in temporary buffer then get CrypOutBuff from temporary buffer  */
    for (i = 0U; i < 4U; i++)
    {
      temp[i] = hcryp->Instance->DATAOUT;
    }
    i = 0U;
    while (((hcryp->CrypOutCount < ((hcryp->Size) / 4U))) && (i < 4U))
    {
      *(uint32_t *)(hcryp->pCrypOutBuffPtr + hcryp->CrypOutCount) = temp[i];
      hcryp->CrypOutCount++;
      i++;
    }
  }

#else /* AES */

  /* Write the input block in the IN FIFO */
  hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
  hcryp->CrypInCount++;
  hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
  hcryp->CrypInCount++;
  hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
  hcryp->CrypInCount++;
  hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
  hcryp->CrypInCount++;

  /* Wait for CCF flag to be raised */
  if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
  {
    /* Disable the CRYP peripheral clock */
    __DAL_CRYP_DISABLE(hcryp);

    /* Change state */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
    hcryp->State = DAL_CRYP_STATE_READY;

    /* Process unlocked */
    __DAL_UNLOCK(hcryp);
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
    /*Call registered error callback*/
    hcryp->ErrorCallback(hcryp);
#else
    /*Call legacy weak error callback*/
    DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
  }

  /* Clear CCF Flag */
  __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

  /* Read the output block from the output FIFO and put them in temporary buffer then get CrypOutBuff from temporary buffer*/
  for (i = 0U; i < 4U; i++)
  {
    temp[i] = hcryp->Instance->DATAOUTR;
  }
  i = 0U;
  while ((hcryp->CrypOutCount < ((hcryp->Size + 3U) / 4U)) && (i < 4U))
  {
    *(uint32_t *)(hcryp->pCrypOutBuffPtr + hcryp->CrypOutCount) = temp[i];
    hcryp->CrypOutCount++;
    i++;
  }
#endif /* End AES or CRYP */
}

/**
  * @brief  Handle CRYP block input/output data handling under interruption.
  * @note   The function is called under interruption only, once
  *         interruptions have been enabled by DAL_CRYP_Encrypt_IT or DAL_CRYP_Decrypt_IT.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module.
  * @retval DAL status
  */
static void CRYP_AES_IT(CRYP_HandleTypeDef *hcryp)
{
  uint32_t temp[4];  /* Temporary CrypOutBuff */
  uint32_t i;
#if defined (CRYP)
  uint16_t incount; /* Temporary CrypInCount Value */
  uint16_t outcount;  /* Temporary CrypOutCount Value */
#endif

  if (hcryp->State == DAL_CRYP_STATE_BUSY)
  {
#if defined (CRYP)

    /*Temporary CrypOutCount Value*/
    incount = hcryp->CrypInCount;
    if (((hcryp->Instance->STS & CRYP_FLAG_IFNF) != 0x0U) && (incount < (hcryp->Size / 4U)))
    {
      /* Write the input block in the IN FIFO */
      hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      if (hcryp->CrypInCount == ((uint16_t)(hcryp->Size) / 4U))
      {
        /* Disable interrupts */
        __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_INI);

        /* Call the input data transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
        /*Call registered Input complete callback*/
        hcryp->InCpltCallback(hcryp);
#else
        /*Call legacy weak Input complete callback*/
        DAL_CRYP_InCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
      }
    }
    /*Temporary CrypOutCount Value*/
    outcount = hcryp->CrypOutCount;

    if (((hcryp->Instance->STS & CRYP_FLAG_OFNE) != 0x0U) && (outcount < (hcryp->Size / 4U)))
    {
      /* Read the output block from the output FIFO and put them in temporary buffer then get CrypOutBuff from temporary buffer  */
      for (i = 0U; i < 4U; i++)
      {
        temp[i] = hcryp->Instance->DATAOUT;
      }
      i = 0U;
      while (((hcryp->CrypOutCount < ((hcryp->Size) / 4U))) && (i < 4U))
      {
        *(uint32_t *)(hcryp->pCrypOutBuffPtr + hcryp->CrypOutCount) = temp[i];
        hcryp->CrypOutCount++;
        i++;
      }
      if (hcryp->CrypOutCount == ((uint16_t)(hcryp->Size) / 4U))
      {
        /* Disable interrupts */
        __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_OUTI);

        /* Change the CRYP state */
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Disable CRYP */
        __DAL_CRYP_DISABLE(hcryp);

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);

        /* Call Output transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
        /*Call registered Output complete callback*/
        hcryp->OutCpltCallback(hcryp);
#else
        /*Call legacy weak Output complete callback*/
        DAL_CRYP_OutCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
      }
    }

#else /*AES*/

    /* Read the output block from the output FIFO and put them in temporary buffer then get CrypOutBuff from temporary buffer*/
    for (i = 0U; i < 4U; i++)
    {
      temp[i] = hcryp->Instance->DATAOUTR;
    }
    i = 0U;
    while ((hcryp->CrypOutCount < ((hcryp->Size + 3U) / 4U)) && (i < 4U))
    {
      *(uint32_t *)(hcryp->pCrypOutBuffPtr + hcryp->CrypOutCount) = temp[i];
      hcryp->CrypOutCount++;
      i++;
    }

    if (hcryp->CrypOutCount == (hcryp->Size / 4U))
    {
      /* Disable Computation Complete flag and errors interrupts */
      __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_CCFIE | CRYP_IT_ERRIE);

      /* Change the CRYP state */
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Disable CRYP */
      __DAL_CRYP_DISABLE(hcryp);

      /* Process Unlocked */
      __DAL_UNLOCK(hcryp);

      /* Call Output transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
      /*Call registered Output complete callback*/
      hcryp->OutCpltCallback(hcryp);
#else
      /*Call legacy weak Output complete callback*/
      DAL_CRYP_OutCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
    }
    else
    {
      /* Write the input block in the IN FIFO */
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;

      if (hcryp->CrypInCount == (hcryp->Size / 4U))
      {
        /* Call Input transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1U)
        /*Call registered Input complete callback*/
        hcryp->InCpltCallback(hcryp);
#else
        /*Call legacy weak Input complete callback*/
        DAL_CRYP_InCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
      }
    }
#endif /* End AES or CRYP  */

  }
  else
  {
    /* Busy error code field */
    hcryp->ErrorCode |= DAL_CRYP_ERROR_BUSY;
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
    /*Call registered error callback*/
    hcryp->ErrorCallback(hcryp);
#else
    /*Call legacy weak error callback*/
    DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
  }
}

/**
  * @brief  Writes Key in Key registers.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  KeySize: Size of Key
  * @retval None
  */
static void CRYP_SetKey(CRYP_HandleTypeDef *hcryp, uint32_t KeySize)
{
#if defined (CRYP)

  switch (KeySize)
  {
    case CRYP_KEYSIZE_256B:
      hcryp->Instance->K0L = *(uint32_t *)(hcryp->Init.pKey);
      hcryp->Instance->K0R = *(uint32_t *)(hcryp->Init.pKey + 1);
      hcryp->Instance->K1L = *(uint32_t *)(hcryp->Init.pKey + 2);
      hcryp->Instance->K1R = *(uint32_t *)(hcryp->Init.pKey + 3);
      hcryp->Instance->K2L = *(uint32_t *)(hcryp->Init.pKey + 4);
      hcryp->Instance->K2R = *(uint32_t *)(hcryp->Init.pKey + 5);
      hcryp->Instance->K3L = *(uint32_t *)(hcryp->Init.pKey + 6);
      hcryp->Instance->K3R = *(uint32_t *)(hcryp->Init.pKey + 7);
      break;
    case CRYP_KEYSIZE_192B:
      hcryp->Instance->K1L = *(uint32_t *)(hcryp->Init.pKey);
      hcryp->Instance->K1R = *(uint32_t *)(hcryp->Init.pKey + 1);
      hcryp->Instance->K2L = *(uint32_t *)(hcryp->Init.pKey + 2);
      hcryp->Instance->K2R = *(uint32_t *)(hcryp->Init.pKey + 3);
      hcryp->Instance->K3L = *(uint32_t *)(hcryp->Init.pKey + 4);
      hcryp->Instance->K3R = *(uint32_t *)(hcryp->Init.pKey + 5);
      break;
    case CRYP_KEYSIZE_128B:
      hcryp->Instance->K2L = *(uint32_t *)(hcryp->Init.pKey);
      hcryp->Instance->K2R = *(uint32_t *)(hcryp->Init.pKey + 1);
      hcryp->Instance->K3L = *(uint32_t *)(hcryp->Init.pKey + 2);
      hcryp->Instance->K3R = *(uint32_t *)(hcryp->Init.pKey + 3);

      break;
    default:
      break;
  }
#else /*AES*/
  switch (KeySize)
  {
    case CRYP_KEYSIZE_256B:
      hcryp->Instance->KEYR7 = *(uint32_t *)(hcryp->Init.pKey);
      hcryp->Instance->KEYR6 = *(uint32_t *)(hcryp->Init.pKey + 1);
      hcryp->Instance->KEYR5 = *(uint32_t *)(hcryp->Init.pKey + 2);
      hcryp->Instance->KEYR4 = *(uint32_t *)(hcryp->Init.pKey + 3);
      hcryp->Instance->KEYR3 = *(uint32_t *)(hcryp->Init.pKey + 4);
      hcryp->Instance->KEYR2 = *(uint32_t *)(hcryp->Init.pKey + 5);
      hcryp->Instance->KEYR1 = *(uint32_t *)(hcryp->Init.pKey + 6);
      hcryp->Instance->KEYR0 = *(uint32_t *)(hcryp->Init.pKey + 7);
      break;
    case CRYP_KEYSIZE_128B:
      hcryp->Instance->KEYR3 = *(uint32_t *)(hcryp->Init.pKey);
      hcryp->Instance->KEYR2 = *(uint32_t *)(hcryp->Init.pKey + 1);
      hcryp->Instance->KEYR1 = *(uint32_t *)(hcryp->Init.pKey + 2);
      hcryp->Instance->KEYR0 = *(uint32_t *)(hcryp->Init.pKey + 3);

      break;
    default:
      break;
  }
#endif /* End AES or CRYP  */
}

#if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)|| defined (AES)
/**
  * @brief  Encryption/Decryption process in AES GCM mode and prepare the authentication TAG
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Timeout: Timeout duration
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AESGCM_Process(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint32_t tickstart;
  uint32_t wordsize = (uint32_t)(hcryp->Size) / 4U ;
  uint16_t outcount;  /* Temporary CrypOutCount Value */
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
      hcryp->SizesSum += hcryp->Size; /* Compute message total payload length */
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
      hcryp->SizesSum = hcryp->Size; /* Merely store payload length */
    }
  }
  else
  {
    hcryp->SizesSum = hcryp->Size;
  }

  if (DoKeyIVConfig == 1U)
  {
    /*  Reset CrypHeaderCount */
    hcryp->CrypHeaderCount = 0U;

    /****************************** Init phase **********************************/

    CRYP_SET_PHASE(hcryp, CRYP_PHASE_INIT);

    /* Set the key */
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

#if defined(CRYP)

    /* Set the initialization vector and the counter : Initial Counter Block (ICB)*/
    hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
    hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
    hcryp->Instance->IV1L = *(uint32_t *)(hcryp->Init.pInitVect + 2);
    hcryp->Instance->IV1R = *(uint32_t *)(hcryp->Init.pInitVect + 3);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /* Get tick */
    tickstart = DAL_GetTick();

    /*Wait for the CRYPEN bit to be cleared*/
    while ((hcryp->Instance->CTRL & CRYP_CTRL_CRYPEN) == CRYP_CTRL_CRYPEN)
    {
      /* Check for the Timeout */
      if (Timeout != DAL_MAX_DELAY)
      {
        if (((DAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
      }
    }

#else /* AES */
    /* Workaround 1 : only AES.
    Datatype configuration must be 32 bits during Init phase. Only, after Init, and before re
    enabling the IP, datatype different from 32 bits can be configured.*/
    /* Select DATATYPE 32  */
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_DATATYPE, CRYP_DATATYPE_32B);

    /* Set the initialization vector and the counter : Initial Counter Block (ICB)*/
    hcryp->Instance->IVR3 = *(uint32_t *)(hcryp->Init.pInitVect);
    hcryp->Instance->IVR2 = *(uint32_t *)(hcryp->Init.pInitVect + 1);
    hcryp->Instance->IVR1 = *(uint32_t *)(hcryp->Init.pInitVect + 2);
    hcryp->Instance->IVR0 = *(uint32_t *)(hcryp->Init.pInitVect + 3);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /* just wait for hash computation */
    if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
    {
      /* Change state */
      hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process unlocked & return error */
      __DAL_UNLOCK(hcryp);
      return DAL_ERROR;
    }
    /* Clear CCF flag */
    __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

#endif /* End AES or CRYP  */

    /************************ Header phase *************************************/

    if (CRYP_GCMCCM_SetHeaderPhase(hcryp,  Timeout) != DAL_OK)
    {
      return DAL_ERROR;
    }

    /*************************Payload phase ************************************/

    /* Set the phase */
    hcryp->Phase = CRYP_PHASE_PROCESS;

#if defined(CRYP)

    /* Disable the CRYP peripheral */
    __DAL_CRYP_DISABLE(hcryp);

    /* Select payload phase once the header phase is performed */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_PAYLOAD);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

#else /* AES */

    /* Select payload phase once the header phase is performed */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_PAYLOAD);

#endif /* End AES or CRYP  */
  } /* if (DoKeyIVConfig == 1U) */

  if ((hcryp->Size % 16U) != 0U)
  {
    /* recalculate  wordsize */
    wordsize = ((wordsize / 4U) * 4U) ;
  }

  /* Get tick */
  tickstart = DAL_GetTick();
  /*Temporary CrypOutCount Value*/
  outcount = hcryp->CrypOutCount;

  /* Write input data and get output Data */
  while ((hcryp->CrypInCount < wordsize) && (outcount < wordsize))
  {
    /* Write plain data and get cipher data */
    CRYP_AES_ProcessData(hcryp, Timeout);

    /*Temporary CrypOutCount Value*/
    outcount = hcryp->CrypOutCount;

    /* Check for the Timeout */
    if (Timeout != DAL_MAX_DELAY)
    {
      if (((DAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state & error code */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    }
  }

  if ((hcryp->Size % 16U) != 0U)
  {
    /*  Workaround 2 :  CRYP1 & AES generates correct TAG for GCM mode only when input block size is multiple of
    128 bits. If lthe size of the last block of payload is inferior to 128 bits, when GCM encryption
    is selected, then the TAG message will be wrong.*/
    CRYP_Workaround(hcryp, Timeout);
  }

  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  Encryption/Decryption process in AES GCM mode and prepare the authentication TAG in interrupt mode
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AESGCM_Process_IT(CRYP_HandleTypeDef *hcryp)
{
  __IO uint32_t count = 0U;
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */
#if defined(AES)
  uint32_t loopcounter;
  uint32_t lastwordsize;
  uint32_t npblb;
#endif /* AES */

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
      hcryp->SizesSum += hcryp->Size; /* Compute message total payload length */
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
      hcryp->SizesSum = hcryp->Size; /* Merely store payload length */
    }
  }
  else
  {
    hcryp->SizesSum = hcryp->Size;
  }

  /* Configure Key, IV and process message (header and payload) */
  if (DoKeyIVConfig == 1U)
  {
    /*  Reset CrypHeaderCount */
    hcryp->CrypHeaderCount = 0U;

    /******************************* Init phase *********************************/

    CRYP_SET_PHASE(hcryp, CRYP_PHASE_INIT);

    /* Set the key */
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

#if defined(CRYP)
    /* Set the initialization vector and the counter : Initial Counter Block (ICB)*/
    hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
    hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
    hcryp->Instance->IV1L = *(uint32_t *)(hcryp->Init.pInitVect + 2);
    hcryp->Instance->IV1R = *(uint32_t *)(hcryp->Init.pInitVect + 3);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /*Wait for the CRYPEN bit to be cleared*/
    count = CRYP_TIMEOUT_GCMCCMINITPHASE;
    do
    {
      count-- ;
      if (count == 0U)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    } while ((hcryp->Instance->CTRL & CRYP_CTRL_CRYPEN) == CRYP_CTRL_CRYPEN);

#else /* AES */

    /* Workaround 1 : only AES
    Datatype configuration must be 32 bits during INIT phase. Only, after INIT, and before re
    enabling the IP, datatype different from 32 bits can be configured.*/
    /* Select DATATYPE 32  */
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_DATATYPE, CRYP_DATATYPE_32B);

    /* Set the initialization vector and the counter : Initial Counter Block (ICB)*/
    hcryp->Instance->IVR3 = *(uint32_t *)(hcryp->Init.pInitVect);
    hcryp->Instance->IVR2 = *(uint32_t *)(hcryp->Init.pInitVect + 1);
    hcryp->Instance->IVR1 = *(uint32_t *)(hcryp->Init.pInitVect + 2);
    hcryp->Instance->IVR0 = *(uint32_t *)(hcryp->Init.pInitVect + 3);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /* just wait for hash computation */
    count = CRYP_TIMEOUT_GCMCCMINITPHASE;
    do
    {
      count-- ;
      if (count == 0U)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));

    /* Clear CCF flag */
    __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

#endif /* End AES or CRYP */

    /***************************** Header phase *********************************/

#if defined(CRYP)

    /* Select header phase */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

    /* Enable interrupts */
    __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_INI);

    /* Enable CRYP */
    __DAL_CRYP_ENABLE(hcryp);

#else /* AES */

    /* Workaround 1: only AES , before re-enabling the IP, datatype can be configured*/
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_DATATYPE, hcryp->Init.DataType);

    /* Select header phase */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

    /* Enable computation complete flag and error interrupts */
    __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_CCFIE | CRYP_IT_ERRIE);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    if (hcryp->Init.HeaderSize == 0U) /*header phase is  skipped*/
    {
      /* Set the phase */
      hcryp->Phase = CRYP_PHASE_PROCESS;

      /* Select payload phase once the header phase is performed */
      MODIFY_REG(hcryp->Instance->CTRL, AES_CR_GCMPH, CRYP_PHASE_PAYLOAD);

      /* Write the payload Input block in the IN FIFO */
      if (hcryp->Size == 0U)
      {
        /* Disable interrupts */
        __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_CCFIE | CRYP_IT_ERRIE);

        /* Change the CRYP state */
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
      }
      else if (hcryp->Size >= 16U)
      {
        hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
        hcryp->CrypInCount++;
        hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
        hcryp->CrypInCount++;
        hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
        hcryp->CrypInCount++;
        hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
        hcryp->CrypInCount++;
        if (hcryp->CrypInCount == (hcryp->Size / 4U))
        {
          /* Call Input transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
          /*Call registered Input complete callback*/
          hcryp->InCpltCallback(hcryp);
#else
          /*Call legacy weak Input complete callback*/
          DAL_CRYP_InCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
        }
      }
      else /* Size < 16Bytes  : first block is the last block*/
      {
        /* Workaround not implemented*/
        /* Size should be %4  otherwise Tag will  be incorrectly generated for GCM Encryption:
        Workaround is implemented in polling mode, so if last block of
        payload <128bit don't use CRYP_Encrypt_IT otherwise TAG is incorrectly generated for GCM Encryption. */

        /* Compute the number of padding bytes in last block of payload */
        npblb = 16U - (uint32_t)(hcryp->Size);

        /* Number of valid words (lastwordsize) in last block */
        if ((npblb % 4U) == 0U)
        {
          lastwordsize = (16U - npblb) / 4U;
        }
        else
        {
          lastwordsize = ((16U - npblb) / 4U) + 1U;
        }

        /*  last block optionally pad the data with zeros*/
        for (loopcounter = 0U; loopcounter < lastwordsize ; loopcounter++)
        {
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
          hcryp->CrypInCount++;
        }
        while (loopcounter < 4U)
        {
          /* pad the data with zeros to have a complete block */
          hcryp->Instance->DATAINR = 0x0U;
          loopcounter++;
        }
      }
    }
    else if ((hcryp->Init.HeaderSize) < 4U)
    {
      for (loopcounter = 0U; loopcounter < hcryp->Init.HeaderSize ; loopcounter++)
      {
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
      }
      while (loopcounter < 4U)
      {
        /* pad the data with zeros to have a complete block */
        hcryp->Instance->DATAINR = 0x0U;
        loopcounter++;
      }
      /* Set the phase */
      hcryp->Phase = CRYP_PHASE_PROCESS;

      /* Select payload phase once the header phase is performed */
      CRYP_SET_PHASE(hcryp, CRYP_PHASE_PAYLOAD);

      /* Call Input transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
      /*Call registered Input complete callback*/
      hcryp->InCpltCallback(hcryp);
#else
      /*Call legacy weak Input complete callback*/
      DAL_CRYP_InCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
    }
    else if ((hcryp->Init.HeaderSize) >= 4U)
    {
      /* Write the input block in the IN FIFO */
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
      hcryp->CrypHeaderCount++;
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
      hcryp->CrypHeaderCount++;
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
      hcryp->CrypHeaderCount++;
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
      hcryp->CrypHeaderCount++;
    }
    else
    {
      /* Nothing to do */
    }

#endif /* End AES or CRYP */
  } /* end of if (DoKeyIVConfig == 1U) */

  /* Return function status */
  return DAL_OK;
}


/**
  * @brief  Encryption/Decryption process in AES GCM mode and prepare the authentication TAG using DMA
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AESGCM_Process_DMA(CRYP_HandleTypeDef *hcryp)
{
  __IO uint32_t count = 0U;
  uint32_t wordsize;
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
      hcryp->SizesSum += hcryp->Size; /* Compute message total payload length */
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
      hcryp->SizesSum = hcryp->Size; /* Merely store payload length */
    }
  }
  else
  {
    hcryp->SizesSum = hcryp->Size;
  }

  if (DoKeyIVConfig == 1U)
  {
    /*  Reset CrypHeaderCount */
    hcryp->CrypHeaderCount = 0U;

    /*************************** Init phase ************************************/

    CRYP_SET_PHASE(hcryp, CRYP_PHASE_INIT);

    /* Set the key */
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

#if defined(CRYP)
    /* Set the initialization vector and the counter : Initial Counter Block (ICB)*/
    hcryp->Instance->IV0L = *(uint32_t *)(hcryp->Init.pInitVect);
    hcryp->Instance->IV0R = *(uint32_t *)(hcryp->Init.pInitVect + 1);
    hcryp->Instance->IV1L = *(uint32_t *)(hcryp->Init.pInitVect + 2);
    hcryp->Instance->IV1R = *(uint32_t *)(hcryp->Init.pInitVect + 3);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /*Wait for the CRYPEN bit to be cleared*/
    count = CRYP_TIMEOUT_GCMCCMINITPHASE;
    do
    {
      count-- ;
      if (count == 0U)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    } while ((hcryp->Instance->CTRL & CRYP_CTRL_CRYPEN) == CRYP_CTRL_CRYPEN);

#else /* AES */

    /*Workaround 1 : only AES
    Datatype configuration must be 32 bits during Init phase. Only, after Init, and before re
    enabling the IP, datatype different from 32 bits can be configured.*/
    /* Select DATATYPE 32  */
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_DATATYPE, CRYP_DATATYPE_32B);

    /* Set the initialization vector and the counter : Initial Counter Block (ICB)*/
    hcryp->Instance->IVR3 = *(uint32_t *)(hcryp->Init.pInitVect);
    hcryp->Instance->IVR2 = *(uint32_t *)(hcryp->Init.pInitVect + 1);
    hcryp->Instance->IVR1 = *(uint32_t *)(hcryp->Init.pInitVect + 2);
    hcryp->Instance->IVR0 = *(uint32_t *)(hcryp->Init.pInitVect + 3);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /* just wait for hash computation */
    count = CRYP_TIMEOUT_GCMCCMINITPHASE;
    do
    {
      count-- ;
      if (count == 0U)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));

    /* Clear CCF flag */
    __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

#endif /* End AES or CRYP */

    /************************ Header phase *************************************/

    if (CRYP_GCMCCM_SetHeaderPhase_DMA(hcryp) != DAL_OK)
    {
      return DAL_ERROR;
    }

    /************************ Payload phase ************************************/

    /* Set the phase */
    hcryp->Phase = CRYP_PHASE_PROCESS;

#if defined(CRYP)

    /* Disable the CRYP peripheral */
    __DAL_CRYP_DISABLE(hcryp);

#endif /* CRYP */

    /* Select payload phase once the header phase is performed */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_PAYLOAD);

  } /* if (DoKeyIVConfig == 1U) */

  if (hcryp->Size != 0U)
  {
    /* CRYP1 IP V < 2.2.1  Size should be %4  otherwise Tag will  be incorrectly generated for GCM Encryption:
    Workaround is implemented in polling mode, so if last block of
    payload <128bit don't use DMA mode otherwise TAG is incorrectly generated . */
    /* Set the input and output addresses and start DMA transfer */
    if ((hcryp->Size % 16U) == 0U)
    {
      CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), (hcryp->Size / 4U), (uint32_t)(hcryp->pCrypOutBuffPtr));
    }
    else /*to compute last word<128bits, otherwise it will not be encrypted/decrypted */
    {
      wordsize = (uint32_t)(hcryp->Size) + (16U - ((uint32_t)(hcryp->Size) % 16U)) ;

      /* Set the input and output addresses and start DMA transfer, pCrypOutBuffPtr size should be %4 */
      CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), ((uint16_t)wordsize / 4U),
                        (uint32_t)(hcryp->pCrypOutBuffPtr));
    }
  }
  else
  {
    /* Process unLocked */
    __DAL_UNLOCK(hcryp);

    /* Change the CRYP state and phase */
    hcryp->State = DAL_CRYP_STATE_READY;
  }

  /* Return function status */
  return DAL_OK;
}


/**
  * @brief  AES CCM encryption/decryption processing in polling mode
  *         for TinyAES IP, no encrypt/decrypt performed, only authentication preparation.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Timeout: Timeout duration
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AESCCM_Process(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint32_t tickstart;
  uint32_t wordsize = (uint32_t)(hcryp->Size) / 4U;
  uint16_t outcount;  /* Temporary CrypOutCount Value */
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */
#if defined(AES)
  uint32_t loopcounter;
  uint32_t npblb;
  uint32_t lastwordsize;
#endif /* AES */

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
      hcryp->SizesSum += hcryp->Size; /* Compute message total payload length */
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
      hcryp->SizesSum = hcryp->Size; /* Merely store payload length */
    }
  }
  else
  {
    hcryp->SizesSum = hcryp->Size;
  }

  if (DoKeyIVConfig == 1U)
  {

    /*  Reset CrypHeaderCount */
    hcryp->CrypHeaderCount = 0U;

#if defined(CRYP)

    /********************** Init phase ******************************************/

    CRYP_SET_PHASE(hcryp, CRYP_PHASE_INIT);

    /* Set the key */
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

    /* Set the initialization vector (IV) with CTR1 information */
    hcryp->Instance->IV0L = (hcryp->Init.B0[0]) & CRYP_CCM_CTR1_0;
    hcryp->Instance->IV0R = hcryp->Init.B0[1];
    hcryp->Instance->IV1L = hcryp->Init.B0[2];
    hcryp->Instance->IV1R = (hcryp->Init.B0[3] & CRYP_CCM_CTR1_1) |  CRYP_CCM_CTR1_2;


    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /*Write  B0 packet into CRYP_DATAIN Register*/
    if (hcryp->Init.DataType == CRYP_DATATYPE_8B)
    {
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0));
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0 + 1));
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0 + 2));
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0 + 3));
    }
    else if (hcryp->Init.DataType == CRYP_DATATYPE_16B)
    {
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0), 16);
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0 + 1), 16);
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0 + 2), 16);
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0 + 3), 16);
    }
    else if (hcryp->Init.DataType == CRYP_DATATYPE_1B)
    {
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0));
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0 + 1));
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0 + 2));
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0 + 3));
    }
    else
    {
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0);
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0 + 1);
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0 + 2);
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0 + 3);
    }
    /* Get tick */
    tickstart = DAL_GetTick();

    /*Wait for the CRYPEN bit to be cleared*/
    while ((hcryp->Instance->CTRL & CRYP_CTRL_CRYPEN) == CRYP_CTRL_CRYPEN)
    {
      /* Check for the Timeout */
      if (Timeout != DAL_MAX_DELAY)
      {
        if (((DAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
      }
    }
#else /* AES */
    /*AES2v1.1.1 : CCM authentication : no init phase, only header and final phase */
    /* Select header phase */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

    /* configured encryption mode */
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_ENCRYPT);

    /* Set the key */
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

    /* Set the initialization vector with zero values*/
    hcryp->Instance->IVR3 = 0U;
    hcryp->Instance->IVR2 = 0U;
    hcryp->Instance->IVR1 = 0U;
    hcryp->Instance->IVR0 = 0U;

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /*Write the B0 packet into CRYP_DATAIN*/
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0);
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0 + 1);
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0 + 2);
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0 + 3);

    /*  wait until the end of computation */
    if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
    {
      /* Change state */
      hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process unlocked & return error */
      __DAL_UNLOCK(hcryp);
      return DAL_ERROR;
    }
    /* Clear CCF flag */
    __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

    /* Set the phase */
    hcryp->Phase = CRYP_PHASE_PROCESS;

    /* From that point the whole message must be processed, first the Header then the payload.
    First the  Header block(B1) : associated data length expressed in bytes concatenated with Associated Data (A)*/

    if (hcryp->Init.HeaderSize != 0U)
    {
      if ((hcryp->Init.HeaderSize % 4U) == 0U)
      {
        /* HeaderSize %4, no padding */
        for (loopcounter = 0U; (loopcounter < hcryp->Init.HeaderSize); loopcounter += 4U)
        {
          /* Write the Input block in the Data Input register */
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;

          if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
          {
            /* Disable the CRYP peripheral clock */
            __DAL_CRYP_DISABLE(hcryp);

            /* Change state */
            hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
            hcryp->State = DAL_CRYP_STATE_READY;

            /* Process unlocked */
            __DAL_UNLOCK(hcryp);
            return DAL_ERROR;
          }
          /* Clear CCF Flag */
          __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
        }
      }
      else
      {
        /*Write Header block in the IN FIFO without last block */
        for (loopcounter = 0U; (loopcounter < ((hcryp->Init.HeaderSize) - (hcryp->Init.HeaderSize % 4U))); loopcounter += 4U)
        {
          /* Write the input block in the data input register */
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;

          if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
          {
            /* Disable the CRYP peripheral clock */
            __DAL_CRYP_DISABLE(hcryp);

            /* Change state */
            hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
            hcryp->State = DAL_CRYP_STATE_READY;

            /* Process unlocked */
            __DAL_UNLOCK(hcryp);
            return DAL_ERROR;
          }
          /* Clear CCF Flag */
          __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
        }
        /*  Last block optionally pad the data with zeros*/
        for (loopcounter = 0U; (loopcounter < (hcryp->Init.HeaderSize % 4U)); loopcounter++)
        {
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
        }
        while (loopcounter < 4U)
        {
          /* Pad the data with zeros to have a complete block */
          hcryp->Instance->DATAINR = 0x0U;
          loopcounter++;
        }

        if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
        /* Clear CCF flag */
        __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
      }
    }
  } /* if (DoKeyIVConfig == 1U) */
  /* Then the payload: cleartext payload (not the ciphertext payload).
  Write input Data, no output Data to get */
  if (hcryp->Size != 0U)
  {
    if ((hcryp->Size % 16U) != 0U)
    {
      /* recalculate  wordsize */
      wordsize = ((wordsize / 4U) * 4U) ;
    }

    /* Get tick */
    tickstart = DAL_GetTick();
    /*Temporary CrypOutCount Value*/
    outcount = hcryp->CrypOutCount;

    while ((hcryp->CrypInCount < wordsize) && (outcount < wordsize))
    {
      /* Write plain data and get cipher data */
      CRYP_AES_ProcessData(hcryp, Timeout);

      /*Temporary CrypOutCount Value*/
      outcount = hcryp->CrypOutCount;

      /* Check for the Timeout */
      if (Timeout != DAL_MAX_DELAY)
      {
        if (((DAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
      }
    }

    if ((hcryp->Size % 16U) != 0U)
    {
      /* Compute the number of padding bytes in last block of payload */
      npblb = ((((uint32_t)(hcryp->Size) / 16U) + 1U) * 16U) - (uint32_t)(hcryp->Size);

      /* Number of valid words (lastwordsize) in last block */
      if ((npblb % 4U) == 0U)
      {
        lastwordsize = (16U - npblb) / 4U;
      }
      else
      {
        lastwordsize = ((16U - npblb) / 4U) + 1U;
      }
      /*  Last block optionally pad the data with zeros*/
      for (loopcounter = 0U; loopcounter < lastwordsize; loopcounter ++)
      {
        /* Write the last input block in the IN FIFO */
        hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
        hcryp->CrypInCount++;
      }
      while (loopcounter < 4U)
      {
        /* Pad the data with zeros to have a complete block */
        hcryp->Instance->DATAINR  = 0U;
        loopcounter++;
      }
      /* Wait for CCF flag to be raised */
      if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
      /* Clear CCF flag */
      __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

    }
  }
#endif /* End AES or CRYP */

#if defined(CRYP)

    /************************* Header phase *************************************/
    /* Header block(B1) : associated data length expressed in bytes concatenated
    with Associated Data (A)*/

    if (CRYP_GCMCCM_SetHeaderPhase(hcryp, Timeout) != DAL_OK)
    {
      return DAL_ERROR;
    }

    /********************** Payload phase ***************************************/

    /* Set the phase */
    hcryp->Phase = CRYP_PHASE_PROCESS;

    /* Disable the CRYP peripheral */
    __DAL_CRYP_DISABLE(hcryp);

    /* Select payload phase once the header phase is performed */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_PAYLOAD);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

  } /* if (DoKeyIVConfig == 1U) */

  if ((hcryp->Size % 16U) != 0U)
  {
    /* recalculate  wordsize */
    wordsize = ((wordsize / 4U) * 4U) ;
  }
  /* Get tick */
  tickstart = DAL_GetTick();
  /*Temporary CrypOutCount Value*/
  outcount = hcryp->CrypOutCount;

  /* Write input data and get output data */
  while ((hcryp->CrypInCount < wordsize) && (outcount < wordsize))
  {
    /* Write plain data and get cipher data */
    CRYP_AES_ProcessData(hcryp, Timeout);

    /* Check for the Timeout */
    if (Timeout != DAL_MAX_DELAY)
    {
      if (((DAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    }
  }

  if ((hcryp->Size % 16U) != 0U)
  {
    /* CRYP Workaround :  CRYP1 generates correct TAG  during CCM decryption only when ciphertext blocks size is multiple of
    128 bits. If lthe size of the last block of payload is inferior to 128 bits, when CCM decryption
    is selected, then the TAG message will be wrong.*/
    CRYP_Workaround(hcryp, Timeout);
  }
#endif /* CRYP */

  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  AES CCM encryption/decryption process in interrupt mode
  *         for TinyAES IP, no encrypt/decrypt performed, only authentication preparation.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AESCCM_Process_IT(CRYP_HandleTypeDef *hcryp)
{
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */
#if defined(CRYP)
  __IO uint32_t count = 0U;
#endif /* CRYP */

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
      hcryp->SizesSum += hcryp->Size; /* Compute message total payload length */
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
      hcryp->SizesSum = hcryp->Size; /* Merely store payload length */
    }
  }
  else
  {
    hcryp->SizesSum = hcryp->Size;
  }

  /* Configure Key, IV and process message (header and payload) */
  if (DoKeyIVConfig == 1U)
  {
    /*  Reset CrypHeaderCount */
    hcryp->CrypHeaderCount = 0U;

#if defined(CRYP)

    /************ Init phase ************/

    CRYP_SET_PHASE(hcryp, CRYP_PHASE_INIT);

    /* Set the key */
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

    /* Set the initialization vector (IV) with CTR1 information */
    hcryp->Instance->IV0L = (hcryp->Init.B0[0]) & CRYP_CCM_CTR1_0;
    hcryp->Instance->IV0R = hcryp->Init.B0[1];
    hcryp->Instance->IV1L = hcryp->Init.B0[2];
    hcryp->Instance->IV1R = (hcryp->Init.B0[3] & CRYP_CCM_CTR1_1) |  CRYP_CCM_CTR1_2;

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /*Write the B0 packet into CRYP_DATAIN Register*/
    if (hcryp->Init.DataType == CRYP_DATATYPE_8B)
    {
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0));
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0 + 1));
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0 + 2));
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0 + 3));
    }
    else if (hcryp->Init.DataType == CRYP_DATATYPE_16B)
    {
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0), 16);
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0 + 1), 16);
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0 + 2), 16);
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0 + 3), 16);
    }
    else if (hcryp->Init.DataType == CRYP_DATATYPE_1B)
    {
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0));
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0 + 1));
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0 + 2));
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0 + 3));
    }
    else
    {
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0);
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0 + 1);
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0 + 2);
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0 + 3);
    }
    /*Wait for the CRYPEN bit to be cleared*/
    count = CRYP_TIMEOUT_GCMCCMINITPHASE;
    do
    {
      count-- ;
      if (count == 0U)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    } while ((hcryp->Instance->CTRL & CRYP_CTRL_CRYPEN) == CRYP_CTRL_CRYPEN);

    /* Select header phase */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

  } /* end of if (DoKeyIVConfig == 1U) */

  /* Enable interrupts */
  __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_INI);

  /* Enable CRYP */
  __DAL_CRYP_ENABLE(hcryp);

#else /* AES */

    /*AES2v1.1.1 : CCM authentication : no init phase, only header and final phase */
    /* Select header phase */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

    /* configured mode and encryption mode */
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_ENCRYPT);

    /* Set the key */
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

    /* Set the initialization vector with zero values*/
    hcryp->Instance->IVR3 = 0U;
    hcryp->Instance->IVR2 = 0U;
    hcryp->Instance->IVR1 = 0U;
    hcryp->Instance->IVR0 = 0U;

    /* Enable interrupts */
    __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_CCFIE | CRYP_IT_ERRIE);
    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /*Write the B0 packet into CRYP_DATAIN*/
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0);
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0 + 1);
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0 + 2);
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0 + 3);

  } /* end of if (DoKeyIVConfig == 1U) */
#endif /* End AES or CRYP */

  /* Return function status */
  return DAL_OK;
}
/**
  * @brief  AES CCM encryption/decryption process in DMA mode
  *         for TinyAES IP, no encrypt/decrypt performed, only authentication preparation.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_AESCCM_Process_DMA(CRYP_HandleTypeDef *hcryp)
{
  uint32_t wordsize;
  __IO uint32_t count = 0U;
  uint32_t DoKeyIVConfig = 1U; /* By default, carry out peripheral Key and IV configuration */
#if defined(AES)
  uint32_t loopcounter;
  uint32_t npblb;
  uint32_t lastwordsize;
#endif

  if (hcryp->Init.KeyIVConfigSkip == CRYP_KEYIVCONFIG_ONCE)
  {
    if (hcryp->KeyIVConfig == 1U)
    {
      /* If the Key and IV configuration has to be done only once
      and if it has already been done, skip it */
      DoKeyIVConfig = 0U;
      hcryp->SizesSum += hcryp->Size; /* Compute message total payload length */
    }
    else
    {
      /* If the Key and IV configuration has to be done only once
      and if it has not been done already, do it and set KeyIVConfig
      to keep track it won't have to be done again next time */
      hcryp->KeyIVConfig = 1U;
      hcryp->SizesSum = hcryp->Size; /* Merely store payload length */
    }
  }
  else
  {
    hcryp->SizesSum = hcryp->Size;
  }

  if (DoKeyIVConfig == 1U)
  {

    /*  Reset CrypHeaderCount */
    hcryp->CrypHeaderCount = 0U;

#if defined(CRYP)

    /************************** Init phase **************************************/

    CRYP_SET_PHASE(hcryp, CRYP_PHASE_INIT);

    /* Set the key */
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

    /* Set the initialization vector (IV) with CTR1 information */
    hcryp->Instance->IV0L = (hcryp->Init.B0[0]) & CRYP_CCM_CTR1_0;
    hcryp->Instance->IV0R = hcryp->Init.B0[1];
    hcryp->Instance->IV1L = hcryp->Init.B0[2];
    hcryp->Instance->IV1R = (hcryp->Init.B0[3] & CRYP_CCM_CTR1_1) |  CRYP_CCM_CTR1_2;

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /*Write the B0 packet into CRYP_DATAIN Register*/
    if (hcryp->Init.DataType == CRYP_DATATYPE_8B)
    {
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0));
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0 + 1));
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0 + 2));
      hcryp->Instance->DATAIN = __REV(*(uint32_t *)(hcryp->Init.B0 + 3));
    }
    else if (hcryp->Init.DataType == CRYP_DATATYPE_16B)
    {
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0), 16);
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0 + 1), 16);
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0 + 2), 16);
      hcryp->Instance->DATAIN = __ROR(*(uint32_t *)(hcryp->Init.B0 + 3), 16);
    }
    else if (hcryp->Init.DataType == CRYP_DATATYPE_1B)
    {
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0));
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0 + 1));
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0 + 2));
      hcryp->Instance->DATAIN = __RBIT(*(uint32_t *)(hcryp->Init.B0 + 3));
    }
    else
    {
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0);
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0 + 1);
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0 + 2);
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.B0 + 3);
    }

    /*Wait for the CRYPEN bit to be cleared*/
    count = CRYP_TIMEOUT_GCMCCMINITPHASE;
    do
    {
      count-- ;
      if (count == 0U)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    } while ((hcryp->Instance->CTRL & CRYP_CTRL_CRYPEN) == CRYP_CTRL_CRYPEN);

#else /* AES */

    /*AES2v1.1.1 : CCM authentication : no init phase, only header and final phase */
    /* Select header phase */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

    /* configured encryption mode */
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_MODE, CRYP_OPERATINGMODE_ENCRYPT);

    /* Set the key */
    CRYP_SetKey(hcryp, hcryp->Init.KeySize);

    /* Set the initialization vector with zero values*/
    hcryp->Instance->IVR3 = 0U;
    hcryp->Instance->IVR2 = 0U;
    hcryp->Instance->IVR1 = 0U;
    hcryp->Instance->IVR0 = 0U;

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    /*Write the B0 packet into CRYP_DATAIN*/
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0);
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0 + 1);
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0 + 2);
    hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.B0 + 3);

    count = CRYP_TIMEOUT_GCMCCMINITPHASE;
    do
    {
      count-- ;
      if (count == 0U)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process Unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));
    /* Clear CCF flag */
    __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

    /* Set the phase */
    hcryp->Phase = CRYP_PHASE_PROCESS;

    /* From that point the whole message must be processed, first the Header then the payload.
    First the  Header block(B1) : associated data length expressed in bytes concatenated with Associated Data (A)*/

    if (hcryp->Init.HeaderSize != 0U)
    {
      if ((hcryp->Init.HeaderSize % 4U) == 0U)
      {
        /* HeaderSize %4, no padding */
        for (loopcounter = 0U; (loopcounter < hcryp->Init.HeaderSize); loopcounter += 4U)
        {
          /* Write the Input block in the Data Input register */
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;

          /*  wait until the end of computation */
          count = CRYP_TIMEOUT_GCMCCMINITPHASE;
          do
          {
            count-- ;
            if (count == 0U)
            {
              /* Disable the CRYP peripheral clock */
              __DAL_CRYP_DISABLE(hcryp);

              /* Change state */
              hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
              hcryp->State = DAL_CRYP_STATE_READY;

              /* Process Unlocked */
              __DAL_UNLOCK(hcryp);
              return DAL_ERROR;
            }
          } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));
          /* Clear CCF flag */
          __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
        }
      }
      else
      {
        /*Write Header block in the IN FIFO without last block */
        for (loopcounter = 0U; (loopcounter < ((hcryp->Init.HeaderSize) - (hcryp->Init.HeaderSize % 4U))); loopcounter += 4U)
        {
          /* Write the input block in the data input register */
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;

          count = CRYP_TIMEOUT_GCMCCMINITPHASE;
          do
          {
            count-- ;
            if (count == 0U)
            {
              /* Disable the CRYP peripheral clock */
              __DAL_CRYP_DISABLE(hcryp);

              /* Change state */
              hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
              hcryp->State = DAL_CRYP_STATE_READY;

              /* Process Unlocked */
              __DAL_UNLOCK(hcryp);
              return DAL_ERROR;
            }
          } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));
          /* Clear CCF flag */
          __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
        }
        /*  Last block optionally pad the data with zeros*/
        for (loopcounter = 0U; (loopcounter < (hcryp->Init.HeaderSize % 4U)); loopcounter++)
        {
          hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
          hcryp->CrypHeaderCount++ ;
        }
        while (loopcounter < 4U)
        {
          /* Pad the data with zeros to have a complete block */
          hcryp->Instance->DATAINR = 0x0U;
          loopcounter++;
        }

        count = CRYP_TIMEOUT_GCMCCMINITPHASE;
        do
        {
          count-- ;
          if (count == 0U)
          {
            /* Disable the CRYP peripheral clock */
            __DAL_CRYP_DISABLE(hcryp);

            /* Change state */
            hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
            hcryp->State = DAL_CRYP_STATE_READY;

            /* Process Unlocked */
            __DAL_UNLOCK(hcryp);
            return DAL_ERROR;
          }
        } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));
        /* Clear CCF flag */
        __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
      }
    }
  } /* if (DoKeyIVConfig == 1U) */
  /* Then the payload: cleartext payload (not the ciphertext payload).
  Write input Data, no output Data to get */
  if (hcryp->Size != 0U)
  {
    if (hcryp->Size >= 16U)
    {
      if ((hcryp->Size % 16U) == 0U)
      {
        CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), (hcryp->Size / 4U), (uint32_t)(hcryp->pCrypOutBuffPtr));
      }
      else /*to compute last word<128bits, otherwise it will not be encrypted/decrypted */
      {
        wordsize = (uint32_t)(hcryp->Size) + (16U - ((uint32_t)(hcryp->Size) % 16U)) ;

        /* Set the input and output addresses and start DMA transfer, pCrypOutBuffPtr size should be %4 */
        CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), ((uint16_t)wordsize / 4U),
                          (uint32_t)(hcryp->pCrypOutBuffPtr));
      }
    }
    if ((hcryp->Size < 16U) != 0U)
    {
      /* Compute the number of padding bytes in last block of payload */
      npblb = ((((uint32_t)(hcryp->Size) / 16U) + 1U) * 16U) - (uint32_t)(hcryp->Size);

      /* Number of valid words (lastwordsize) in last block */
      if ((npblb % 4U) == 0U)
      {
        lastwordsize = (16U - npblb) / 4U;
      }
      else
      {
        lastwordsize = ((16U - npblb) / 4U) + 1U;
      }
      /*  Last block optionally pad the data with zeros*/
      for (loopcounter = 0U; loopcounter < lastwordsize; loopcounter ++)
      {
        /* Write the last input block in the IN FIFO */
        hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
        hcryp->CrypInCount++;
      }
      while (loopcounter < 4U)
      {
        /* Pad the data with zeros to have a complete block */
        hcryp->Instance->DATAINR  = 0U;
        loopcounter++;
      }
      count = CRYP_TIMEOUT_GCMCCMINITPHASE;
      do
      {
        count-- ;
        if (count == 0U)
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process Unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
      } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));
      /* Clear CCF flag */
      __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

      /* Process unlocked */
      __DAL_UNLOCK(hcryp);

      /* Change the CRYP state and phase */
      hcryp->State = DAL_CRYP_STATE_READY;
    }
  }
  else
  {
    /* Process unLocked */
    __DAL_UNLOCK(hcryp);

    /* Change the CRYP state and phase */
    hcryp->State = DAL_CRYP_STATE_READY;
  }
#endif /* AES */
#if defined(CRYP)
    /********************* Header phase *****************************************/

    if (CRYP_GCMCCM_SetHeaderPhase_DMA(hcryp) != DAL_OK)
    {
      return DAL_ERROR;
    }

    /******************** Payload phase *****************************************/

    /* Set the phase */
    hcryp->Phase = CRYP_PHASE_PROCESS;

    /* Disable the CRYP peripheral */
    __DAL_CRYP_DISABLE(hcryp);

    /* Select payload phase once the header phase is performed */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_PAYLOAD);

  } /* if (DoKeyIVConfig == 1U) */
  if (hcryp->Size != 0U)
  {
    /* Size should be %4  otherwise Tag will  be incorrectly generated for GCM Encryption & CCM Decryption
    Workaround is implemented in polling mode, so if last block of
    payload <128bit don't use DAL_CRYP_AESGCM_DMA otherwise TAG is incorrectly generated for GCM Encryption. */
    /* Set the input and output addresses and start DMA transfer */
    if ((hcryp->Size % 16U) == 0U)
    {
      CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), hcryp->Size / 4U, (uint32_t)(hcryp->pCrypOutBuffPtr));
    }
    else
    {
      wordsize = (uint32_t)(hcryp->Size) + 16U - ((uint32_t)(hcryp->Size) % 16U) ;

      /* Set the input and output addresses and start DMA transfer, pCrypOutBuffPtr size should be %4*/
      CRYP_SetDMAConfig(hcryp, (uint32_t)(hcryp->pCrypInBuffPtr), (uint16_t)wordsize / 4U,
                        (uint32_t)(hcryp->pCrypOutBuffPtr));
    }
  }
  else /*Size = 0*/
  {
    /* Process unlocked */
    __DAL_UNLOCK(hcryp);

    /* Change the CRYP state and phase */
    hcryp->State = DAL_CRYP_STATE_READY;
  }
#endif /* CRYP */
  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  Sets the payload phase in iterrupt mode
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @retval state
  */
static void CRYP_GCMCCM_SetPayloadPhase_IT(CRYP_HandleTypeDef *hcryp)
{
  uint32_t loopcounter;
  uint32_t temp[4];  /* Temporary CrypOutBuff */
  uint32_t lastwordsize;
  uint32_t npblb;
  uint32_t i;
#if defined(AES)
  uint16_t outcount;  /* Temporary CrypOutCount Value */
#endif /* AES */

  /***************************** Payload phase *******************************/

#if defined(CRYP)
  if (hcryp->Size == 0U)
  {
    /* Disable interrupts */
    __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_INI | CRYP_IT_OUTI);

    /* Process unlocked */
    __DAL_UNLOCK(hcryp);

    /* Change the CRYP state */
    hcryp->State = DAL_CRYP_STATE_READY;
  }

  else if (((hcryp->Size / 4U) - (hcryp->CrypInCount)) >= 4U)
  {
    /* Write the input block in the IN FIFO */
    hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    if (((hcryp->Size / 4U) == hcryp->CrypInCount) && ((hcryp->Size % 16U) == 0U))
    {
      /* Disable interrupts */
      __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_INI);

      /* Call the input data transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1U)
      /*Call registered Input complete callback*/
      hcryp->InCpltCallback(hcryp);
#else
      /*Call legacy weak Input complete callback*/
      DAL_CRYP_InCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
    }
    if (hcryp->CrypOutCount < (hcryp->Size / 4U))
    {
      /* Read the output block from the Output FIFO and put them in temporary buffer then get CrypOutBuff from temporary buffer  */
      for (i = 0U; i < 4U; i++)
      {
        temp[i] = hcryp->Instance->DATAOUT;
      }
      i = 0U;
      while (((hcryp->CrypOutCount < ((hcryp->Size) / 4U))) && (i < 4U))
      {
        *(uint32_t *)(hcryp->pCrypOutBuffPtr + hcryp->CrypOutCount) = temp[i];
        hcryp->CrypOutCount++;
        i++;
      }
      if (((hcryp->Size / 4U) == hcryp->CrypOutCount) && ((hcryp->Size % 16U) == 0U))
      {
        /* Disable interrupts */
        __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_OUTI);

        /* Change the CRYP state */
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Disable CRYP */
        __DAL_CRYP_DISABLE(hcryp);

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);

        /* Call output transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
        /*Call registered Output complete callback*/
        hcryp->OutCpltCallback(hcryp);
#else
        /*Call legacy weak Output complete callback*/
        DAL_CRYP_OutCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
      }
    }
  }
  else if ((hcryp->Size % 16U) != 0U)
  {
    /* Size should be %4 in word and %16 in byte  otherwise TAG will  be incorrectly generated for GCM Encryption & CCM Decryption
    Workaround is implemented in polling mode, so if last block of
    payload <128bit don't use CRYP_AESGCM_Encrypt_IT otherwise TAG is incorrectly generated. */

    /* Compute the number of padding bytes in last block of payload */
    npblb = ((((uint32_t)(hcryp->Size) / 16U) + 1U) * 16U) - (uint32_t)(hcryp->Size);

    /* Number of valid words (lastwordsize) in last block */
    if ((npblb % 4U) == 0U)
    {
      lastwordsize = (16U - npblb) / 4U;
    }
    else
    {
      lastwordsize = ((16U - npblb) / 4U) + 1U;
    }

    /*  Last block optionally pad the data with zeros*/
    for (loopcounter = 0U; loopcounter < lastwordsize; loopcounter++)
    {
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
    }
    while (loopcounter < 4U)
    {
      /* Pad the data with zeros to have a complete block */
      hcryp->Instance->DATAIN = 0x0U;
      loopcounter++;
    }
    __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_INI);

    if ((hcryp->Instance->STS & CRYP_FLAG_OFNE) != 0x0U)
    {
      for (i = 0U; i < 4U; i++)
      {
        temp[i] = hcryp->Instance->DATAOUT;
      }
      if (((hcryp->Size) / 4U) == 0U)
      {
        for (i = 0U; i < ((uint32_t)(hcryp->Size) % 4U); i++)
        {
          *(uint32_t *)(hcryp->pCrypOutBuffPtr + hcryp->CrypOutCount) = temp[i];
          hcryp->CrypOutCount++;
        }
      }
      i = 0x0U;
      while (((hcryp->CrypOutCount < ((hcryp->Size) / 4U))) && (i < 4U))
      {
        *(uint32_t *)(hcryp->pCrypOutBuffPtr + hcryp->CrypOutCount) = temp[i];
        hcryp->CrypOutCount++;
        i++;
      }
    }
    if (hcryp->CrypOutCount >= (hcryp->Size / 4U))
    {
      /* Disable interrupts */
      __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_OUTI | CRYP_IT_INI);

      /* Change the CRYP peripheral state */
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process unlocked */
      __DAL_UNLOCK(hcryp);

      /* Call output transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
      /*Call registered Output complete callback*/
      hcryp->OutCpltCallback(hcryp);
#else
      /*Call legacy weak Output complete callback*/
      DAL_CRYP_OutCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
    }
  }
  else
  {
    /* Nothing to do */
  }
#else /* AES */

  /* Read the output block from the output FIFO and put them in temporary buffer then get CrypOutBuff from temporary buffer*/
  for (i = 0U; i < 4U; i++)
  {
    temp[i] = hcryp->Instance->DATAOUTR;
  }
  i = 0U;
  while ((hcryp->CrypOutCount < ((hcryp->Size + 3U) / 4U)) && (i < 4U))
  {
    *(uint32_t *)(hcryp->pCrypOutBuffPtr + hcryp->CrypOutCount) = temp[i];
    hcryp->CrypOutCount++;
    i++;
  }
  /*Temporary CrypOutCount Value*/
  outcount = hcryp->CrypOutCount;

  if ((hcryp->CrypOutCount >= (hcryp->Size / 4U)) && ((outcount * 4U) >=  hcryp->Size))
  {
    /* Disable computation complete flag and errors interrupts */
    __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_CCFIE | CRYP_IT_ERRIE);

    /* Change the CRYP state */
    hcryp->State = DAL_CRYP_STATE_READY;

    /* Process unlocked */
    __DAL_UNLOCK(hcryp);

    /* Call output transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
    /*Call registered Output complete callback*/
    hcryp->OutCpltCallback(hcryp);
#else
    /*Call legacy weak Output complete callback*/
    DAL_CRYP_OutCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
  }

  else if (((hcryp->Size / 4U) - (hcryp->CrypInCount)) >= 4U)
  {
    /* Write the input block in the IN FIFO */
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
    if ((hcryp->CrypInCount == (hcryp->Size / 4U)) && ((hcryp->Size % 16U) == 0U))
      {
        /* Call Input transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
        /*Call registered Input complete callback*/
        hcryp->InCpltCallback(hcryp);
#else
        /*Call legacy weak Input complete callback*/
        DAL_CRYP_InCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
      }
  }
  else /* Last block of payload < 128bit*/
  {
    /* Workaround not implemented, Size should be %4  otherwise Tag will  be incorrectly
    generated for GCM Encryption & CCM Decryption. Workaround is implemented in polling mode, so if last block of
    payload <128bit don't use CRYP_Encrypt_IT otherwise TAG is incorrectly generated for GCM Encryption & CCM Decryption. */

    /* Compute the number of padding bytes in last block of payload */
    npblb = ((((uint32_t)(hcryp->Size) / 16U) + 1U) * 16U) - (uint32_t)(hcryp->Size);

    /* Number of valid words (lastwordsize) in last block */
    if ((npblb % 4U) == 0U)
    {
      lastwordsize = (16U - npblb) / 4U;
    }
    else
    {
      lastwordsize = ((16U - npblb) / 4U) + 1U;
    }

    /*  Last block optionally pad the data with zeros*/
    for (loopcounter = 0U; loopcounter < lastwordsize; loopcounter++)
    {
      hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
    }
    while (loopcounter < 4U)
    {
      /* pad the data with zeros to have a complete block */
      hcryp->Instance->DATAINR = 0x0U;
      loopcounter++;
    }
  }
#endif /* AES */

}


/**
  * @brief  Sets the header phase in polling mode
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module(Header & HeaderSize)
  * @param  Timeout: Timeout value
  * @retval state
  */
static DAL_StatusTypeDef CRYP_GCMCCM_SetHeaderPhase(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint32_t loopcounter;
  uint32_t size_in_bytes;
  uint32_t tmp;
  uint32_t mask[12] = {0x0U, 0xFF000000U, 0xFFFF0000U, 0xFFFFFF00U,  /* 32-bit data type */
                       0x0U, 0x0000FF00U, 0x0000FFFFU, 0xFF00FFFFU,  /* 16-bit data type */
                       0x0U, 0x000000FFU, 0x0000FFFFU, 0x00FFFFFFU}; /*  8-bit data type */

  /***************************** Header phase for GCM/GMAC or CCM *********************************/

  if (hcryp->Init.HeaderWidthUnit == CRYP_HEADERWIDTHUNIT_WORD)
  {
    size_in_bytes = hcryp->Init.HeaderSize * 4U;
  }
  else
  {
    size_in_bytes = hcryp->Init.HeaderSize;
  }

  if (size_in_bytes != 0U)
  {

#if defined(CRYP)

    /* Select header phase */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    if ((size_in_bytes % 16U) == 0U)
    {
      /* HeaderSize %4, no padding */
      for (loopcounter = 0U; (loopcounter < (size_in_bytes / 4U)); loopcounter += 4U)
      {
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;

        /* Wait for IFEM to be raised */
        if (CRYP_WaitOnIFEMFlag(hcryp, Timeout) != DAL_OK)
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
      }
    }
    else
    {
      /*Write header block in the IN FIFO without last block */
      for (loopcounter = 0U; (loopcounter < ((size_in_bytes / 16U) * 4U)); loopcounter += 4U)
      {
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;

        /* Wait for IFEM to be raised */
        if (CRYP_WaitOnIFEMFlag(hcryp, Timeout) != DAL_OK)
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
      }
      /*  Last block optionally pad the data with zeros*/
      for (loopcounter = 0U; (loopcounter < ((size_in_bytes / 4U) % 4U)); loopcounter++)
      {
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
      }
      /* If the header size is a multiple of words */
      if ((size_in_bytes % 4U) == 0U)
      {
        /* Pad the data with zeros to have a complete block */
        while (loopcounter < 4U)
        {
          hcryp->Instance->DATAIN = 0x0U;
          loopcounter++;
        }
      }
      else
      {
        /* Enter last bytes, padded with zeroes */
        tmp =  *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        tmp &= mask[(hcryp->Init.DataType * 2U) + (size_in_bytes % 4U)];
        hcryp->Instance->DATAIN = tmp;
        loopcounter++;
        /* Pad the data with zeros to have a complete block */
        while (loopcounter < 4U)
        {
          hcryp->Instance->DATAIN = 0x0U;
          loopcounter++;
        }
      }
      /* Wait for CCF IFEM to be raised */
      if (CRYP_WaitOnIFEMFlag(hcryp, Timeout) != DAL_OK)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    }
    /* Wait until the complete message has been processed */
    if (CRYP_WaitOnBUSYFlag(hcryp, Timeout) != DAL_OK)
    {
      /* Disable the CRYP peripheral clock */
      __DAL_CRYP_DISABLE(hcryp);

      /* Change state */
      hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process unlocked & return error */
      __DAL_UNLOCK(hcryp);
      return DAL_ERROR;
    }

#else /* AES */

    if (hcryp->Init.Algorithm == CRYP_AES_GCM_GMAC)
    {
      /* Workaround 1 :only AES before re-enabling the IP, datatype can be configured.*/
      MODIFY_REG(hcryp->Instance->CTRL, AES_CR_DATATYPE, hcryp->Init.DataType);

      /* Select header phase */
      CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

      /* Enable the CRYP peripheral */
      __DAL_CRYP_ENABLE(hcryp);

    }
    /* If size_in_bytes is a multiple of blocks (a multiple of four 32-bits words ) */
    if ((size_in_bytes % 16U) == 0U)
    {
      /* No padding */
      for (loopcounter = 0U; (loopcounter < (size_in_bytes / 4U)); loopcounter += 4U)
      {
        /* Write the input block in the data input register */
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;

        if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
        /* Clear CCF flag */
        __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
      }
    }
    else
    {
      /*Write header block in the IN FIFO without last block */
      for (loopcounter = 0U; (loopcounter < ((size_in_bytes / 16U) * 4U)); loopcounter += 4U)
      {
        /* Write the input block in the data input register */
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;

        if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
        /* Clear CCF flag */
        __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
      }
      /* Write last complete words */
      for (loopcounter = 0U; (loopcounter < ((size_in_bytes / 4U) % 4U)); loopcounter++)
      {
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
      }
      /* If the header size is a multiple of words */
      if ((size_in_bytes % 4U) == 0U)
      {
        /* Pad the data with zeros to have a complete block */
        while (loopcounter < 4U)
        {
          hcryp->Instance->DATAINR = 0x0U;
          loopcounter++;
        }
      }
      else
      {
        /* Enter last bytes, padded with zeroes */
        tmp =  *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        tmp &= mask[(hcryp->Init.DataType * 2U) + (size_in_bytes % 4U)];
        hcryp->Instance->DATAINR = tmp;
        loopcounter++;
        /* Pad the data with zeros to have a complete block */
        while (loopcounter < 4U)
        {
          hcryp->Instance->DATAINR = 0x0U;
          loopcounter++;
        }
      }

      if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
      /* Clear CCF flag */
      __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
    }
#endif /* End AES or CRYP */
  }
  else
  {
#if defined(AES)
    if (hcryp->Init.Algorithm == CRYP_AES_GCM_GMAC)
    {
      /*Workaround 1: only AES, before re-enabling the IP, datatype can be configured.*/
      MODIFY_REG(hcryp->Instance->CTRL, AES_CR_DATATYPE, hcryp->Init.DataType);

      /* Select header phase */
      CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

      /* Enable the CRYP peripheral */
      __DAL_CRYP_ENABLE(hcryp);
    }
#endif /* AES */
  }
  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  Sets the header phase when using DMA in process
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module(Header & HeaderSize)
  * @retval None
  */
static DAL_StatusTypeDef CRYP_GCMCCM_SetHeaderPhase_DMA(CRYP_HandleTypeDef *hcryp)
{
  __IO uint32_t count  = 0U;
  uint32_t loopcounter;
  uint32_t headersize_in_bytes;
  uint32_t tmp;
  uint32_t mask[12] = {0x0U, 0xFF000000U, 0xFFFF0000U, 0xFFFFFF00U,  /* 32-bit data type */
                       0x0U, 0x0000FF00U, 0x0000FFFFU, 0xFF00FFFFU,  /* 16-bit data type */
                       0x0U, 0x000000FFU, 0x0000FFFFU, 0x00FFFFFFU}; /*  8-bit data type */

  /***************************** Header phase for GCM/GMAC or CCM *********************************/
  if (hcryp->Init.HeaderWidthUnit == CRYP_HEADERWIDTHUNIT_WORD)
  {
    headersize_in_bytes = hcryp->Init.HeaderSize * 4U;
  }
  else
  {
    headersize_in_bytes = hcryp->Init.HeaderSize;
  }
  
  if (headersize_in_bytes != 0U)
  {

#if defined(CRYP)

    /* Select header phase */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);

    if ((headersize_in_bytes % 16U) == 0U)
    {
      /* HeaderSize %4, no padding */
      for (loopcounter = 0U; (loopcounter < (headersize_in_bytes / 4U)); loopcounter += 4U)
      {
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;

        /* Wait for IFEM to be raised */
        count = CRYP_TIMEOUT_GCMCCMHEADERPHASE;
        do
        {
          count-- ;
          if (count == 0U)
          {
            /* Disable the CRYP peripheral clock */
            __DAL_CRYP_DISABLE(hcryp);

            /* Change state */
            hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
            hcryp->State = DAL_CRYP_STATE_READY;

            /* Process unlocked */
            __DAL_UNLOCK(hcryp);
            return DAL_ERROR;
          }
        } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, CRYP_FLAG_IFEM));
      }
    }
    else
    {
      /*Write header block in the IN FIFO without last block */
      for (loopcounter = 0U; (loopcounter < ((headersize_in_bytes / 16U) * 4U)); loopcounter += 4U)
      {
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;

        /* Wait for IFEM to be raised */
        count = CRYP_TIMEOUT_GCMCCMHEADERPHASE;
        do
        {
          count-- ;
          if (count == 0U)
          {
            /* Disable the CRYP peripheral clock */
            __DAL_CRYP_DISABLE(hcryp);

            /* Change state */
            hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
            hcryp->State = DAL_CRYP_STATE_READY;

            /* Process unlocked */
            __DAL_UNLOCK(hcryp);
            return DAL_ERROR;
          }
        } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, CRYP_FLAG_IFEM));
      }
      /*  Last block optionally pad the data with zeros*/
      for (loopcounter = 0U; (loopcounter < ((headersize_in_bytes / 4U) % 4U)); loopcounter++)
      {
        hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
      }
      /* If the header size is a multiple of words */
      if ((headersize_in_bytes % 4U) == 0U)
      {
        /* Pad the data with zeros to have a complete block */
        while (loopcounter < 4U)
        {
          hcryp->Instance->DATAIN = 0x0U;
          loopcounter++;
        }
      }
      else
      {
        /* Enter last bytes, padded with zeroes */
        tmp =  *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        tmp &= mask[(hcryp->Init.DataType * 2U) + (headersize_in_bytes % 4U)];
        hcryp->Instance->DATAIN = tmp;
        loopcounter++;
        /* Pad the data with zeros to have a complete block */
        while (loopcounter < 4U)
        {
          hcryp->Instance->DATAIN = 0x0U;
          loopcounter++;
        }
      }
      /* Wait for IFEM to be raised */
      count = CRYP_TIMEOUT_GCMCCMHEADERPHASE;
      do
      {
        count-- ;
        if (count == 0U)
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
      } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, CRYP_FLAG_IFEM));
    }
    /* Wait until the complete message has been processed */
    count = CRYP_TIMEOUT_GCMCCMHEADERPHASE;
    do
    {
      count-- ;
      if (count == 0U)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
        return DAL_ERROR;
      }
    } while (DAL_IS_BIT_SET(hcryp->Instance->STS, CRYP_FLAG_BUSY));

#else /* AES */

    if (hcryp->Init.Algorithm == CRYP_AES_GCM_GMAC)
    {
      /* Workaround 1: only AES, before re-enabling the IP, datatype can be configured.*/
      MODIFY_REG(hcryp->Instance->CTRL, AES_CR_DATATYPE, hcryp->Init.DataType);

      /* Select header phase */
      CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

      /* Enable the CRYP peripheral */
      __DAL_CRYP_ENABLE(hcryp);
    }
    if ((headersize_in_bytes % 16U) == 0U)
    {
      /* HeaderSize %4, no padding */
      for (loopcounter = 0U; (loopcounter < (headersize_in_bytes / 4U)); loopcounter += 4U)
      {
        /* Write the input block in the data input register */
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;

        /*Wait on CCF flag*/
        count = CRYP_TIMEOUT_GCMCCMHEADERPHASE;
        do
        {
          count-- ;
          if (count == 0U)
          {
            /* Disable the CRYP peripheral clock */
            __DAL_CRYP_DISABLE(hcryp);

            /* Change state */
            hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
            hcryp->State = DAL_CRYP_STATE_READY;

            /* Process unlocked */
            __DAL_UNLOCK(hcryp);
            return DAL_ERROR;
          }
        } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));

        /* Clear CCF flag */
        __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
      }
    }
    else
    {
      /*Write header block in the IN FIFO without last block */
      for (loopcounter = 0U; (loopcounter < ((headersize_in_bytes / 16U) * 4U)); loopcounter += 4U)
      {
        /* Write the Input block in the Data Input register */
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;

        /*Wait on CCF flag*/
        count = CRYP_TIMEOUT_GCMCCMHEADERPHASE;
        do
        {
          count-- ;
          if (count == 0U)
          {
            /* Disable the CRYP peripheral clock */
            __DAL_CRYP_DISABLE(hcryp);

            /* Change state */
            hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
            hcryp->State = DAL_CRYP_STATE_READY;

            /* Process unlocked */
            __DAL_UNLOCK(hcryp);
            return DAL_ERROR;
          }
        } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));

        /* Clear CCF flag */
        __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
      }
      /*  Last block optionally pad the data with zeros*/
      for (loopcounter = 0U; (loopcounter < ((headersize_in_bytes /4U) % 4U)); loopcounter++)
      {
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        hcryp->CrypHeaderCount++ ;
      }
      /* If the header size is a multiple of words */
      if ((headersize_in_bytes % 4U) == 0U)
      {
        /* Pad the data with zeros to have a complete block */
        while (loopcounter < 4U)
        {
          hcryp->Instance->DATAINR = 0x0U;
          loopcounter++;
        }
      }
      else
      {
        /* Enter last bytes, padded with zeroes */
        tmp =  *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
        tmp &= mask[(hcryp->Init.DataType * 2U) + (headersize_in_bytes % 4U)];
        hcryp->Instance->DATAINR = tmp;
        loopcounter++;
        /* Pad the data with zeros to have a complete block */
        while (loopcounter < 4U)
        {
          hcryp->Instance->DATAINR = 0x0U;
          loopcounter++;
        }
      }
      /*Wait on CCF flag*/
      count = CRYP_TIMEOUT_GCMCCMHEADERPHASE;
      do
      {
        count-- ;
        if (count == 0U)
        {
          /* Disable the CRYP peripheral clock */
          __DAL_CRYP_DISABLE(hcryp);

          /* Change state */
          hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
          hcryp->State = DAL_CRYP_STATE_READY;

          /* Process unlocked */
          __DAL_UNLOCK(hcryp);
          return DAL_ERROR;
        }
      } while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF));

      /* Clear CCF flag */
      __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);
    }
#endif /* End AES or CRYP  */
  }
  else
  {
#if defined(AES)
    if (hcryp->Init.Algorithm == CRYP_AES_GCM_GMAC)
    {
      /*Workaround 1: only AES, before re-enabling the IP, datatype can be configured.*/
      MODIFY_REG(hcryp->Instance->CTRL, AES_CR_DATATYPE, hcryp->Init.DataType);

      /* Select header phase */
      CRYP_SET_PHASE(hcryp, CRYP_PHASE_HEADER);

      /* Enable the CRYP peripheral */
      __DAL_CRYP_ENABLE(hcryp);
    }
#endif /* AES */
  }
  /* Return function status */
  return DAL_OK;
}

/**
  * @brief  Sets the header phase in interrupt mode
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module(Header & HeaderSize)
  * @retval None
  */
static void CRYP_GCMCCM_SetHeaderPhase_IT(CRYP_HandleTypeDef *hcryp)
{
  uint32_t loopcounter;
#if defined(AES)
  uint32_t lastwordsize;
  uint32_t npblb;
#endif
  uint32_t headersize_in_bytes;
  uint32_t tmp;
  uint32_t mask[12] = {0x0U, 0xFF000000U, 0xFFFF0000U, 0xFFFFFF00U,  /* 32-bit data type */
                       0x0U, 0x0000FF00U, 0x0000FFFFU, 0xFF00FFFFU,  /* 16-bit data type */
                       0x0U, 0x000000FFU, 0x0000FFFFU, 0x00FFFFFFU}; /*  8-bit data type */

  if (hcryp->Init.HeaderWidthUnit == CRYP_HEADERWIDTHUNIT_WORD)
  {
    headersize_in_bytes = hcryp->Init.HeaderSize * 4U;
  }
  else
  {
    headersize_in_bytes = hcryp->Init.HeaderSize;
  }

  /***************************** Header phase *********************************/

#if defined(CRYP)
  if (headersize_in_bytes <= ((uint32_t)(hcryp->CrypHeaderCount) * 4U))
  {
    /* Disable interrupts */
    __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_INI);

    /* Disable the CRYP peripheral */
    __DAL_CRYP_DISABLE(hcryp);

    /* Set the phase */
    hcryp->Phase = CRYP_PHASE_PROCESS;

    /* Select payload phase once the header phase is performed */
    CRYP_SET_PHASE(hcryp, CRYP_PHASE_PAYLOAD);

    /* Enable Interrupts */
    __DAL_CRYP_ENABLE_IT(hcryp, CRYP_IT_INI | CRYP_IT_OUTI);

    /* Enable the CRYP peripheral */
    __DAL_CRYP_ENABLE(hcryp);
  }
  else if (((headersize_in_bytes / 4U) - (hcryp->CrypHeaderCount)) >= 4U)

  {
    /* HeaderSize %4, no padding */
    hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
    hcryp->CrypHeaderCount++ ;
    hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
    hcryp->CrypHeaderCount++  ;
    hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
    hcryp->CrypHeaderCount++ ;
    hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
    hcryp->CrypHeaderCount++ ;
  }
  else
  {
    /*  Last block optionally pad the data with zeros*/
    for (loopcounter = 0U; loopcounter < ((headersize_in_bytes / 4U) % 4U); loopcounter++)
    {
      hcryp->Instance->DATAIN = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
      hcryp->CrypHeaderCount++ ;
    }
    if ((headersize_in_bytes % 4U) == 0U)
    {
      /* Pad the data with zeros to have a complete block */
      while (loopcounter < 4U)
      {
        hcryp->Instance->DATAIN = 0x0U;
        loopcounter++;
        hcryp->CrypHeaderCount++;
      }
    }
    else
    {
      /* Enter last bytes, padded with zeros */
      tmp =  *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
      tmp &= mask[(hcryp->Init.DataType * 2U) + (headersize_in_bytes % 4U)];
      hcryp->Instance->DATAIN = tmp;
      loopcounter++;
      hcryp->CrypHeaderCount++;
      /* Pad the data with zeros to have a complete block */
    while (loopcounter < 4U)
    {
      hcryp->Instance->DATAIN = 0x0U;
      loopcounter++;
        hcryp->CrypHeaderCount++;
      }
    }
  }
#else /* AES */

  if (headersize_in_bytes <= ((uint32_t)(hcryp->CrypHeaderCount) * 4U))
  {
    /* Set the phase */
    hcryp->Phase = CRYP_PHASE_PROCESS;

    /*  Payload phase not supported in CCM AES2  */
    if (hcryp->Init.Algorithm == CRYP_AES_GCM_GMAC)
    {
      /* Select payload phase once the header phase is performed */
      MODIFY_REG(hcryp->Instance->CTRL, AES_CR_GCMPH, CRYP_PHASE_PAYLOAD);
    }
    if (hcryp->Init.Algorithm == CRYP_AES_CCM)
    {
      /* Increment CrypHeaderCount to pass in CRYP_GCMCCM_SetPayloadPhase_IT */
      hcryp->CrypHeaderCount++;
    }
    /* Write the payload Input block in the IN FIFO */
    if (hcryp->Size == 0U)
    {
      /* Disable interrupts */
      __DAL_CRYP_DISABLE_IT(hcryp, CRYP_IT_CCFIE | CRYP_IT_ERRIE);

      /* Change the CRYP state */
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process unlocked */
      __DAL_UNLOCK(hcryp);
    }
    else if (hcryp->Size >= 16U)
    {
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
      hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;

      if ((hcryp->CrypInCount == (hcryp->Size / 4U)) && ((hcryp->Size % 16U) == 0U))
      {
        /* Call the input data transfer complete callback */
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
        /*Call registered Input complete callback*/
        hcryp->InCpltCallback(hcryp);
#else
        /*Call legacy weak Input complete callback*/
        DAL_CRYP_InCpltCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
      }
    }
    else /* Size < 4 words  : first block is the last block*/
    {
      /* Workaround not implemented, Size should be %4  otherwise Tag will  be incorrectly
      generated for GCM Encryption. Workaround is implemented in polling mode, so if last block of
      payload <128bit don't use CRYP_Encrypt_IT otherwise TAG is incorrectly generated for GCM Encryption. */

      /* Compute the number of padding bytes in last block of payload */
      npblb = ((((uint32_t)(hcryp->Size) / 16U) + 1U) * 16U) - (uint32_t)(hcryp->Size);

      /* Number of valid words (lastwordsize) in last block */
      if ((npblb % 4U) == 0U)
      {
        lastwordsize = (16U - npblb) / 4U;
      }
      else
      {
        lastwordsize = ((16U - npblb) / 4U) + 1U;
      }

      /*  Last block optionally pad the data with zeros*/
      for (loopcounter = 0U; loopcounter < lastwordsize; loopcounter++)
      {
        hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
        hcryp->CrypInCount++;
      }
      while (loopcounter < 4U)
      {
        /* Pad the data with zeros to have a complete block */
        hcryp->Instance->DATAINR = 0x0U;
        loopcounter++;
      }
    }
  }
  else if (((headersize_in_bytes / 4U) - (hcryp->CrypHeaderCount)) >= 4U)
  {
    /* Write the input block in the IN FIFO */
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
    hcryp->CrypHeaderCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
    hcryp->CrypHeaderCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
    hcryp->CrypHeaderCount++;
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
    hcryp->CrypHeaderCount++;
  }
  else /*HeaderSize < 4 or HeaderSize >4 & HeaderSize %4 != 0*/
  {
    /*  Last block optionally pad the data with zeros*/
    for (loopcounter = 0U; loopcounter < ((headersize_in_bytes / 4U) % 4U); loopcounter++)
    {
      hcryp->Instance->DATAINR = *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
      hcryp->CrypHeaderCount++ ;
    }
    /* If the header size is a multiple of words */
    if ((headersize_in_bytes % 4U) == 0U)
    {
      /* Pad the data with zeros to have a complete block */
      while (loopcounter < 4U)
      {
        hcryp->Instance->DATAINR = 0x0U;
        loopcounter++;
        hcryp->CrypHeaderCount++;
      }
    }
    else
    {
      /* Enter last bytes, padded with zeros */
      tmp =  *(uint32_t *)(hcryp->Init.Header + hcryp->CrypHeaderCount);
      tmp &= mask[(hcryp->Init.DataType * 2U) + (headersize_in_bytes % 4U)];
      hcryp->Instance->DATAINR = tmp;
      loopcounter++;
      hcryp->CrypHeaderCount++;
      /* Pad the data with zeros to have a complete block */
    while (loopcounter < 4U)
    {
      hcryp->Instance->DATAINR = 0x0U;
      loopcounter++;
        hcryp->CrypHeaderCount++;
      }
    }
  }
#endif /* End AES or CRYP */
}


/**
  * @brief  Workaround used for GCM/CCM mode.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module
  * @param  Timeout: specify Timeout value
  * @retval None
  */
static void CRYP_Workaround(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint32_t lastwordsize;
  uint32_t npblb;
#if defined(CRYP)
  uint32_t  iv1temp;
  uint32_t  temp[4] = {0};
  uint32_t  temp2[4] = {0};
#endif /* CRYP */
  uint32_t intermediate_data[4] = {0};
  uint32_t index;

  /* Compute the number of padding bytes in last block of payload */
  npblb = ((((uint32_t)(hcryp->Size) / 16U) + 1U) * 16U) - (uint32_t)(hcryp->Size);

  /* Number of valid words (lastwordsize) in last block */
  if ((npblb % 4U) == 0U)
  {
    lastwordsize = (16U - npblb) / 4U;
  }
  else
  {
    lastwordsize = ((16U - npblb) / 4U) + 1U;
  }

#if defined(CRYP)

  /* Workaround 2, case GCM encryption */
  if (hcryp->Init.Algorithm == CRYP_AES_GCM)
  {
    if ((hcryp->Instance->CTRL & CRYP_CTRL_ALGODIRSEL) == CRYP_OPERATINGMODE_ENCRYPT)
    {
      /*Workaround in order to properly compute authentication tags while doing
       a GCM encryption with the last block of payload size inferior to 128 bits*/
      /* Disable CRYP to start the final phase */
      __DAL_CRYP_DISABLE(hcryp);

      /*Update CRYP_IV1R register and ALGOMODE*/
      hcryp->Instance->IV1R = ((hcryp->Instance->CSGCMCCM7R) - 1U);
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGOMSEL, CRYP_AES_CTR);

      /* Enable CRYP to start the final phase */
      __DAL_CRYP_ENABLE(hcryp);
    }
    /*  Last block optionally pad the data with zeros*/
    for (index = 0; index < lastwordsize; index ++)
    {
      /* Write the last input block in the IN FIFO */
      hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
    }
    while (index < 4U)
    {
      /* Pad the data with zeros to have a complete block */
      hcryp->Instance->DATAIN  = 0U;
      index++;
    }
    /* Wait for OFNE flag to be raised */
    if (CRYP_WaitOnOFNEFlag(hcryp, Timeout) != DAL_OK)
    {
      /* Disable the CRYP peripheral clock */
      __DAL_CRYP_DISABLE(hcryp);

      /* Change state */
      hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process Unlocked */
      __DAL_UNLOCK(hcryp);
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
      /*Call registered error callback*/
      hcryp->ErrorCallback(hcryp);
#else
      /*Call legacy weak error callback*/
      DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
    }
    if ((hcryp->Instance->STS & CRYP_FLAG_OFNE) != 0x0U)
    {
      for (index = 0U; index < 4U; index++)
      {
        /* Read the output block from the output FIFO */
        intermediate_data[index] = hcryp->Instance->DATAOUT;

        /* Intermediate data buffer to be used in for the workaround*/
        *(uint32_t *)(hcryp->pCrypOutBuffPtr + (hcryp->CrypOutCount)) = intermediate_data[index];
        hcryp->CrypOutCount++;
      }
    }

    if ((hcryp->Instance->CTRL & CRYP_CTRL_ALGODIRSEL) == CRYP_OPERATINGMODE_ENCRYPT)
    {
      /*workaround in order to properly compute authentication tags while doing
      a GCM encryption with the last block of payload size inferior to 128 bits*/
      /* Change the AES mode to GCM mode and Select Final phase */
      /* configured  CHMOD GCM   */
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGOMSEL, CRYP_AES_GCM);

      /* configured  final phase  */
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_GCM_CCMPH, CRYP_PHASE_FINAL);

      if ((hcryp->Instance->CTRL & CRYP_CTRL_DTSEL) == CRYP_DATATYPE_32B)
      {
        if ((npblb % 4U) == 1U)
        {
          intermediate_data[lastwordsize - 1U] &= 0xFFFFFF00U;
        }
        if ((npblb % 4U) == 2U)
        {
          intermediate_data[lastwordsize - 1U] &= 0xFFFF0000U;
        }
        if ((npblb % 4U) == 3U)
        {
          intermediate_data[lastwordsize - 1U] &= 0xFF000000U;
        }
      }
      else if ((hcryp->Instance->CTRL & CRYP_CTRL_DTSEL) == CRYP_DATATYPE_8B)
      {
        if ((npblb % 4U) == 1U)
        {
          intermediate_data[lastwordsize - 1U] &= __REV(0xFFFFFF00U);
        }
        if ((npblb % 4U) == 2U)
        {
          intermediate_data[lastwordsize - 1U] &= __REV(0xFFFF0000U);
        }
        if ((npblb % 4U) == 3U)
        {
          intermediate_data[lastwordsize - 1U] &= __REV(0xFF000000U);
        }
      }
      else if ((hcryp->Instance->CTRL & CRYP_CTRL_DTSEL) == CRYP_DATATYPE_16B)
      {
        if ((npblb % 4U) == 1U)
        {
          intermediate_data[lastwordsize - 1U] &= __ROR((0xFFFFFF00U), 16);
        }
        if ((npblb % 4U) == 2U)
        {
          intermediate_data[lastwordsize - 1U] &= __ROR((0xFFFF0000U), 16);
        }
        if ((npblb % 4U) == 3U)
        {
          intermediate_data[lastwordsize - 1U] &= __ROR((0xFF000000U), 16);
        }
      }
      else /*CRYP_DATATYPE_1B*/
      {
        if ((npblb % 4U) == 1U)
        {
          intermediate_data[lastwordsize - 1U] &= __RBIT(0xFFFFFF00U);
        }
        if ((npblb % 4U) == 2U)
        {
          intermediate_data[lastwordsize - 1U] &= __RBIT(0xFFFF0000U);
        }
        if ((npblb % 4U) == 3U)
        {
          intermediate_data[lastwordsize - 1U] &= __RBIT(0xFF000000U);
        }
      }
      for (index = 0U; index < lastwordsize; index ++)
      {
        /*Write the intermediate_data in the IN FIFO */
        hcryp->Instance->DATAIN = intermediate_data[index];
      }
      while (index < 4U)
      {
        /* Pad the data with zeros to have a complete block */
        hcryp->Instance->DATAIN  = 0x0U;
        index++;
      }
      /* Wait for OFNE flag to be raised */
      if (CRYP_WaitOnOFNEFlag(hcryp, Timeout) != DAL_OK)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process unlocked */
        __DAL_UNLOCK(hcryp);
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1)
        /*Call registered error callback*/
        hcryp->ErrorCallback(hcryp);
#else
        /*Call legacy weak error callback*/
        DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
      }

      if ((hcryp->Instance->STS & CRYP_FLAG_OFNE) != 0x0U)
      {
        for (index = 0U; index < 4U; index++)
        {
          intermediate_data[index] = hcryp->Instance->DATAOUT;
        }
      }
    }
  } /* End of GCM encryption */
  else
  {
    /* Workaround 2, case CCM decryption, in order to properly compute
      authentication tags while doing a CCM decryption with the last block
      of payload size inferior to 128 bits*/

    if ((hcryp->Instance->CTRL & CRYP_CTRL_ALGODIRSEL) == CRYP_OPERATINGMODE_DECRYPT)
    {
      iv1temp = hcryp->Instance->CSGCMCCM7R;

      /* Disable CRYP to start the final phase */
      __DAL_CRYP_DISABLE(hcryp);

      temp[0] =  hcryp->Instance->CSGCMCCM0R;
      temp[1] =  hcryp->Instance->CSGCMCCM1R;
      temp[2] =  hcryp->Instance->CSGCMCCM2R;
      temp[3] =  hcryp->Instance->CSGCMCCM3R;

      hcryp->Instance->IV1R = iv1temp;

      /* Configured  CHMOD CTR   */
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGOMSEL, CRYP_AES_CTR);

      /* Enable CRYP to start the final phase */
      __DAL_CRYP_ENABLE(hcryp);
    }
    /*  Last block optionally pad the data with zeros*/
    for (index = 0; index < lastwordsize; index ++)
    {
      /* Write the last Input block in the IN FIFO */
      hcryp->Instance->DATAIN  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
      hcryp->CrypInCount++;
    }
    while (index < 4U)
    {
      /* Pad the data with zeros to have a complete block */
      hcryp->Instance->DATAIN  = 0U;
      index++;
    }
    /* Wait for OFNE flag to be raised */
    if (CRYP_WaitOnOFNEFlag(hcryp, Timeout) != DAL_OK)
    {
      /* Disable the CRYP peripheral clock */
      __DAL_CRYP_DISABLE(hcryp);

      /* Change state */
      hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process Unlocked */
      __DAL_UNLOCK(hcryp);
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1U)
      /*Call registered error callback*/
      hcryp->ErrorCallback(hcryp);
#else
      /*Call legacy weak error callback*/
      DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
    }

    if ((hcryp->Instance->STS & CRYP_FLAG_OFNE) != 0x0U)
    {
      for (index = 0U; index < 4U; index++)
      {
        /* Read the Output block from the Output FIFO */
        intermediate_data[index] = hcryp->Instance->DATAOUT;

        /*intermediate data buffer to be used in for the workaround*/
        *(uint32_t *)(hcryp->pCrypOutBuffPtr + (hcryp->CrypOutCount)) = intermediate_data[index];
        hcryp->CrypOutCount++;
      }
    }

    if ((hcryp->Instance->CTRL & CRYP_CTRL_ALGODIRSEL) == CRYP_OPERATINGMODE_DECRYPT)
    {
      temp2[0] =  hcryp->Instance->CSGCMCCM0R;
      temp2[1] =  hcryp->Instance->CSGCMCCM1R;
      temp2[2] =  hcryp->Instance->CSGCMCCM2R;
      temp2[3] =  hcryp->Instance->CSGCMCCM3R;

      /* configured  CHMOD CCM   */
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_ALGOMSEL, CRYP_AES_CCM);

      /* configured  Header phase  */
      MODIFY_REG(hcryp->Instance->CTRL, CRYP_CTRL_GCM_CCMPH, CRYP_PHASE_HEADER);

      /*set to zero the bits corresponding to the padded bits*/
      for (index = lastwordsize; index < 4U; index ++)
      {
        intermediate_data[index] = 0U;
      }
      if ((npblb % 4U) == 1U)
      {
        intermediate_data[lastwordsize - 1U] &= 0xFFFFFF00U;
      }
      if ((npblb % 4U) == 2U)
      {
        intermediate_data[lastwordsize - 1U] &= 0xFFFF0000U;
      }
      if ((npblb % 4U) == 3U)
      {
        intermediate_data[lastwordsize - 1U] &= 0xFF000000U;
      }
      for (index = 0U; index < 4U ; index ++)
      {
        intermediate_data[index] ^=  temp[index];
        intermediate_data[index] ^=  temp2[index];
      }
      for (index = 0U; index < 4U; index ++)
      {
        /* Write the last Input block in the IN FIFO */
        hcryp->Instance->DATAIN  = intermediate_data[index] ;
      }

      /* Wait for BUSY flag to be raised */
      if (CRYP_WaitOnBUSYFlag(hcryp, Timeout) != DAL_OK)
      {
        /* Disable the CRYP peripheral clock */
        __DAL_CRYP_DISABLE(hcryp);

        /* Change state */
        hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
        hcryp->State = DAL_CRYP_STATE_READY;

        /* Process Unlocked */
        __DAL_UNLOCK(hcryp);
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1U)
        /*Call registered error callback*/
        hcryp->ErrorCallback(hcryp);
#else
        /*Call legacy weak error callback*/
        DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
      }
    }
  } /* End of CCM WKA*/

  /* Process Unlocked */
  __DAL_UNLOCK(hcryp);

#else /* AES */

  /*Workaround 2: case GCM encryption, during payload phase and before inserting
  the last block of paylaod, which size is inferior to  128 bits  */

  if ((hcryp->Instance->CTRL & AES_CR_MODE) == CRYP_OPERATINGMODE_ENCRYPT)
  {
    /* configured  CHMOD CTR   */
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_CHMOD, CRYP_AES_CTR);
  }
  /*  last block optionally pad the data with zeros*/
  for (index = 0U; index < lastwordsize; index ++)
  {
    /* Write the last Input block in the IN FIFO */
    hcryp->Instance->DATAINR  = *(uint32_t *)(hcryp->pCrypInBuffPtr + hcryp->CrypInCount);
    hcryp->CrypInCount++;
  }
  while (index < 4U)
  {
    /* pad the data with zeros to have a complete block */
    hcryp->Instance->DATAINR  = 0U;
    index++;
  }
  /* Wait for CCF flag to be raised */
  if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
  {
    hcryp->State = DAL_CRYP_STATE_READY;
    __DAL_UNLOCK(hcryp);
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1U)
    /*Call registered error callback*/
    hcryp->ErrorCallback(hcryp);
#else
    /*Call legacy weak error callback*/
    DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
  }

  /* Clear CCF Flag */
  __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

  for (index = 0U; index < 4U; index++)
  {
    /* Read the Output block from the Output FIFO */
    intermediate_data[index] = hcryp->Instance->DATAOUTR;

    /*intermediate data buffer to be used in  the workaround*/
    *(uint32_t *)(hcryp->pCrypOutBuffPtr + (hcryp->CrypOutCount)) = intermediate_data[index];
    hcryp->CrypOutCount++;
  }

  if ((hcryp->Instance->CTRL & AES_CR_MODE) == CRYP_OPERATINGMODE_ENCRYPT)
  {
    /* configured  CHMOD GCM   */
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_CHMOD, CRYP_AES_GCM_GMAC);

    /* Select final phase */
    MODIFY_REG(hcryp->Instance->CTRL, AES_CR_GCMPH, CRYP_PHASE_FINAL);

    if ((hcryp->Instance->CTRL & AES_CR_DATATYPE) == CRYP_DATATYPE_32B)
    {
      if ((npblb % 4U) == 1U)
      {
        intermediate_data[lastwordsize - 1U] &= 0xFFFFFF00U;
      }
      if ((npblb % 4U) == 2U)
      {
        intermediate_data[lastwordsize - 1U] &= 0xFFFF0000U;
      }
      if ((npblb % 4U) == 3U)
      {
        intermediate_data[lastwordsize - 1U] &= 0xFF000000U;
      }
    }
    else if ((hcryp->Instance->CTRL & AES_CR_DATATYPE) == CRYP_DATATYPE_8B)
    {
      if ((npblb % 4U) == 1U)
      {
        intermediate_data[lastwordsize - 1U] &= __REV(0xFFFFFF00U);
      }
      if ((npblb % 4U) == 2U)
      {
        intermediate_data[lastwordsize - 1U] &= __REV(0xFFFF0000U);
      }
      if ((npblb % 4U) == 3U)
      {
        intermediate_data[lastwordsize - 1U] &= __REV(0xFF000000U);
      }
    }
    else if ((hcryp->Instance->CTRL & AES_CR_DATATYPE) == CRYP_DATATYPE_16B)
    {
      if ((npblb % 4U) == 1U)
      {
        intermediate_data[lastwordsize - 1U] &= __ROR((0xFFFFFF00U), 16);
      }
      if ((npblb % 4U) == 2U)
      {
        intermediate_data[lastwordsize - 1U] &= __ROR((0xFFFF0000U), 16);
      }
      if ((npblb % 4U) == 3U)
      {
        intermediate_data[lastwordsize - 1U] &= __ROR((0xFF000000U), 16);
      }
    }
    else /*CRYP_DATATYPE_1B*/
    {
      if ((npblb % 4U) == 1U)
      {
        intermediate_data[lastwordsize - 1U] &= __RBIT(0xFFFFFF00U);
      }
      if ((npblb % 4U) == 2U)
      {
        intermediate_data[lastwordsize - 1U] &= __RBIT(0xFFFF0000U);
      }
      if ((npblb % 4U) == 3U)
      {
        intermediate_data[lastwordsize - 1U] &= __RBIT(0xFF000000U);
      }
    }

    /*Write the intermediate_data in the IN FIFO */
    for (index = 0U; index < lastwordsize; index ++)
    {
      hcryp->Instance->DATAINR  = intermediate_data[index];
    }
    while (index < 4U)
    {
      /* pad the data with zeros to have a complete block */
      hcryp->Instance->DATAINR = 0U;
      index++;
    }
    /* Wait for CCF flag to be raised */
    if (CRYP_WaitOnCCFlag(hcryp, Timeout) != DAL_OK)
    {
      /* Disable the CRYP peripheral clock */
      __DAL_CRYP_DISABLE(hcryp);

      /* Change state */
      hcryp->ErrorCode |= DAL_CRYP_ERROR_TIMEOUT;
      hcryp->State = DAL_CRYP_STATE_READY;

      /* Process Unlocked */
      __DAL_UNLOCK(hcryp);
#if (USE_DAL_CRYP_REGISTER_CALLBACKS == 1U)
      /*Call registered error callback*/
      hcryp->ErrorCallback(hcryp);
#else
      /*Call legacy weak error callback*/
      DAL_CRYP_ErrorCallback(hcryp);
#endif /* USE_DAL_CRYP_REGISTER_CALLBACKS */
    }
    /* Clear CCF Flag */
    __DAL_CRYP_CLEAR_FLAG(hcryp, CRYP_CCF_CLEAR);

    for (index = 0U; index < 4U; index++)
    {
      intermediate_data[index] = hcryp->Instance->DATAOUTR;
    }
  }/*End of Workaround 2*/
#endif /* End AES or CRYP */
}
#endif /* AES or GCM CCM defined*/
#if defined (CRYP)
#if defined (CRYP_CTRL_ALGOMSEL_AES_GCM)
/**
  * @brief  Handle CRYP hardware block Timeout when waiting for IFEM flag to be raised.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module.
  * @param  Timeout: Timeout duration.
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_WaitOnIFEMFlag(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint32_t tickstart;

  /* Get timeout */
  tickstart = DAL_GetTick();

  while (DAL_IS_BIT_CLR(hcryp->Instance->STS, CRYP_FLAG_IFEM))
  {
    /* Check for the Timeout */
    if (Timeout != DAL_MAX_DELAY)
    {
      if (((DAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
      {
        return DAL_ERROR;
      }
    }
  }
  return DAL_OK;
}
#endif /* GCM CCM defined*/
/**
  * @brief  Handle CRYP hardware block Timeout when waiting for BUSY flag to be raised.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module.
  * @param  Timeout: Timeout duration.
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_WaitOnBUSYFlag(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint32_t tickstart;

  /* Get timeout */
  tickstart = DAL_GetTick();

  while (DAL_IS_BIT_SET(hcryp->Instance->STS, CRYP_FLAG_BUSY))
  {
    /* Check for the Timeout */
    if (Timeout != DAL_MAX_DELAY)
    {
      if (((DAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
      {
        return DAL_ERROR;
      }
    }
  }
  return DAL_OK;
}


/**
  * @brief  Handle CRYP hardware block Timeout when waiting for OFNE flag to be raised.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module.
  * @param  Timeout: Timeout duration.
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_WaitOnOFNEFlag(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint32_t tickstart;

  /* Get timeout */
  tickstart = DAL_GetTick();

  while (DAL_IS_BIT_CLR(hcryp->Instance->STS, CRYP_FLAG_OFNE))
  {
    /* Check for the Timeout */
    if (Timeout != DAL_MAX_DELAY)
    {
      if (((DAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
      {
        return DAL_ERROR;
      }
    }
  }
  return DAL_OK;
}

#else /* AES */

/**
  * @brief  Handle CRYP hardware block Timeout when waiting for CCF flag to be raised.
  * @param  hcryp: pointer to a CRYP_HandleTypeDef structure that contains
  *         the configuration information for CRYP module.
  * @param  Timeout: Timeout duration.
  * @retval DAL status
  */
static DAL_StatusTypeDef CRYP_WaitOnCCFlag(CRYP_HandleTypeDef *hcryp, uint32_t Timeout)
{
  uint32_t tickstart;

  /* Get timeout */
  tickstart = DAL_GetTick();

  while (DAL_IS_BIT_CLR(hcryp->Instance->STS, AES_SR_CCF))
  {
    /* Check for the Timeout */
    if (Timeout != DAL_MAX_DELAY)
    {
      if (((DAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
      {
        return DAL_ERROR;
      }
    }
  }
  return DAL_OK;
}

#endif /* End AES or CRYP  */


/**
  * @}
  */



/**
  * @}
  */

/**
  * @}
  */

#endif /* DAL_CRYP_MODULE_ENABLED */


/**
  * @}
  */
#endif /* TinyAES or CRYP*/
/**
  * @}
  */

