/**************************************************************************//**
 *
 *  \copyright  This software is the property of  Technologies. Any
 *              information contained in this doc should not be reproduced,
 *              or used, or disclosed without the written authorization from
 *               Technologies.
 *
 *  \brief      This is a source file to make seed and verify a key.
 *
 *  \file       bl_access_udsdemo.c
 *  \ingroup    security_manager_module
 *  \author     
 *
 *  \version    5.1.0
 *  \date       27/03/2018
 *
 *  \par        Changelist
 *      Version  | Date       | Authors          | CR# | Descriptions
 *      -------- | ---------- | ---------------- | --- | ------------
 *      01.00.00 | 25/03/2018 | xucong      | N/A | Boot010001
 *
 *****************************************************************************/
#include "bl_system_cfg.h"

#include "bl_common.h"
#include "bl_security_funcfg.h"
#include "bl_access_udsdemo.h"
#include "bl_adpt_uds_platform.h"
#include "bl_dcm_cfg.h"
#include "bl_adapter_cfg.h"

/*****************************************************************************
 *  QAC Suppression
 *****************************************************************************/
/*PRQA S 602,1532,3212,3227,3453 EOF*/
/*
 * MISRA-C:2004 20.2(602):The identifier is reserved for use by the library.
 * The Bootloader do not use any library funtion and use the underscores to
 * indicate that the function is a interal function.
 *
 * 1532:The function is only referenced in one translation unit.
 * all functions in this file are configurations in the Security Module.
 *
 * 3212:This explicit cast is redundant and could be removed.
 * ACC_UDSDEMO_KEY_FROM_BUF and ACC_UDSDEMO_SEED_TO_BUF are not explicit cast.
 *
 * 3227:The parameter is never modified and so it could be declared with const.
 * Acc_UdsDemoGetSeed, the seed will be modify.
 * Acc_UdsDemoVerifyKey, the key is declared with const.
 *
 * MISRA-C:2004 19.7(3453):A function could probably be used instead of this
 * function-like macro.
 * ACC_UDSDEMO_KEY_FROM_BUF macro do not have side-effect.
 * ACC_UDSDEMO_SEED_TO_BUF macro do not have side-effect.
 *
 */

/*****************************************************************************
 *  Verify The Configurations of Macro
 *****************************************************************************/
#if ((SECM_ACCESS_KEY_SIZE != 4u) && (SECM_ACCESS_KEY_SIZE != 2u) && (SECM_ACCESS_KEY_SIZE != 16u) )
#error "The size of a key is only four or two, other values are invalid."
#endif

#if ((SECM_ACCESS_SEED_SIZE != 4u) && (SECM_ACCESS_SEED_SIZE != 2u))
#error "The size of a seed is only four or two, other values are invalid."
#endif
/*****************************************************************************
 *  Internal Macro Definitions
 *****************************************************************************/
#if (SECM_ACCESS_KEY_SIZE == 4u)    //進入該選項
#define ACC_UDSDEMO_KEY_MASK                (0xA5CEFDB6UL)
#define ACC_UDSDEMO_KEY_FROM_BUF(buf)       BL_BE32_TO_MCU(buf)   //buf = * buf
#elif (SECM_ACCESS_KEY_SIZE == 2u)
#define ACC_UDSDEMO_KEY_MASK                (0xDFB6u)
#define ACC_UDSDEMO_KEY_FROM_BUF(buf)       BL_BE16_TO_MCU(buf)
#elif (SECM_ACCESS_KEY_SIZE > 4u)
#define ACC_UDSDEMO_KEY_MASK                (0xDFu)
#define ACC_UDSDEMO_KEY_FROM_BUF(buf)       BL_BE16_TO_MCU(buf)
#endif

#if (SECM_ACCESS_SEED_SIZE == 4u)  //進入該選項
/** \brief It is used to calculate the random seed*/
#define ACC_UDSDEMO_RANDOM_SEED             (16807UL)
#define ACC_UDSDEMO_SEED_INITVALUE          (0x12350012UL)
#define ACC_UDSDEMO_SEED_TO_BUF(seed,buf)   BL_MCU_TO_BE32(buf,seed)  //*buf = seed
#elif (SECM_ACCESS_SEED_SIZE == 2u)
/** \brief It is used to calculate the random seed*/
#define ACC_UDSDEMO_RANDOM_SEED             (16807u)
#define ACC_UDSDEMO_SEED_INITVALUE          (0x1235u)
#define ACC_UDSDEMO_SEED_TO_BUF(seed,buf)   BL_MCU_TO_BE16(buf,seed)
#elif (SECM_ACCESS_SEED_SIZE > 4u)
#define ACC_UDSDEMO_RANDOM_SEED             (3u)
#define ACC_UDSDEMO_SEED_INITVALUE          (0x12u)
#define ACC_UDSDEMO_SEED_TO_BUF(seed,buf)   BL_MCU_TO_BE16(buf,seed)

#endif

/*****************************************************************************
 *  Internal Type Definitions
 *****************************************************************************/
#if (SECM_ACCESS_SEED_SIZE == 4u)   //是該選項
typedef bl_u32_t bl_UdsDemoSeed_t;
#elif (SECM_ACCESS_SEED_SIZE == 2u)
typedef bl_u16_t bl_UdsDemoSeed_t;
#else
typedef bl_u16_t bl_UdsDemoSeed_t;
#endif

#if (SECM_ACCESS_KEY_SIZE == 4u)   //是該選項
typedef bl_u32_t bl_UdsDemoKey_t;
#elif (SECM_ACCESS_KEY_SIZE == 2u)
typedef bl_u16_t bl_UdsDemoKey_t;
#else
typedef bl_u16_t bl_UdsDemoKey_t;
#endif


/*****************************************************************************
 *  Internal Structure Definitions
 *****************************************************************************/

/*****************************************************************************
 *  Internal Function Declarations
 *****************************************************************************/
/** \brief Calculate the key from the gs_UdsDemoSeed.*/
static bl_UdsDemoKey_t _Acc_UdsDemoCalculateKey(void);

/*****************************************************************************
 *  Internal Variable Definitions
 *****************************************************************************/
STATIC bl_UdsDemoSeed_t gs_UdsDemoSeed;  //u32

/*****************************************************************************
 *  Global Variable Definitions
 *****************************************************************************/

//#define GETBIT(a,b)  (unsigned char)(((a) & (1<<(b) ))!=0)/*fetch bit "b" out of "a"*/

/*****************************************************************************
 *  Function Definitions
 *****************************************************************************/
/**************************************************************************//**
 *
 *  \details Initialize the DEMO security access used for UDS.
 *
 *  \since  V1.0.0
 *
 *****************************************************************************/
void Acc_UdsDemoInit(void)
{
	gs_UdsDemoSeed = ACC_UDSDEMO_SEED_INITVALUE;
}

/**************************************************************************//**
 *
 *  \details Make a new seed.
 *
 *  \since  V5.0.0
 *
 *****************************************************************************/
void Acc_UdsDemoMakeNewSeed(void)
{
	#if 1
	gs_UdsDemoSeed *= ACC_UDSDEMO_RANDOM_SEED;
	#else
	gs_UdsDemoSeed =  0x12345678;
	#endif
	return ;
}

/**************************************************************************//**
 *
 *  \details Get current seed value.
 *
 *  \param[out]  seed - the value of current seed.
 *
 *  \since  V1.0.0
 *
 *****************************************************************************/
void Acc_UdsDemoGetSeed(bl_Buffer_t *seed)
{
    ACC_UDSDEMO_SEED_TO_BUF(gs_UdsDemoSeed,seed);  // seed = gs_UdsDemoSeed  

    return ;
}

/**************************************************************************//**
 *
 *  \details Verify the value of transmitted key whether is right.
 *
 *  \param[in]  key - the value of transmitted key.
 *
 *  \return If the transmitted key value is right return BL_ERR_OK, otherwise
 *          return BL_ERR_NOT_OK.
 *
 *  \retval BL_ERR_OK - the transmitted key value is right.
 *  \retval BL_ERR_NOT_OK - the transmitted key value is NOT right.
 *
 *  \since  V1.0.0
 *
 *****************************************************************************/
bl_Return_t Acc_UdsDemoVerifyKey(const bl_Buffer_t *key)
{
    bl_Return_t ret = BL_ERR_NOT_OK;
    bl_UdsDemoKey_t calKey;
    bl_UdsDemoKey_t tranKey;

    calKey = _Acc_UdsDemoCalculateKey();   //這是相當於本地算出來的
    tranKey = ACC_UDSDEMO_KEY_FROM_BUF(key);  // tranKey = *key  --這是相當於 診斷上收回來的數據；

    if (calKey == tranKey)
    {
        ret = BL_ERR_OK;
    }

    return ret;
}

/**************************************************************************//**
 *
 *  \details An algorithm is used to calculate the key by a seed.
 *
 *  \return the key value
 *
 *  \since V1.0.0
 *
 *****************************************************************************/

static const u32 key_u32= 0x00000017;

static bl_UdsDemoKey_t _Acc_UdsDemoCalculateKey(void)
{
	bl_UdsDemoKey_t key = 0;
#if 0
	/*When the size of seed is 2, there will be a necessary explicit cast.*/
	key = (((bl_UdsDemoKey_t)gs_UdsDemoSeed ^ ACC_UDSDEMO_KEY_MASK)
								+ ACC_UDSDEMO_KEY_MASK);
	return key;
#else
	#if 0
	bl_u8_t PowArray_P[16] = { 0 };
	bl_u8_t PowArray_N[16] = { 0 };
	bl_u8_t i; /*programming flash */
	bl_UdsDemoKey_t Key_P=0, Key_N=0, key_tmp=0;
	for (i = 0; i < 15; i++)
	{
		PowArray_P[i] = PowArray_N[i] = 0;
		if ((gs_UdsDemoSeed & 0x8000u) != 0)
		{
			PowArray_P[i] = 1;
		}
		else
		{
			PowArray_N[i] = 1;
		}
		gs_UdsDemoSeed <<= 1;
		Key_P += PowArray_P[i] * Brilliance_f60.KeyArrayCom[i];
		Key_N += PowArray_N[i] * Brilliance_f60.KeyArrayCom[i];
	}
	PowArray_P[15] = PowArray_N[15] = 0;
	if ((gs_UdsDemoSeed & 0x8000u) != 0)
	{
		PowArray_P[15] = 1;
	}
	else
	{
		PowArray_N[15] = 1;
	}
	Key_P += PowArray_P[15] * Brilliance_f60.KeyArrayTs;
	Key_N += PowArray_N[15] * Brilliance_f60.KeyArrayTs;
	if (Key_P >= Key_N)
	{
		key_tmp = (Key_P - Key_N);
	}
	else
	{
		key_tmp = (Key_N - Key_P);
	}
	key_tmp = key_tmp * 32;
	key_tmp += (Key_P & Brilliance_f60.kypMask);
	key = key_tmp & Brilliance_f60.MASK; //[lev_index];
	#else
	bl_u8_t i, Key[4];//,cal_data[4];
	bl_u8_t MagicSeed[4] = {0};
	//static const bl_u8_t xor_array[4] = {0x44U, 0x4DU, 0x53U, 0x16U};
	u32 l_seed =0;
	u32 l_result=0;
	u32 l_key;

	Acc_UdsDemoGetSeed(MagicSeed);
	l_seed= ((u32)MagicSeed[0]<<24) | ((u32)MagicSeed[1]<<16) | ((u32)MagicSeed[2]<<8) | ((u32)MagicSeed[3]);

	l_result = ((((l_seed >> 1) ^ l_seed) <<3) ^ (l_seed >>2));
	l_key = l_result ^ key_u32;
	Key[0] = l_key>>24;
	Key[1] = l_key>>16;
	Key[2] = l_key>>8;
	Key[3] = l_key;

	key = ACC_UDSDEMO_KEY_FROM_BUF(Key);  //key = *Key
	#endif

	return key;
#endif
}

