/*--------------------------------------------------------------------------*/
/* Copyright 2020 NXP                                                       */
/*                                                                          */
/* NXP Confidential. This software is owned or controlled by NXP and may    */
/* only be used strictly in accordance with the applicable license terms.   */
/* By expressly accepting such terms or by downloading, installing,         */
/* activating and/or otherwise using the software, you are agreeing that    */
/* you have read, and that you agree to comply with and are bound by, such  */
/* license terms. If you do not agree to be bound by the applicable license */
/* terms, then you may not retain, install, activate or otherwise use the   */
/* software.                                                                */
/*--------------------------------------------------------------------------*/

/**
 * @file  cipher_aes128_ecb_encrypt.c
 * @brief Example AES-128 ECB encryption using the CSSv2 (CLNS component mcuxClCss)
 *
 * @example  cipher_aes128_ecb_encrypt.c
 * @brief    Example AES-128 ECB encryption using the CSSv2 (CLNS component mcuxClCss)
 */

#include <mcuxClCss.h>              // Interface to the entire mcuxClCss component
#include <mcuxCsslFlowProtection.h> // Code flow protection
#include <stdbool.h>                // bool type for the example's return code
#include "fsl_common.h"             // SDK Align

/** Plaintext input for the AES encryption. */
static uint8_t const aes128_input[MCUXCLCSS_CIPHER_BLOCK_SIZE_AES] = {
    0x6BU, 0xC1U, 0xBEU, 0xE2U, 0x2EU, 0x40U, 0x9FU, 0x96U, 0xE9U, 0x3DU, 0x7EU, 0x11U, 0x73U, 0x93U, 0x17U, 0x2AU};

/** Expected ciphertext output of the AES encryption. */
static uint8_t const aes128_expected_output[MCUXCLCSS_CIPHER_BLOCK_SIZE_AES] = {
    0x3AU, 0xD7U, 0x7BU, 0xB4U, 0x0DU, 0x7AU, 0x36U, 0x60U, 0xA8U, 0x9EU, 0xCAU, 0xF3U, 0x24U, 0x66U, 0xEFU, 0x97U};

/** Key for the AES encryption. */
SDK_ALIGN(static uint8_t const aes128_key[MCUXCLCSS_CIPHER_KEY_SIZE_AES_128], 8U) = {
    0x2BU, 0x7EU, 0x15U, 0x16U, 0x28U, 0xAEU, 0xD2U, 0xA6U, 0xABU, 0xF7U, 0x15U, 0x88U, 0x09U, 0xCFU, 0x4FU, 0x3CU};

/** Destination buffer to receive the ciphertext output of the AES encryption. */
static uint8_t aes128_output[MCUXCLCSS_CIPHER_BLOCK_SIZE_AES];

/** Performs AES-128 ECB encryption using mcuxClCss functions.
 * @retval true  The example code completed successfully
 * @retval false The example code failed */
bool cipher_aes128_ecb_encrypt(void)
{
    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Enable_Async()); // Enable the CSSv2.
    // mcuxClCss_Enable_Async is a flow-protected function: Check the protection token and the return value
    if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Enable_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(
        result, token,
        mcuxClCss_WaitForOperation(
            MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_Enable_Async operation to complete.
    // mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
    if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    mcuxClCss_CipherOption_t cipher_options = {
        0U}; // Initialize a new configuration for the planned mcuxClCss_Cipher_Async operation.
    cipher_options.bits.cphmde =
        MCUXCLCSS_CIPHERPARAM_ALGORITHM_AES_ECB; // Configure the AES block cipher mode of operation to be the ECB
                                                 // (Electronic Codebook) mode.
    cipher_options.bits.dcrpt =
        MCUXCLCSS_CIPHER_ENCRYPT; // Configure that the mcuxClCss_Cipher_Async operation shall perform  encryption.
    cipher_options.bits.extkey = MCUXCLCSS_CIPHER_EXTERNAL_KEY; // Configure that an external key should be used.

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(
        result, token,
        mcuxClCss_Cipher_Async(                 // Perform the encryption.
            cipher_options,                     // Set the prepared configuration.
            (mcuxClCss_KeyIndex_t)0U,           // This parameter (keyIdx) is ignored, since an external key is used.
            aes128_key, sizeof(aes128_key),     // The AES key for the encryption (external key).
            aes128_input, sizeof(aes128_input), // The plaintext to encrypt. Note that this plaintext's length is a
                                                // multiple of the block length, so no padding is required.
            NULL,                               // This parameter (pIV) is ignored, since the ECB mode is used.
            aes128_output                       // Output buffer, which the operation will write the ciphertext to.
            ));
    // mcuxClCss_Cipher_Async is a flow-protected function: Check the protection token and the return value
    if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Cipher_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
        return false; // Expect that no error occurred, meaning that the mcuxClCss_Cipher_Async operation was started.
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(
        result, token,
        mcuxClCss_WaitForOperation(
            MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_Cipher_Async operation to complete.
    // mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
    if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    for (size_t i = 0U; i < sizeof(aes128_output); i++)
    {
        if (aes128_output[i] != aes128_expected_output[i])
            return false; // Expect that the resulting ciphertext matches our expected output
    }

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Disable()); // Disable the CSSv2.
    // mcuxClCss_Disable is a flow-protected function: Check the protection token and the return value
    if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Disable) != token) || (MCUXCLCSS_STATUS_OK != result))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    return true;
}
