/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2018 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

/*******************************************************************************
 * Includes
 ******************************************************************************/

#include "fsl_device_registers.h"
#include "fsl_debug_console.h"
#include "board.h"

#include "fsl_hashcrypt.h"

#include <string.h>

#include "pin_mux.h"
#include "clock_config.h"
/*******************************************************************************
 * Definitions
 ******************************************************************************/

#define TEST_ASSERT(a, str)  \
    if (!(a))                \
    {                        \
        PRINTF("%s error\r\n", str); \
        do                   \
        {                    \
        } while (1);         \
    }

#define OTP_INIT_API ((void (*)(uint32_t src_clk_freq))FSL_ROM_OTP_INIT_ADDR)

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

/*******************************************************************************
 * Code
 ******************************************************************************/

void TestAesOtpKeyEcb(void)
{
    static const uint8_t plainAes128[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
                                          0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
		/* cipher text based on key = all zeros to avoid programming OTP bits */
    static const uint8_t cipherAes128[] = {0x59, 0x55, 0xEE, 0x51, 0xB7, 0xF0, 0x7E, 0x8D, 
																					 0x99, 0x42, 0x06, 0x50, 0x44, 0x67, 0x85, 0x80};
																					 
    uint8_t cipher[16];
    uint8_t output[16];
    status_t status;

    hashcrypt_handle_t m_handle;

		/* secret key default is OTP, 192-bit key */
		SYSCTL0->AESKEY_SRCSEL = 0x2;
    m_handle.keyType = kHASHCRYPT_SecretKey;
																					 
		/* 192-bit key loaded to OTP shadow register */
		OCOTP->OTP_SHADOW[107] = 0; 
		OCOTP->OTP_SHADOW[112] = 0x03020100;																			 
		OCOTP->OTP_SHADOW[113] = 0x07060504;																			 
		OCOTP->OTP_SHADOW[114] = 0x0B0A0908;																			 
		OCOTP->OTP_SHADOW[115] = 0x0F0E0D0C;																			 
		OCOTP->OTP_SHADOW[116] = 0x13121110;																			 
		OCOTP->OTP_SHADOW[117] = 0x17161514;																			 
		m_handle.keySize = kHASHCRYPT_Aes192;

    status = HASHCRYPT_AES_EncryptEcb(HASHCRYPT, &m_handle, plainAes128, cipher, 16);
    TEST_ASSERT(kStatus_Success == status, "ECB");
    TEST_ASSERT(memcmp(cipher, cipherAes128, 16) == 0, "ECB");

    status = HASHCRYPT_AES_DecryptEcb(HASHCRYPT, &m_handle, cipher, output, 16);
    TEST_ASSERT(kStatus_Success == status, "ECB");
    TEST_ASSERT(memcmp(output, plainAes128, 16) == 0, "ECB");

    PRINTF("AES ECB Test - 192-bit OTP key - pass\r\n");
}

void TestAesOtpKeyCbc(void)
{
    static const uint8_t plainAes128[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
                                          0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
    static const uint8_t ive[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                                  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
		/* cipher text based on key = all zeros to avoid programming OTP bits */
    static const uint8_t cipherAes128[] = {0xFC, 0x96, 0x2C, 0xED, 0x40, 0xC6, 0x84, 0x08, 
		                                       0xA2, 0xF5, 0x06, 0xBB, 0x32, 0x10, 0x38, 0x5F };
																	
    uint8_t cipher[16];
    uint8_t output[16];
    status_t status;

    hashcrypt_handle_t m_handle;

		/* secret key default is OTP, 192-bit key */
		SYSCTL0->AESKEY_SRCSEL = 0x2;
    m_handle.keyType = kHASHCRYPT_SecretKey;

		/* 192-bit key loaded to OTP shadow register */
		OCOTP->OTP_SHADOW[107] = 0; 
		OCOTP->OTP_SHADOW[112] = 0x03020100;																			 
		OCOTP->OTP_SHADOW[113] = 0x07060504;																			 
		OCOTP->OTP_SHADOW[114] = 0x0B0A0908;																			 
		OCOTP->OTP_SHADOW[115] = 0x0F0E0D0C;																			 
		OCOTP->OTP_SHADOW[116] = 0x13121110;																			 
		OCOTP->OTP_SHADOW[117] = 0x17161514;																			 
		m_handle.keySize = kHASHCRYPT_Aes192;

    status = HASHCRYPT_AES_EncryptCbc(HASHCRYPT, &m_handle, plainAes128, cipher, 16, ive);
    TEST_ASSERT(kStatus_Success == status, "CBC");
    TEST_ASSERT(memcmp(cipher, cipherAes128, 16) == 0, "CBC");

    status = HASHCRYPT_AES_DecryptCbc(HASHCRYPT, &m_handle, cipher, output, 16, ive);
    TEST_ASSERT(kStatus_Success == status, "CBC");
    TEST_ASSERT(memcmp(output, plainAes128, 16) == 0, "CBC");

    PRINTF("AES CBC Test - 192-bit OTP key - pass\r\n");
}

void TestAesOtpKeyCtr(void)
{
    static uint8_t aes_ctr_test01_counter_1[16]      = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
                                                   0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
    static uint8_t aes_ctr_test01_counter_2[16]      = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
                                                   0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
    static uint8_t aes_ctr_test01_plaintext[]        = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
                                                        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
		/* cipher text based on key = all zeros to avoid programming OTP bits */
    static const uint8_t aes_ctr_test01_ciphertext[] = {0xaf, 0xa8, 0x99, 0x3e, 0x55, 0x66, 0x14, 0xc2, 
		                                                    0x28, 0x3c, 0xb2, 0x54, 0xbf, 0xdd, 0xf7, 0xf5};
    uint8_t cipher[16]                               = {0};
    uint8_t output[16]                               = {0};
    status_t status;

    hashcrypt_handle_t m_handle;

		/* secret key default is OTP, 256-bit key */
		SYSCTL0->AESKEY_SRCSEL = 0x2;
    m_handle.keyType = kHASHCRYPT_SecretKey;

		/* 256-bit key loaded to OTP shadow register */
		OCOTP->OTP_SHADOW[107] = 0; 
		OCOTP->OTP_SHADOW[112] = 0x03020100;
		OCOTP->OTP_SHADOW[113] = 0x07060504;
		OCOTP->OTP_SHADOW[114] = 0x0B0A0908;
		OCOTP->OTP_SHADOW[115] = 0x0F0E0D0C;
		OCOTP->OTP_SHADOW[116] = 0x13121110;
		OCOTP->OTP_SHADOW[117] = 0x17161514;
		OCOTP->OTP_SHADOW[118] = 0x1B1A1918;
		OCOTP->OTP_SHADOW[119] = 0x1F1E1D1C;
		m_handle.keySize = kHASHCRYPT_Aes256;

    /* Encrypt */
    status = HASHCRYPT_AES_CryptCtr(HASHCRYPT, &m_handle, aes_ctr_test01_plaintext, cipher, 16,
                                    aes_ctr_test01_counter_1, NULL, NULL);
    TEST_ASSERT(kStatus_Success == status, "CTR");
    TEST_ASSERT(memcmp(cipher, aes_ctr_test01_ciphertext, 16) == 0, "CTR");

    /* Decrypt */
    status = HASHCRYPT_AES_CryptCtr(HASHCRYPT, &m_handle, cipher, output, 16, aes_ctr_test01_counter_2, NULL, NULL);
    TEST_ASSERT(kStatus_Success == status, "CTR");
    TEST_ASSERT(memcmp(output, aes_ctr_test01_plaintext, sizeof(aes_ctr_test01_plaintext)) == 0, "CTR");

    PRINTF("AES CTR Test - 256-bit OTP key - pass\r\n");
}

/*!
 * @brief Main function.
 */
int main(void)
{
    /* Init hardware */
    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();

    /* test description */
    PRINTF("\r\nAES ECB, CBC, CTR testing using OTP key (via OTP shadow registers)\r\n");
    PRINTF("If OTP shadow register 107 (KEY_SCRAMBLE_SEED) is 0,\r\n");
    PRINTF("OTP shadow registers 119-112 (OTP_MASTER_KEY) function\r\n");
    PRINTF("as a test key for the AES engine\r\n\r\n");

    /* Initialize Hashcrypt */
    HASHCRYPT_Init(HASHCRYPT);

    /* Call HASH APIs */
    TestAesOtpKeyEcb();
    TestAesOtpKeyCbc();
    TestAesOtpKeyCtr();

    HASHCRYPT_Deinit(HASHCRYPT);

    while (1)
    {
    }
}
