#include "hcu_cases.h"
#include "flash_driver.h"
#include "interrupt_manager.h"

#define HCU_NVR_START       (0x11001A00U) 
#define HCU_NVR_END         (0x11001DFFU)
#define HCU_NVR_SIZE        (1024U)
#define HCU_NVR_BLOCK_SIZE  (0x10U)

/* AES-128 key */
static const uint32_t key[4] = {
    0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c
};

/* PlainText to encrypt */
static const uint32_t plainText[16] = { 
    0x6bc1bee2, 0x2e409f96, 0xe93d7e11, 0x7393172a,
    0xae2d8a57, 0x1e03ac9c, 0x9eb76fac, 0x45af8e51,
    0x30c81c46, 0xa35ce411, 0xe5fbc119, 0x1a0a52ef,
    0xf69f2445, 0xdf4f9b17, 0xad2b417b, 0xe66c3710
};

/* AES-CMAC encrypt result */
static uint8_t mac_result[16] = { 
    0xBF, 0xEA, 0x13, 0xE3, 0xEA, 0x66, 0x0C, 0x85,
    0x80, 0x4E, 0xB3, 0xBF, 0x8F, 0xA5, 0x05, 0x95
};

static uint8_t result[16];

/* AES-CMAC configuration */
static hcu_cmac_config_t cmacConfig =
{
    .macPtr = result,
    .macLen = 16,
};

/* HCU SW encrypt configuration */
static aes_algorithm_config_t encryptSwCfg = {
    .dataInputPtr = plainText,
    .msgLen = 64,
    .swKeyPtr = key,
    .hwKeySelected = false,
    .keySize = KEY_SIZE_128_BITS,
    .msgType = MSG_ALL,
};

/* HCU HW encrypt configuration */
static aes_algorithm_config_t encryptHwCfg = {
    .dataInputPtr = plainText,
    .msgLen = 64,
    .hwKeySelected = true,
    .hwKeySlot = 0,
    .keySize = KEY_SIZE_128_BITS,
    .msgType = MSG_ALL,
};

static hcu_user_config_t hcuUserConfig = {
    .swap = MODE_SWAPPING_NO,
    .carryType = HCU_USING_POLLING,
    .ingressDMAChannel = 0U,
    .egressDMAChannel = 1U,
};

static hcu_state_t hcuState;

void hcu_cmac_demo(void)
{
    uint32_t i = 0;
    status_t status = STATUS_SUCCESS;
    PRINTF("HCU AES-CMAC Using Polling!\r\n");

    /* Init HCU */
    status |= HCU_DRV_Init(&hcuUserConfig, &hcuState);

    PRINTF("AES-CMAC generation!\r\n");
    /* Start AES-CMAC generation */
    status |= HCU_DRV_GenerateMAC(&encryptSwCfg, &cmacConfig);
    /* Wait encrypt done */
    while(hcuState.cmdInProgress);

    /* Check mac result */
    for(i = 0; i < 16; i++)
    {
        if(result[i] != mac_result[i])
        {
            PRINTF("AES-CMAC generation Failed!\r\n");
            PRINTF("Expected is 0x%02X, actual is 0x%02X.\r\n", mac_result[i], result[i]);
            break;
        }
    }
    if(i == 16)
    {
        PRINTF("AES-CMAC generation success!\r\n");
    }

    PRINTF("AES-CMAC authorization!\r\n");
    /* Start AES-CMAC authorization */
    status |= HCU_DRV_AuthorizeMAC(&encryptSwCfg, &cmacConfig);
    /* Wait encrypt done */
    while(hcuState.cmdInProgress);
    if(status != STATUS_SUCCESS)
    {
        PRINTF("AES-CMAC authorization Failed!\r\n");
    }
    else
    {
        PRINTF("AES-CMAC authorization Pass!\r\n");  
    }

    PRINTF("AES-CMAC wrong MAC authorization!\r\n");
    /* Modify MAC and check if authorization FAIL */
    result[0] += 1;
    /* Start AES-CMAC authorization */
    status |= HCU_DRV_AuthorizeMAC(&encryptSwCfg, &cmacConfig);
    /* Wait encrypt done */
    while(hcuState.cmdInProgress);
    if(status != STATUS_HCU_MAC_CHECK_ERROR)
    {
        PRINTF("AES-CMAC wrong MAC authorization Failed!\r\n");
    }
    else
    {
        PRINTF("AES-CMAC wrong MAC authorization Pass!\r\n");  
    }

    PRINTF("AES-CMAC generation by hardware key load from HCU_NVR!\r\n");
    PRINTF("Program HCU NVR.\r\n");
    INT_SYS_DisableIRQGlobal();
    EFM->CUS_KEY = 0x4dff32;
    /* Erase all HCU NVR */
    status |= FLASH_DRV_EraseSector(0, HCU_NVR_START, HCU_NVR_SIZE);
    /* Program one key to HCU NVR */
    status |= FLASH_DRV_Program(0, HCU_NVR_START, HCU_NVR_BLOCK_SIZE, key);
    INT_SYS_EnableIRQGlobal();

    /* Start AES-CMAC generation by hardware key */
    status |= HCU_DRV_GenerateMAC(&encryptHwCfg, &cmacConfig);
    /* Wait encrypt done */
    while(hcuState.cmdInProgress);

    /* Check mac result */
    for(i = 0; i < 16; i++)
    {
        if(result[i] != mac_result[i])
        {
            PRINTF("AES-CMAC generation Failed!\r\n");
            PRINTF("Expected is 0x%02X, actual is 0x%02X.\r\n", mac_result[i], result[i]);
            break;
        }
    }
    if(i == 16)
    {
        PRINTF("AES-CMAC generation success!\r\n");
    }
    
    HCU_DRV_DeInit(&hcuState);
}
