text: /***************************************************************************//**
  * \file cy_crypto_core_aes_v1.c
  * \version 2.40
  *
  * \brief
  *  This file provides the source code fro the API for the AES method
  *  in the Crypto driver.
  *
  ********************************************************************************
  * Copyright 2016-2020 Cypress Semiconductor Corporation
  * SPDX-License-Identifier: Apache-2.0
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *    http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *******************************************************************************/
  
  #include "cy_device.h"
  
  #if defined (CY_IP_MXCRYPTO)
  
  #include "cy_crypto_core_aes_v1.h"
  
  #if defined(__cplusplus)
  extern "C" {
  #endif
  
  #if (CPUSS_CRYPTO_AES == 1)
  
  #include "cy_crypto_core_hw_v1.h"
  #include "cy_crypto_core_mem_v1.h"
  #include "cy_syslib.h"
  
  static void Cy_Crypto_Core_V1_Aes_InvKey(CRYPTO_Type *base, cy_stc_crypto_aes_state_t const *aesState);
  
  /*******************************************************************************
  * Function Name: Cy_Crypto_Core_V1_Aes_ProcessBlock
  ****************************************************************************//**
  *
  * Performs the AES block cipher.
  *
  * \param base
  * The pointer to the CRYPTO instance.
  *
  * \param aesState
  * The pointer to the AES state structure allocated by the user. The user
  * must not modify anything in this structure.
  *
  * \param dirMode
  * One of CRYPTO_ENCRYPT or CRYPTO_DECRYPT.
  *
  * \param dstBlock
  * The pointer to the cipher text.
  *
  * \param srcBlock
  * The pointer to the plain text. Must be 4-Byte aligned!
  *
  *******************************************************************************/
  void Cy_Crypto_Core_V1_Aes_ProcessBlock(CRYPTO_Type *base,
                              cy_stc_crypto_aes_state_t const *aesState,
                              cy_en_crypto_dir_mode_t dirMode,
                              uint32_t *dstBlock,
                              uint32_t const *srcBlock)
  {
      /* Set the key mode: 128, 192 or 256 Bit */
      REG_CRYPTO_AES_CTL(base) = (uint32_t)(_VAL2FLD(CRYPTO_AES_CTL_KEY_SIZE, (uint32_t)(aesState->keyLength)));
  
      Cy_Crypto_SetReg3Instr(base,
                             (CY_CRYPTO_DECRYPT == dirMode) ? (uint32_t)aesState->buffers->keyInv : (uint32_t)aesState->buffers->key,
                             (uint32_t)srcBlock,
                             (uint32_t)dstBlock);
  
      Cy_Crypto_Run3ParamInstr(base,
                              (CY_CRYPTO_DECRYPT == dirMode) ? CY_CRYPTO_V1_AES_BLOCK_INV_OPC : CY_CRYPTO_V1_AES_BLOCK_OPC,
                              CY_CRYPTO_RSRC0_SHIFT,
                              CY_CRYPTO_RSRC4_SHIFT,
                              CY_CRYPTO_RSRC12_SHIFT);
  
      /* Wait until the AES instruction is complete */
      while (0uL != _FLD2VAL(CRYPTO_STATUS_AES_BUSY, REG_CRYPTO_STATUS(base)))
      {
      }
  }
  
  /*******************************************************************************
  * Function Name: Cy_Crypto_Core_V1_Aes_Xor
  ****************************************************************************//**
  *
  * Perform the XOR of two 16-Byte memory structures.
  * All addresses must be 4-Byte aligned!
  *
  * \param base
  * The pointer to the CRYPTO instance.
  *
  * \param aesState
  * The pointer to the AES state structure allocated by the user. The user
  * must not modify anything in this structure.
  *
  * \param dstBlock
  * The pointer to the memory structure with the XOR results.
  *
  * \param src0Block
  * The pointer to the first memory structure. Must be 4-Byte aligned!
  *
  * \param src1Block
  * The pointer to the second memory structure. Must be 4-Byte aligned!
  *
  *******************************************************************************/
  void Cy_Crypto_Core_V1_Aes_Xor(CRYPTO_Type *base,
                              cy_stc_crypto_aes_state_t const *aesState,
                              uint32_t *dstBlock,
                              uint32_t const *src0Block,
                              uint32_t const *src1Block)
  {
      /* Set the key mode: 128, 192 or 256 Bit */
      REG_CRYPTO_AES_CTL(base) = (uint32_t)(_VAL2FLD(CRYPTO_AES_CTL_KEY_SIZE, (uint32_t)(aesState->keyLength)));
  
      Cy_Crypto_SetReg3Instr(base,
                             (uint32_t)src0Block,
                             (uint32_t)src1Block,
                             (uint32_t)dstBlock);
  
      /* Issue the AES_XOR instruction */
      Cy_Crypto_Run3ParamInstr(base,
                               CY_CRYPTO_V1_AES_XOR_OPC,
                               CY_CRYPTO_RSRC0_SHIFT,
                               CY_CRYPTO_RSRC4_SHIFT,
                               CY_CRYPTO_RSRC8_SHIFT);
  
      /* Wait until the AES instruction is complete */
      while(0uL != _FLD2VAL(CRYPTO_STATUS_AES_BUSY, REG_CRYPTO_STATUS(base)))
      {
      }
  }
  
  /*******************************************************************************
  * Function Name: Cy_Crypto_Core_V1_Aes_InvKey
  ****************************************************************************//**
  *
  * Calculates an inverse block cipher key from the block cipher key.
  *
  * \param base
  * The pointer to the CRYPTO instance.
  *
  * \param aesState
  * The pointer to the AES state structure allocated by the user. The user
  * must not modify anything in this structure.
  *
  *******************************************************************************/
  static void Cy_Crypto_Core_V1_Aes_InvKey(CRYPTO_Type *base, cy_stc_crypto_aes_state_t const *aesState)
  {
      /* Set the key mode: 128, 192 or 256 Bit */
      REG_CRYPTO_AES_CTL(base) = (uint32_t)(_VAL2FLD(CRYPTO_AES_CTL_KEY_SIZE, (uint32_t)(aesState->keyLength)));
  
      /* Issue the AES_KEY instruction to prepare the key for decrypt operation */
      Cy_Crypto_SetReg2Instr(base, (uint32_t)aesState->buffers->key, (uint32_t)aesState->buffers->keyInv);
  
      Cy_Crypto_Run2ParamInstr(base,
                               CY_CRYPTO_V1_AES_KEY_OPC,
                               CY_CRYPTO_RSRC0_SHIFT,
                               CY_CRYPTO_RSRC8_SHIFT);
  
      /* Wait until the AES instruction is complete */
      while(0uL != _FLD2VAL(CRYPTO_STATUS_AES_BUSY, REG_CRYPTO_STATUS(base)))
      {
      }
  }
  
  /*******************************************************************************
  * Function Name: Cy_Crypto_Core_V1_Aes_Init
  ****************************************************************************//**
  *
  * Sets AES mode and prepares an inverse key.
  *
  * \param base
  * The pointer to the CRYPTO instance.
  *
  * \param key
  * The pointer to the encryption/decryption key.
  *
  * \param keyLength
  * \ref cy_en_crypto_aes_key_length_t
  *
  * \param aesState
  * The pointer to the AES state structure allocated by the user. The user
  * must not modify anything in this structure.
  *
  * \param aesBuffers
  * The pointer to the memory buffers storage.
  *
  * \return
  * \ref cy_en_crypto_status_t
  *
  *******************************************************************************/
  cy_en_crypto_status_t Cy_Crypto_Core_V1_Aes_Init(CRYPTO_Type *base,
                                                   uint8_t const *key,
                                                   cy_en_crypto_aes_key_length_t keyLength,
                                                   cy_stc_crypto_aes_state_t *aesState,
                                                   cy_stc_crypto_aes_buffers_t *aesBuffers)
  {
      uint16_t keySize = CY_CRYPTO_AES_128_KEY_SIZE + ((uint16_t)keyLength * 8u);
  
      aesState->keyLength = keyLength;
      aesState->buffers = aesBuffers;
  
      Cy_Crypto_Core_V1_MemCpy(base, (uint8_t *)(aesState->buffers->key), key, keySize);
  
      Cy_Crypto_Core_V1_Aes_InvKey(base, aesState);
  
      return (CY_CRYPTO_SUCCESS);
  }
  
  /*******************************************************************************
  * Function Name: Cy_Crypto_Core_V1_Aes_Free
  ****************************************************************************//**
  *
  * Clears AES operation context.
  *
  * \param base
  * The pointer to the CRYPTO instance.
  *
  * \param aesState
  * The pointer to the AES state structure allocated by the user. The user
  * must not modify anything in this structure.
  *
  * \return
  * \ref cy_en_crypto_status_t
  *
  *******************************************************************************/
  cy_en_crypto_status_t Cy_Crypto_Core_V1_Aes_Free(CRYPTO_Type *base, cy_stc_crypto_aes_state_t *aesState)
  {
      Cy_Crypto_Core_V1_MemSet(base, (void *)aesState->buffers, 0u, sizeof(cy_stc_crypto_aes_buffers_t));
      Cy_Crypto_Core_V1_MemSet(base, (void *)aesState, 0u, sizeof(cy_stc_crypto_aes_state_t));
  
      return (CY_CRYPTO_SUCCESS);
  }
  
  /*******************************************************************************
  * Function Name: Cy_Crypto_Core_V1_Aes_Ecb
  ****************************************************************************//**
  *
  * Performs an AES operation on one block.
  *
  * \param base
  * The pointer to the CRYPTO instance.
  *
  * \param dirMode
  * Can be \ref CY_CRYPTO_ENCRYPT or \ref CY_CRYPTO_DECRYPT
  * (\ref cy_en_crypto_dir_mode_t).
  *
  * \param dst
  * The pointer to a destination cipher block.
  *
  * \param src
  * The pointer to a source block.
  *
  * \param aesState
  * The pointer to the AES state structure allocated by the user. The user
  * must not modify anything in this structure.
  *
  * \return
  * \ref cy_en_crypto_status_t
  *
  *******************************************************************************/
  cy_en_crypto_status_t Cy_Crypto_Core_V1_Aes_Ecb(CRYPTO_Type *base,
                                              cy_en_crypto_dir_mode_t dirMode,
                                              uint8_t *dst,
                                              uint8_t const *src,
                                              cy_stc_crypto_aes_state_t *aesState)
  {
      cy_stc_crypto_aes_buffers_t *aesBuffers = (cy_stc_crypto_aes_buffers_t*)aesState->buffers;
  
      Cy_Crypto_Core_V1_MemCpy(base, &aesBuffers->block0, src, CY_CRYPTO_AES_BLOCK_SIZE);
  
      Cy_Crypto_Core_V1_Aes_ProcessBlock(base, aesState, dirMode, (uint32_t*)&aesBuffers->block1, (uint32_t*)&aesBuffers->block0);
  
      Cy_Crypto_Core_V1_MemCpy(base, dst, &aesBuffers->block1, CY_CRYPTO_AES_BLOCK_SIZE);
  
      return (CY_CRYPTO_SUCCESS);
  }
  
  /*******************************************************************************
  * Function Name: Cy_Crypto_Core_V1_Aes_Cbc
  ****************************************************************************//**
  *
  * Performs AES operation on a plain text with Cipher Block Chaining (CBC).
  *
  * \param base
  * The pointer to the CRYPTO instance.
  *
  * \param dirMode
  * Can be \ref CY_CRYPTO_ENCRYPT or \ref CY_CRYPTO_DECRYPT
  * (\ref cy_en_crypto_dir_mode_t)
  *
  * \param srcSize
  * The size of the source plain text.
  *
  * \param ivPtr
  * The pointer to the initial vector.
  *
  * \param dst
  * The pointer to a destination cipher text.
  *
  * \param src
  * The pointer to a source plain text.
  *
  * \param aesState
  * The pointer to the AES state structure allocated by the user. The user
  * must not modify anything in this structure.
  *
  * \return
  * \ref cy_en_crypto_status_t
  *
  *******************************************************************************/
  cy_en_crypto_status_t Cy_Crypto_Core_V1_Aes_Cbc(CRYPTO_Type *base,
                                              cy_en_crypto_dir_mode_t dirMode,
                                              uint32_t srcSize,
                                              uint8_t *ivPtr,
                                              uint8_t *dst,
                                              uint8_t const *src,
                                              cy_stc_crypto_aes_state_t *aesState)
  {
      uint32_t size = srcSize;
  
      cy_stc_crypto_aes_buffers_t *aesBuffers = (cy_stc_crypto_aes_buffers_t*)aesState->buffers;
      uint32_t *srcBuff  = (uint32_t*)(&aesBuffers->block0);
      uint32_t *dstBuff  = (uint32_t*)(&aesBuffers->block1);
      uint32_t *tempBuff = (uint32_t*)(&aesBuffers->block2);
  
      cy_en_crypto_status_t tmpResult = CY_CRYPTO_SIZE_NOT_X16;
  
      /* Check whether the data size is multiple of CY_CRYPTO_AES_BLOCK_SIZE */
      if (0UL == (uint32_t)(size & (CY_CRYPTO_AES_BLOCK_SIZE - 1U)))
      {
          /* Copy the Initialization Vector to the local buffer because it changes during calculation */
          Cy_Crypto_Core_V1_MemCpy(base, tempBuff, ivPtr, CY_CRYPTO_AES_BLOCK_SIZE);
  
          if (CY_CRYPTO_DECRYPT == dirMode)
          {
              while (size != 0UL)
              {
                  /* source message block */
                  Cy_Crypto_Core_V1_MemCpy(base, srcBuff, src, CY_CRYPTO_AES_BLOCK_SIZE);
  
                  Cy_Crypto_Core_V1_Aes_ProcessBlock(base, aesState, dirMode, dstBuff, srcBuff);
                  Cy_Crypto_Core_V1_Aes_Xor(base, aesState, dstBuff, tempBuff, dstBuff);
  
                  /* temporary cipher block */
                  Cy_Crypto_Core_V1_MemCpy(base, tempBuff, srcBuff, CY_CRYPTO_AES_BLOCK_SIZE);
  
                  /* destination cipher text block */
                  Cy_Crypto_Core_V1_MemCpy(base, dst, dstBuff, CY_CRYPTO_AES_BLOCK_SIZE);
  
                  src  += CY_CRYPTO_AES_BLOCK_SIZE;
                  dst  += CY_CRYPTO_AES_BLOCK_SIZE;
                  size -= CY_CRYPTO_AES_BLOCK_SIZE;
              }
          }
          else
          {
              while (size != 0UL)
              {
                  /* source message block */
                  Cy_Crypto_Core_V1_MemCpy(base, srcBuff, src, CY_CRYPTO_AES_BLOCK_SIZE);
  
                  Cy_Crypto_Core_V1_Aes_Xor(base, aesState, tempBuff, srcBuff, tempBuff);
                  Cy_Crypto_Core_V1_Aes_ProcessBlock(base, aesState, dirMode, dstBuff, tempBuff);
  
                  /* temporary cipher block */
                  Cy_Crypto_Core_V1_MemCpy(base, tempBuff, dstBuff, CY_CRYPTO_AES_BLOCK_SIZE);
  
                  /* destination cipher text block */
                  Cy_Crypto_Core_V1_MemCpy(base, dst, dstBuff, CY_CRYPTO_AES_BLOCK_SIZE);
  
                  src  += CY_CRYPTO_AES_BLOCK_SIZE;
                  dst  += CY_CRYPTO_AES_BLOCK_SIZE;
                  size -= CY_CRYPTO_AES_BLOCK_SIZE;
              }
          }
  
          /* Copy the cipher block to the Initialization Vector */
          Cy_Crypto_Core_V1_MemCpy(base, ivPtr, tempBuff, CY_CRYPTO_AES_BLOCK_SIZE);
  
          tmpResult = CY_CRYPTO_SUCCESS;
      }
  
      return (tmpResult);
  }
  
  /*******************************************************************************
  * Function Name: Cy_Crypto_Core_V1_Aes_Cfb
  ********************************************************************************
  *
  * Performs AES operation on a plain text with the Cipher Feedback Block method (CFB).
  *
  * \param base
  * The pointer to the CRYPTO instance.
  *
  * \param dirMode
  * Can be \ref CY_CRYPTO_ENCRYPT or \ref CY_CRYPTO_DECRYPT
  * (\ref cy_en_crypto_dir_mode_t)
  *
  * \param srcSize
  * The size of the source plain text.
  *
  * \param ivPtr
  * The pointer to the initial vector.
  *
  * \param dst
  * The pointer to a destination cipher text.
  *
  * \param src
  * The pointer to a source plain text.
  *
  * \param aesState
  * The pointer to the AES state structure allocated by the user. The user must
  * must not modify anything in this structure.
  *
  * \return
  * \ref cy_en_crypto_status_t
  *
  *******************************************************************************/
  cy_en_crypto_status_t Cy_Crypto_Core_V1_Aes_Cfb(CRYPTO_Type *base,
                                               cy_en_crypto_dir_mode_t dirMode,
                                               uint32_t srcSize,
                                               uint8_t *ivPtr,
                                               uint8_t *dst,
                                               uint8_t const *src,
                                               cy_stc_crypto_aes_state_t *aesState)
  {
      uint32_t size = srcSize;
      cy_en_crypto_status_t tmpResult = CY_CRYPTO_SIZE_NOT_X16;
  
      cy_stc_crypto_aes_buffers_t *aesBuffers = (cy_stc_crypto_aes_buffers_t*)aesState->buffers;
  
      uint32_t *srcBuff = (uint32_t*)(aesBuffers->block0);
      uint32_t *dstBuff = (uint32_t*)(aesBuffers->block1);
  
      uint32_t *encBuff = dstBuff;   /* Default operation is ENCRYPT */
  
      /* Check whether the data size is multiple of CY_CRYPTO_AES_BLOCK_SIZE */
      if (0UL == (size & (CY_CRYPTO_AES_BLOCK_SIZE - 1U)))
      {
          if (CY_CRYPTO_DECRYPT == dirMode)
          {
              encBuff = srcBuff;
          }
  
          /* Copies the Initialization Vector to the local encode buffer. */
          Cy_Crypto_Core_V1_MemCpy(base, encBuff, ivPtr, CY_CRYPTO_AES_BLOCK_SIZE);
  
          while (size != 0UL)
          {
              /* In this mode, (CFB) is always an encryption! */
              Cy_Crypto_Core_V1_Aes_ProcessBlock(base, aesState, CY_CRYPTO_ENCRYPT, dstBuff, encBuff);
  
              /* source message block */
              Cy_Crypto_Core_V1_MemCpy(base, srcBuff, src, CY_CRYPTO_AES_BLOCK_SIZE);
  
              Cy_Crypto_Core_V1_Aes_Xor(base, aesState, dstBuff, srcBuff, dstBuff);
  
              /* destination cipher text block */
              Cy_Crypto_Core_V1_MemCpy(base, dst, dstBuff, CY_CRYPTO_AES_BLOCK_SIZE);
  
              src  += CY_CRYPTO_AES_BLOCK_SIZE;
              dst  += CY_CRYPTO_AES_BLOCK_SIZE;
  
              size -= CY_CRYPTO_AES_BLOCK_SIZE;
          }
  
          /* Copies the local encode buffer to the Initialization Vector. */
          Cy_Crypto_Core_V1_MemCpy(base, ivPtr, encBuff, CY_CRYPTO_AES_BLOCK_SIZE);
  
          tmpResult = CY_CRYPTO_SUCCESS;
      }
  
      return (tmpResult);
  }
  
  /*******************************************************************************
  * Function Name: Cy_Crypto_Core_V1_Aes_Ctr
  ********************************************************************************
  *
  * Performs an AES operation on a plain text using the counter method (CTR).
  *
  * \param base
  * The pointer to the CRYPTO instance.
  *
  * \param srcSize
  * The size of a source plain text.
  *
  * \param srcOffset
  * The size of an offset within the current block stream for resuming within the
  * current cipher stream.
  *
  * \param ivPtr
  * The 128-bit initial vector that contains a 64-bit nonce and 64-bit counter.
  *
  * \param streamBlock
  * The saved stream-block for resuming. Is over-written by the function.
  *
  * \param dst
  * The pointer to a destination cipher text.
  *
  * \param src
  * The pointer to a source plain text. Must be 4-Byte aligned.
  *
  * \param aesState
  * The pointer to the AES state structure allocated by the user. The user must
  * must not modify anything in this structure.
  *
  * \return
  * \ref cy_en_crypto_status_t
  *
  *******************************************************************************/
  #define CY_CRYPTO_AES_CTR_CNT_POS          (0x02U)
  cy_en_crypto_status_t Cy_Crypto_Core_V1_Aes_Ctr(CRYPTO_Type *base,
                                              uint32_t srcSize,
                                              uint32_t *srcOffset,
                                              uint8_t  *ivPtr,
                                              uint8_t  *streamBlock,
                                              uint8_t  *dst,
                                              uint8_t  const *src,
                                              cy_stc_crypto_aes_state_t *aesState)
  {
      uint32_t i;
      uint32_t cnt;
      uint64_t counter;
      uint32_t blockCounter[CY_CRYPTO_AES_BLOCK_SIZE_U32] = { 0UL };
  
      cy_stc_crypto_aes_buffers_t *aesBuffers = (cy_stc_crypto_aes_buffers_t*)aesState->buffers;
      uint32_t *srcBuff      = (uint32_t*)(&aesBuffers->block0);
      uint32_t *dstBuff      = (uint32_t*)(&aesBuffers->block1);
      uint32_t *streamBuff   = (uint32_t*)(&aesBuffers->block2);
  
      (void)streamBlock; /* Suppress warning */
  
      Cy_Crypto_Core_V1_MemCpy(base, blockCounter, ivPtr, CY_CRYPTO_AES_BLOCK_SIZE);
  
      CY_MISRA_DEVIATE_LINE('MISRA C-2012 Rule 11.3','Intentional pointer type conversion');
      counter = CY_SWAP_ENDIAN64(*(uint64_t*)(blockCounter + CY_CRYPTO_AES_CTR_CNT_POS));
  
      cnt = (uint32_t)(srcSize / CY_CRYPTO_AES_BLOCK_SIZE);
  
      for (i = 0UL; i < cnt; i++)
      {
          /* source message block */
          Cy_Crypto_Core_V1_MemCpy(base, srcBuff, src, CY_CRYPTO_AES_BLOCK_SIZE);
  
          /* In this mode, (CTR) is always an encryption! */
          Cy_Crypto_Core_V1_Aes_ProcessBlock(base, aesState, CY_CRYPTO_ENCRYPT, streamBuff, blockCounter);
  
          /* Increment the block counter, at least 64Bits (from 128) is the counter part */
          counter++;
          CY_MISRA_DEVIATE_LINE('MISRA C-2012 Rule 11.3','Intentional pointer type conversion');
          *(uint64_t*)(blockCounter + CY_CRYPTO_AES_CTR_CNT_POS) = CY_SWAP_ENDIAN64(counter);
  
          Cy_Crypto_Core_V1_Aes_Xor(base, aesState, dstBuff, srcBuff, streamBuff);
  
          /* destination cipher text block */
          Cy_Crypto_Core_V1_MemCpy(base, dst, dstBuff, CY_CRYPTO_AES_BLOCK_SIZE);
  
          src += CY_CRYPTO_AES_BLOCK_SIZE;
          dst += CY_CRYPTO_AES_BLOCK_SIZE;
      }
  
      Cy_Crypto_Core_V1_MemCpy(base, ivPtr, blockCounter, CY_CRYPTO_AES_BLOCK_SIZE);
  
      /* Save the reminder of the last non-complete block */
      *srcOffset = (uint32_t)(srcSize % CY_CRYPTO_AES_BLOCK_SIZE);
  
      return (CY_CRYPTO_SUCCESS);
  }
  
  #endif /* #if (CPUSS_CRYPTO_AES == 1) */
  
  #if defined(__cplusplus)
  }
  #endif
  
  #endif /* CY_IP_MXCRYPTO */
  
  
  /* [] END OF FILE */
  