/**
  ******************************************************************************
  * @file    se_user_application.c
  * @author  MCD Application Team
  * @brief   Secure Engine USER APPLICATION module.
  *          This file is a placeholder for the code dedicated to the user application.
  *          These services are used by the application.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright(c) 2017 STMicroelectronics International N.V.
  * All rights reserved.</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted, provided that the following conditions are met:
  *
  * 1. Redistribution 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 STMicroelectronics nor the names of other
  *    contributors to this software may be used to endorse or promote products
  *    derived from this software without specific written permission.
  * 4. This software, including modifications and/or derivative works of this
  *    software, must execute solely and exclusively on microcontroller or
  *    microprocessor devices manufactured by or for STMicroelectronics.
  * 5. Redistribution and use of this software other than as permitted under
  *    this license is void and will automatically terminate your rights under
  *    this license.
  *
  * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
  * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
  * SHALL STMICROELECTRONICS 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.
  *
  ******************************************************************************
  */

/*+ Step 2 */
#define STEP2
/*- Step 2 */

/* Includes ------------------------------------------------------------------*/
#include "se_user_application.h"
#include "se_low_level.h"
#include "string.h"
/*+ Using the AES GCM encrypt/decrypt services */
#include "se_crypto_common.h"     /* re-use common crypto code (wrapper to cryptolib in this example)  */
/*- */

/** @addtogroup SE Secure Engine
  * @{
  */

/** @addtogroup SE_CORE SE Core
  * @{
  */

/** @defgroup  SE_APPLI SE Code for Application
  * @brief This file is a placeholder for the code dedicated to the user application.
  * It contains the code written by the end user.
  * The code used by the application to handle the Firmware images is located in se_fwimg.c.
  * @{
  */

/** @defgroup SE_APPLI_Private_Variables Private Variables
  * @brief Use this section to declare User Application data to be protected.
  * @note For instance a user application key stored in protected FLASH could be stored here like this:
  */
#if defined(__ICCARM__)
	#pragma default_variable_attributes  = @ ".SE_Key_Const"
#else
	__attribute__((section(".SE_Key_Const")))
#endif
/*+ Define your user key here (128 bit) */
static const  uint8_t m_aSE_UserAppKey[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
/*- Define your user key here */
#if defined(__ICCARM__)
#pragma default_variable_attributes  =
#endif
/* @{
  */

/**
  * @}
  */

/** @defgroup SE_APPLI_Exported_Functions Exported Functions
  * @{
  */

/**
  * @brief Service called by the User Application to retrieve the Active Firmware Info.
  * @param p_FwInfo Active Firmware Info structure that will be filled.
  * @retval SE_ErrorStatus SE_SUCCESS if successful, SE_ERROR otherwise.
  */
SE_ErrorStatus SE_APPLI_GetActiveFwInfo(SE_APP_ActiveFwInfo *p_FwInfo)
{
  SE_ErrorStatus e_ret_status;
  uint8_t buffer[SE_FW_HEADER_TOT_LEN];  /* to read FW metadata from FLASH */
  SE_FwRawHeaderTypeDef fw_image_header; /* FW metadata */

  /* Check the pointer allocation */
  if (NULL == p_FwInfo)
  {
    return SE_ERROR;
  }

  /*
   * The Firmware Information is available in the header of the slot #0.
   */
  e_ret_status = SE_LL_FLASH_Read(buffer, SFU_IMG_SLOT_0_REGION_BEGIN, sizeof(buffer));
  if (e_ret_status != SE_ERROR)
  {
    /*
     * The endianess is the same for storing and reading the data so memcpy is acceptable here.
     * Of course, this code is wrong if the endianess is not the same for reading and writing.
     */
    (void) memcpy(&fw_image_header, buffer, sizeof(SE_FwRawHeaderTypeDef));

    /*
     * We do not check the header validity.
     * We just copy the information.
     */
    p_FwInfo->ActiveFwVersion = fw_image_header.FwVersion;
    p_FwInfo->ActiveFwSize = fw_image_header.FwSize;
  }

  return e_ret_status;
}

/*+ Define your user functions here */

/**
  * @brief Service called by the User Application to Encrypt (AES GCM) DataIn in DataOut
  * @param p_Data data to be processed
  * @param p_Data data processed
  * @param dataLen data length in bytes
  * @retval SE_ErrorStatus SE_SUCCESS if successful, SE_ERROR otherwise.
  */
#ifdef STEP2
SE_ErrorStatus SE_APPLI_UserFunc1(uint8_t *p_DataIn, uint8_t *p_DataOut, uint32_t dataLen, uint8_t * p_Nonce, uint8_t * p_Tag)
#else
SE_ErrorStatus SE_APPLI_UserFunc1(uint8_t *p_DataIn, uint8_t *p_DataOut, uint32_t dataLen)
#endif /* STEP2 */
{
  SE_ErrorStatus e_ret_status = SE_ERROR;

  /*+ Step 2 */
  SE_GCMInitTypeDef se_gcm_init;
  int32_t gcmTagSize;
  /*- Step 2 */

  /* Check the pointer allocation */
  if ( (NULL == p_DataIn) || (NULL == p_DataOut) )
  {
    return SE_ERROR;
  }

#ifdef STEP2
  /*+ Step 2 */
  /* Check the pointer allocation */
  if ( (NULL == p_Nonce) || (NULL == p_Tag) )
  {
    return SE_ERROR;
  }

  if (dataLen > INT32_MAX)
  {
	  /* the uint32_t value cannot be casted on an int32_t */
	  return SE_ERROR;
  }

  /* Prepare a local structure with appropriate types (this step could be skipped) */
  se_gcm_init.HeaderSize = 0;
  se_gcm_init.PayloadSize = (int32_t)dataLen; /* This cast is fine only if we check dataLen before */
  se_gcm_init.pNonce = p_Nonce;
  se_gcm_init.NonceSize = 12; /* a nonce is 96 bits (12 bytes) */
  se_gcm_init.pTag = p_Tag;
  se_gcm_init.TagSize = 16; /* an AES GCM tag is 16 bytes */


  /* Check the pointers allocation */
  if ((se_gcm_init.pNonce == NULL) || (se_gcm_init.pTag == NULL))
  {
    return SE_ERROR;
  }

  /* Common Crypto function call*/
  e_ret_status = SE_CRYPTO_AES_GCM_Encrypt_Init(m_aSE_UserAppKey, &se_gcm_init);

  if (SE_SUCCESS == e_ret_status)
  {
	  e_ret_status = SE_CRYPTO_AES_GCM_Encrypt_Append(p_DataIn, (int32_t)dataLen, p_DataOut, (int32_t *)&dataLen);
  }

  if (SE_SUCCESS == e_ret_status)
  {
	  e_ret_status = SE_CRYPTO_AES_GCM_Encrypt_Finish(p_Tag, &gcmTagSize);

	  if (16 != gcmTagSize)
	  {
		  e_ret_status = SE_ERROR;
	  }
  }

  /*- Step 2 */
#else
  /* Implement here */
  e_ret_status = SE_SUCCESS;
  memcpy(p_DataOut, p_DataIn, dataLen);
#endif /* step 2 */

  return e_ret_status;
}

/**
  * @brief Service called by the User Application to Decrypt (AES GCM) DataIn in DataOut
  * @param p_Data data to be processed
  * @param p_Data data processed
  * @param dataLen data length in bytes*
  * @retval SE_ErrorStatus SE_SUCCESS if successful, SE_ERROR otherwise.
  */
#ifdef STEP2
SE_ErrorStatus SE_APPLI_UserFunc2(uint8_t *p_DataIn, uint8_t *p_DataOut, uint32_t dataLen, uint8_t * p_Nonce, uint8_t * p_Tag)
#else
SE_ErrorStatus SE_APPLI_UserFunc2(uint8_t *p_DataIn, uint8_t *p_DataOut, uint32_t dataLen)
#endif /* STEP2 */
{
  SE_ErrorStatus e_ret_status = SE_ERROR;

  /*+ Step 2 */
  SE_GCMInitTypeDef se_gcm_init;
  int32_t gcmTagSize;
  /*- Step 2 */

  /* Check the pointer allocation */
  if ( (NULL == p_DataIn) || (NULL == p_DataOut) )
  {
    return SE_ERROR;
  }

#ifdef STEP2
  /*+ Step 2 */
  /* Check the pointer allocation */
  if ( (NULL == p_Nonce) || (NULL == p_Tag) )
  {
    return SE_ERROR;
  }

  if (dataLen > INT32_MAX)
  {
	  /* the uint32_t value cannot be cast on an int32_t */
	  return SE_ERROR;
  }

  /* Prepare a local structure with appropriate types (this step could be skipped) */
  se_gcm_init.HeaderSize = 0;
  se_gcm_init.PayloadSize = (int32_t)dataLen; /* This cast is fine only if we check dataLen before */
  se_gcm_init.pNonce = p_Nonce;
  se_gcm_init.NonceSize = 12; /* a nonce is 96 bits (12 bytes) */
  se_gcm_init.pTag = p_Tag;
  se_gcm_init.TagSize = 16; /* an AES GCM tag is 16 bytes */


  /* Check the pointers allocation */
  if ((se_gcm_init.pNonce == NULL) || (se_gcm_init.pTag == NULL))
  {
    return SE_ERROR;
  }

  /* Common Crypto function call*/
  e_ret_status = SE_CRYPTO_AES_GCM_Decrypt_Init(m_aSE_UserAppKey, &se_gcm_init);

  if (SE_SUCCESS == e_ret_status)
  {
	  e_ret_status = SE_CRYPTO_AES_GCM_Decrypt_Append(p_DataIn, (int32_t)dataLen, p_DataOut, (int32_t *)&dataLen);
  }

  if (SE_SUCCESS == e_ret_status)
  {
	  e_ret_status = SE_CRYPTO_AES_GCM_Decrypt_Finish(p_Tag, &gcmTagSize);

	  if (16 != gcmTagSize)
	  {
		  e_ret_status = SE_ERROR;
	  }
  }
  /*- Step 2 */
#else
  /* Implement here */
  e_ret_status = SE_SUCCESS;
  memcpy(p_DataOut, p_DataIn, dataLen);
#endif /* STEP2 */

  return e_ret_status;
}

/*- Define your user functions here */


/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */


/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
