
#include "password.h"
#include "crc8.h"


//-------------------------------------------------------------------------------

// 密码串字符集
#define	CHAR_TAB_LEN	32
#define	CHAR_BITS		5

#define	PSWD_BIT_LEN	(PSWDSTR_LEN*CHAR_BITS)
#define	PSWD_BYTE_LEN	((PSWD_BIT_LEN+CHAR_BITS-1)/8)

#define	CHAR32MASK		0x1F

#define	XOR_VAL			0x59


static const char g_charTable[CHAR_TAB_LEN] = 
{
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
	'L', 'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W',
	'X', 'Y',
};

#define	CLINET_NUM		3		// 客户个数



// 存储序列表
static const u8 g_saveSWTab[CLINET_NUM+1][PSWDSTR_LEN] = 
{
	{	1,	2,	3,	4,	5,	6,	7,	8,	9,	10,	11,	12,	13,	14,	15,	16,	17,	18,	19,	20	},		// 默认
	{	4,	9,	17,	5,	10,	14,	16,	6,	18,	3,	20,	11,	1,	13,	19,	15,	2,	7,	12,	8	},		// 宝盈
	{	13,	7,	12,	4,	6,	19,	3,	10,	17,	20,	11,	18,	15,	5,	14,	2,	8,	1,	9,	16	},		// 上工
	{   10, 4,  11, 8,  16, 12, 5,  9,  17, 19, 7,  14, 20, 3,  13, 1,  15, 2,  6,  18  },      // 再登
};


//-------------------------------------------------------------------------------

typedef union
{
	u8 pswdbin[PSWD_BYTE_LEN];
	struct
	{
		u8 check;		// 校验码
		s32 totalTime;	// 累计改变时间
		s16 thisTime;	// 本次改变时间
		u32 cpuId;		// CPU ID
		u8 clientId;	// 客户ID
		u8 moveBit;		// 移位
	} __attribute__ ((packed)) pswdstruct;

	struct
	{
		u8 check;		// 校验码
		u8 datbuff[12];
	} __attribute__ ((packed)) pswdckdat;

} Password;


//-------------------------------------------------------------------------------


// 得到某个位的值
int GetBitVal(u8 * buff, int bitidx)
{
	int i;
	u8 mod = 0x01;
	u8 num = bitidx % 8;
	buff += bitidx / 8;

	for (i = 0; i < num; i++)
	{
		mod *= 2;
	}

	if ((*buff & mod) != 0)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

// 设置某个位的值
void SetBitVal(u8 * buff, int bitidx, int bitval)
{
	int i;
	u8 mod = 0x01;
	u8 num = bitidx % 8;
	buff += bitidx / 8;

	for (i = 0; i < num; i++)
	{
		mod *= 2;
	}

	if (bitval != 0)
	{
		*buff |= mod;
	}
	else
	{
		*buff &= (~mod);
	}
}


// 循环移位
// movenum > 0, 左移
// movenum < 0, 右移
void CyclicShift(u8 * buff, int bitlen, int movenum)
{
	int mvdir;
	if (buff == 0 || bitlen <= 1 || movenum == 0)
	{
		return;
	}

	if (movenum < 0)	// 右移
	{
		mvdir = -1;
	}
	else		// 左移
	{
		mvdir = 1;
	}

	movenum *= mvdir;
	movenum %= bitlen;

	int bitidx = 0;
	int nbidx;
	int bitval, tmpval;
	// 取出 bitidx == 0 的位
	bitval = GetBitVal(buff, bitidx);
	do
	{
		// 计算新的位置
		if (mvdir < 0)	// 右移
		{
			nbidx = bitidx - movenum;
			if (nbidx < 0)
			{
				nbidx += bitlen;
			}
		}
		else		// 左移
		{
			nbidx = bitidx + movenum;
			if (nbidx >= bitlen)
			{
				nbidx -= bitlen;
			}
		}

		// 先取出 nbidx 原来的位
		tmpval = GetBitVal(buff, nbidx);
		// 将 bitidx 的位写入到 nbidx 的位置
		SetBitVal(buff, nbidx, bitval);
		bitidx = nbidx;
		bitval = tmpval;
	}while(bitidx != 0);
}

//-------------------------------------------------------------------------------

// 解密
int DecodePswdString(PswdCtrl * pCtrl, char * pswdStr, u8 clientId)
{
	char pslist[PSWDSTR_LEN];		// 交换后的 32 进制数据串
	Password pswd;
	u8 moveBit;

	if (pCtrl == 0 || pswdStr == 0)
	{
		return -1;
	}

	memset(pCtrl, 0, sizeof(PswdCtrl));

	if (clientId <= 0 || clientId > CLINET_NUM)
	{
		return -1;
	}

	// 1. 得到密码串后，按照客户序列反向解析，得到正确序列的32进制数据串。
	{
		int i, idx;
		for (i = 0; i < PSWDSTR_LEN; i++)
		{
			idx = g_saveSWTab[clientId][i] - 1;
			pslist[i] = pswdStr[idx];
		}
	}
	// 2. 根据32进制数据串，得到100位的二进制数据串
	{
		int i, j;
		u8 buff32[PSWDSTR_LEN];			// 32进制数据的二进制表示
		for (i = 0; i < PSWDSTR_LEN; i++)
		{
			char ch32 = pslist[i];
			for (j = 0; j < CHAR_TAB_LEN; j++)
			{
				if (ch32 == g_charTable[j])
				{
					break;
				}
			}
			if (j >= CHAR_TAB_LEN)
			{
				return -1;
			}

			buff32[i] = j;
		}
		memset(&pswd, 0, sizeof(Password));
		for (i = PSWDSTR_LEN-1; i >= 0; i--)
		{
			u8 bin = buff32[i];
			bin &= CHAR32MASK;

			for (j = PSWD_BYTE_LEN-1; j > 0; j--)		// 移位 5 位
			{
				pswd.pswdbin[j] <<= CHAR_BITS;
				pswd.pswdbin[j] |= (pswd.pswdbin[j-1] >> (8-CHAR_BITS));
			}
			pswd.pswdbin[0] <<= CHAR_BITS;
			pswd.pswdbin[0] |= bin;
		}
	}
//	3.对二进制字符串做异或操作。
	{
		int i;
		for (i = 0; i < PSWD_BYTE_LEN; i++)
		{
			pswd.pswdbin[i] ^= XOR_VAL;
		}
		pswd.pswdbin[PSWD_BYTE_LEN-1] &= 0x0f;
	}

	// 4. 按照移位规则，反向移位加密信息数据段后，得到密码信息数据段。
	{
		int movenum, idx;
		pswd.pswdstruct.moveBit &= 0x0f;			// 移位数据段
		moveBit = pswd.pswdstruct.moveBit;			// 移位次数索引
		movenum = g_saveSWTab[clientId][moveBit];		// 移位次数
		idx = 0x10;

		while (idx < PSWDSTR_LEN && (movenum == 5 || movenum == 10 || movenum == 15 || movenum == 20))
		{
			movenum = g_saveSWTab[clientId][idx];
			idx++;
		}
		if (idx == PSWDSTR_LEN || (movenum == 5 || movenum == 10 || movenum == 15 || movenum == 20) || movenum <= 0 || movenum > PSWDSTR_LEN)
		{
			return -1;
		}

		if ((moveBit & 0x01) != 0)		// 解密，循环移动
		{
			// 循环左移
		}
		else
		{
			// 循环右移
			movenum *= -1;
		}
		CyclicShift(pswd.pswdbin, PSWD_BIT_LEN-4, movenum);
	}
	// 5. 按照校验算法，检验信息数据段的正确性。
	{
		u8 crc = CalcCrc8(pswd.pswdckdat.datbuff, sizeof(Password)-1);
		if (crc != pswd.pswdstruct.check)
		{
			return -1;
		}
		pCtrl->clientId = pswd.pswdstruct.clientId;
		pCtrl->cpuId = pswd.pswdstruct.cpuId;
		pCtrl->thishours = pswd.pswdstruct.thisTime / TIME_MUTI;
		pCtrl->totalhours = pswd.pswdstruct.totalTime / TIME_MUTI;

		pCtrl->nexttotaltime = (pCtrl->thishours+pCtrl->totalhours)*TIME_MUTI + (int)(pswd.pswdstruct.thisTime+pswd.pswdstruct.totalTime)%TIME_MUTI;
		pCtrl->totaltime = pswd.pswdstruct.totalTime;
		pCtrl->thistime = pswd.pswdstruct.thisTime;
	}

/*
6.验证客户识别码和主板识别码是否符合当前设备。
7.验证上次加密累计时间是否和板卡保存的一致（按小时数验证）。
8.将新的改变时间加到当前计数时间，并写入计数区域。
9.保存密码串到记录区域。
*/
	return 0;
}




