/******************************************************************************
版权所有：	
文件名称：	encrypt_core.c
文件版本：	01.01
创建作者:	   sunxi
创建日期：	2017-04-27
功能说明：	国网加密核心模块
其它说明：
修改记录：
*/
/*------------------------------- 头文件 --------------------------------------
*/
#include "head.h"
#ifdef LINUX_KERNEL_APP
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/wait.h> 
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/ioctls.h>
#include <linux/syscalls.h> 
#include <termios.h>
#include <linux/slab.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#else
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/wait.h> 
#include <termios.h>
#endif

 
/*------------------------------- 宏定义 --------------------------------------
*/
// 报文类型定义
#define SEC_MSG_OBJECT_MASK			0XC0	// 相对终端连接对象屏蔽码
#define SEC_MSG_OBJECT_ZZ			0X00	// 主站
#define SEC_MSG_OBJECT_YW			0X40	// 运维
#define SEC_MSG_OBJECT_WG			0X80	// 网关
#define SEC_MSG_OBJECT_BY			0XC0	// 备用

// 对称密钥标识，终端发出的加密报文，全部填0
#define SEC_MSG_ENCRYPT				0X08	// 加密标志
#define SEC_MSG_KID_MASK			0X07	// 对称密码屏蔽码
#define SEC_MSG_KID_ZD				0X00	// 终端
#define SEC_MSG_KID_ZZ				0X01	// 主站
#define SEC_MSG_KID_YW				0X02	// 运维

// 应用类型定义
#define SEC_APP_GROUP_MASK			0XF0	// 应用类型组屏蔽码
#define SEC_APP_GROUP_GY			0X00	// 规约业务
#define SEC_APP_GROUP_GY1			0X10	// 规约业务1
#define SEC_APP_GROUP_WG			0X20	// 认证网关和终端交互
#define SEC_APP_GROUP_YW			0X30	// 现场运维工具和终端交互
#define SEC_APP_GROUP_YW1			0X40	// 现场运维工具和终端交互1
#define SEC_APP_GROUP_ZZ_VRY		0X50	// 主站和终端交互，认证类
#define SEC_APP_GROUP_ZZ_KEY		0X60	// 主站和终端交互，密钥管理类
#define SEC_APP_GROUP_ZZ_CER		0X70	// 主站和终端交互，证书管理类
#define SEC_APP_GROUP_BACKUP		0X80	// 此处开始备用

// 错误码
// 以下为安全扩展错误码
#define SEC_ERR_OK				0X9000 // 成功
#define SEC_ERR_AUTH			0X9090 // 认证失败
#define SEC_ERR_KEY_UPDATE		0X9091 // 密钥更新失败，主站，对应0X62，0X64
#define SEC_ERR_KEY_RESTORE		0X9092 // 密钥恢复失败，运维，对应0X46 ????
#define SEC_ERR_CER_IN			0X9093 // 证书导入失败，运维，对应类型0X3E,0X40
#define SEC_ERR_CER_OUT			0X9094 // 证书导出失败，运维，但是导出没有对应报文上送错误码
#define SEC_ERR_CER_GET			0X9095 // 证书提取失败，主站，但是提取没有对应报文上送错误码
#define SEC_ERR_FRAME			0X9096 // 分帧数据接收失败，运维，只有运维能够返回分帧结果。
#define SEC_ERR_CER_UPDATE		0X9097 // 证书远程更新/下载失败，主站，更新/下载证书用

// 以下为业务扩展错误码
#define SEC_ERR_TYPE			0x9101 // 业务应用类型错误
#define SEC_ERR_VERIFY			0x9102 // 报文验签失败 
#define SEC_ERR_JM				0x9103 // 报文解密失败
#define SEC_ERR_RANDOM			0x9104 // 随机数验证失败
#define SEC_ERR_TIME			0x9105 // 时间校验失败
#define SEC_ERR_WJM				0x9106 // 业务安全要求不合规
#define SEC_ERR_PROC			0x9107 // 业务安全流程非法 
#define SEC_ERR_ACCESS			0x9108 // 权限不够 
#define SEC_ERR_UNKNOWN			0x9109 // 未知错误
#define SEC_ERR_MSG				0x9110 // 报文长度有误或解析失败

// 报文位置
#define SEC_POS_TYPE			5	// 4为高8位，保留为0；5为低8位，实际报文类型
#define SEC_POS_APP				6		
#define SEC_POS_DATA			7		
#define SEC_POS_EXT_LEN			7	// 没有应用数据区时，长度的位置	
#define SEC_POS_EXT_DATA		9	// 没有应用数据区时，数据的位置		

// 连接对象状态
enum
{
	SEC_ST_IDLE,		// 空闲
	SEC_ST_AUTH_GETWAY,	// 网关身份认证
	SEC_ST_AUTH1,		// 主站身份认证1
	SEC_ST_AUTH2,		// 主站身份认证2
	SEC_ST_BUSINESS,	// 业务阶段
};

#define SEC_BUF_SIZE			1024
#define SEC_DATA_LEN			(SEC_BUF_SIZE - 16)

// 加密使用数据的长度
#define SEC_RANDOM_LEN			8		// 随机数长度
#define SEC_YW_ID_LEN			8		// 运维ID长度
#define SEC_CER_FRAME_LEN		0XDC	// 证书上传分帧长度 //0XF0->0xDC modify by EWen 兼容蓝牙分帧处理 
#define SEC_MD5_LEN				16		// MD5摘要长度
#define SEC_MD5_PAGE_SIZE		8192	// MD5摘要计算页长度


/*------------------------------ 类型结构 -------------------------------------
*/
//链路状态维护
typedef struct sec_lnk
{
	u8 obj; 					// 连接对象，主站，还是运维工具
	u8 status;					// 状态
	
	uint32_t us0; 			// 最后报文时间
}sec_lnk_t;


typedef struct sec_app_type
{

	u8 ti;	// 规约报文类型标识
	u8 cot; // 规约报文传送原因
	u8 se;	// 规约报文选择执行
	u8 jm;	// 规约报文是否加密
	u8 at;	// 安全应用类型
}sec_app_type_t;


/*------------------------------ 全局变量 -------------------------------------
*/
// 会话过程中需保存的数据
u8 g_sec_zd_random[SEC_RANDOM_LEN];		// 终端随机数，目前只在程序升级时用
u8 g_sec_zz_random[SEC_RANDOM_LEN*2]; 	// 主站随机数，后8字节是前8字节的取反
u8 g_sec_yw_random[SEC_RANDOM_LEN*3]; 	// 运维随机数，中8字节和前8字节相同，后8字节是前8字节的取反
u8 g_sec_yw_id[SEC_YW_ID_LEN];				// 证书管理工具ID


int g_sec_md5_ret=-1;

// 加密输入输出BUF
u8  g_sec_in[SEC_BUF_SIZE];
u8  g_sec_out[SEC_BUF_SIZE];

// 证书BUF
u8  g_cer_buf[SEC_BUF_SIZE];
u8  g_cer_at;	// 证书应用类型
u8  g_cer_idx;	// 证书标识
u8  g_cer_frm;  // 帧索引
u16 g_cer_len;	// 已接收证书长度

// 连接状态维护
sec_lnk_t g_sec_lnk[COMM_CHANNEL_NUM];

sec_app_type_t g_sec_app_type[] = 
{
	//定长帧
	{0x00,0x00,0x00,0x00,0x00}, // 定长帧，不带类型标识
	
	// 遥控
	// 45，46
	{45 ,0x06,0x01,0x01,0x05}, // 选择 需与遥控执行区分，靠se位判断 se=1
	{45 ,0x08,0x01,0x01,0x05}, // 撤销
	{45 ,0x07,0x01,0x01,0x02}, // 选择确认 se=1
	{45 ,0x09,0x01,0x01,0x02}, // 撤销确认
	{45 ,0x06,0x00,0x01,0x07}, // 执行 se=0

	{46 ,0x06,0x01,0x01,0x05}, // 选择 需与遥控执行区分，靠se位判断 se=1
	{46 ,0x08,0x01,0x01,0x05}, // 撤销
	{46 ,0x07,0x01,0x01,0x02}, // 选择确认 se=1
	{46 ,0x09,0x01,0x01,0x02}, // 撤销确认
	{46 ,0x06,0x00,0x01,0x07}, // 执行 se=0

	//写文件	 210
	{210,0x06,0x01,0x01,0x01}, // 写文件激活
	// 远程参数读写
	{200,0x06,0x00,0x01,0x01}, // 切换定值区
	{203,0x06,0x01,0x01,0x01}, // 参数预置 se=1
	{203,0x08,0x00,0x01,0x01}, // 参数终止
	{203,0x07,0x01,0x01,0x02}, // 参数预置确认 se=1
	{203,0x09,0x00,0x01,0x02}, // 参数终止确认
	{203,0x06,0x00,0x01,0x03}, // 参数固化	 se=0
	
	// 远程程序升级
	{211,0x06,0x01,0x01,0x01}, // 升级启动 se=1
	{211,0x07,0x01,0x01,0x02}, // 升级启动确认
	
};
#define SEC_APP_TYPE_NUM (sizeof(g_sec_app_type)/sizeof(g_sec_app_type[0]))



/*------------------------------ 函数声明 -------------------------------------
*/


/*------------------------------ 外部函数 -------------------------------------
外部函数供其它实体文件引用，必须仔细检查传入参数的合法性.
*/
int _sec_pack(u8 *buf,u8 *data,u16 len)
{
	int i;
	u8 cs;

	// 固定头
	buf[0] = 0xEB;
	buf[1] = (len>>8)&0XFF;
	buf[2] = (len)&0XFF;
	buf[3] = 0xEB;

	// 数据区
	if(data)
	{
		memcpy(buf+4,data,len);
	}

	// 校验和
	cs=0;
	buf += 4;
	for(i=0;i<len;i++)
	{			
		cs+=*buf++;
	}
	*buf++=cs;

	// 结束符
	*buf = 0xD7;

	return 0;
}


// 返回错误类型
int _sec_echo_error(u8 *buf,u16 errno)
{
	// 终端向主站返回密钥版本， 应用类型 0x1f
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = 0x1f; 			// 应用类型
	g_sec_out[7] = 0x00;	// 扩展区长度0
	g_sec_out[8] = 0x02;	// 扩展区长度1
	g_sec_out[9] = (BYTE)(errno>>8);	// 错误码
	g_sec_out[10] =(BYTE)(errno>>0);	//错误码
	_sec_pack(g_sec_out,NULL,7);
	return 0;
}


void  _sec_get_app_type(u8 ti,u8 cot,u8 se,u8 *at,u8 *jm ) 
{
	int i;
	// 获取规约应用类型
	for(i=0; i<SEC_APP_TYPE_NUM; i++)
	{
		if(ti != g_sec_app_type[i].ti)
		{
			continue;
		}
		if(g_sec_app_type[i].cot &&  ((cot &0x3f)!= g_sec_app_type[i].cot))
		{
			continue;
		}
		if(se == g_sec_app_type[i].se)
		{
			break;
		}
	}
	if(i == SEC_APP_TYPE_NUM)
	{
		*at = 0;
		*jm = 1;	
	}
	else
	{
		*at = g_sec_app_type[i].at;
		*jm = g_sec_app_type[i].jm;
	}
}


// 网关对终端的认证请求， 应用类型 0x20
// 主站对终端的认证请求， 应用类型 0x50
// EB 0013 EB 0080 20 0008 XXXXXXXX CS D7
int _sec_msg_auth1(u8 at,u8 *buf)
{
	int len;
	u16 in_len;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 8)
	{
		return -1;
	}

	// 得到随机数签名
	len = esam_sign_random(buf+SEC_POS_EXT_DATA,in_len,g_sec_out+SEC_POS_EXT_DATA,SEC_DATA_LEN);
	if(len != 0x48)
	{
		return -2;
	}
	g_sec_out[SEC_POS_EXT_DATA+0x48]= 0x06; // 目前终端证书只有一个，签名密钥标识默认为 06。

	// 保存主站随机数,后半部为随机数的按位取反
	if(at == 0x50)
	{
		int i;
		memcpy(g_sec_zz_random,buf+SEC_POS_EXT_DATA,SEC_RANDOM_LEN);
		for(i=0;i<SEC_RANDOM_LEN;i++)
		{
			g_sec_zz_random[SEC_RANDOM_LEN+i] = ~g_sec_zz_random[i];
		}

		{
			int sz_len;
			char sz[128];
			sprintf(sz,"主站随机数原始:");
			sz_len = strlen(sz);
			for(i=0;i<SEC_RANDOM_LEN*2;i++)
			{
				sprintf(sz+sz_len,"%02x ",g_sec_zz_random[i]);
				sz_len += 3;
			}
			sprintf(sz+sz_len,"\r\n");
			rt_printf(sz);
		}
	}
	
	// 终端认证确认并请求网关认证， 应用类型 0x21	
	// 终端认证确认并请求主站认证， 应用类型 0x51
	// EB 0013 EB 0010 21 0049 XXXXXXXX+SignResult+01 CS D7
	len += 1;
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

}

// 网关对终端认证请求的响应， 应用类型 0x22
// 主站对终端认证请求的响应， 应用类型 0x52
int _sec_msg_auth2(u8 at,u8 *buf,int *retvalue)
{
	int len,ret;
	u16 in_len,esam_errno=SEC_ERR_OK;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0x41)
	{
		esam_errno = SEC_ERR_AUTH;
		ret = -1;
		goto RET;
	}

	// 签名验证
	len = esam_sign_verify_zz(buf[SEC_POS_EXT_DATA+in_len-1],buf+SEC_POS_EXT_DATA,in_len-1);
	if(len != 0)
	{
		esam_errno = SEC_ERR_AUTH;
		ret = -2;
		goto RET;
	}

	ret = 0;
	esam_errno = SEC_ERR_OK;
RET:

	if(esam_errno == SEC_ERR_OK)
	{
		*retvalue = 0;
	}
	else
	{
		*retvalue = -1;
	}
	g_sec_out[SEC_POS_EXT_DATA]		= (esam_errno>>8)&0xff; // 返回错误码
	g_sec_out[SEC_POS_EXT_DATA+1]	= (esam_errno>>0)&0xff; // 返回错误码

	// 终端向网关返回认证结果， 应用类型 0x23
	// 终端向主站返回认证结果， 应用类型 0x53
	len = 2;
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

}

// 运维身份认证交互流程
// 证书管理工具发起认证请求， 应用类型 0x30
int _sec_msg_yw_auth1(u8 at,u8 *buf,int *retvalue)
{
	int len,ret,i;
	u16 in_len;
	u8 idx,frm,frm_sum;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len < 0x0b) //11+N
	{
		ret = SEC_ERR_FRAME;
		goto RET;
	}

	idx = buf[SEC_POS_EXT_DATA];
	if(idx != 7) // 证书管理工具的证书标识： 7；
	{
		ret = SEC_ERR_FRAME;
		goto RET;
	}
	
	frm_sum = buf[SEC_POS_EXT_DATA+1];
	frm = buf[SEC_POS_EXT_DATA+2];

	// 如果是首帧，初始化
	if(frm == 1)
	{
		g_cer_idx = idx;
		g_cer_frm = 0;
		g_cer_len = 0;
		memcpy(g_sec_yw_id,&buf[SEC_POS_EXT_DATA+in_len-8],SEC_YW_ID_LEN);
	}

	// 检查工具ID
	if(memcmp(g_sec_yw_id,&buf[SEC_POS_EXT_DATA+in_len-8],SEC_YW_ID_LEN) != 0)
	{
		ret = SEC_ERR_FRAME;
		goto RET;
	}

	// 检查下载过程的合法性,帧序号从 1 开始计算
	if((frm != g_cer_frm+1) || (idx != g_cer_idx) || (frm > frm_sum))
	{
		ret = SEC_ERR_FRAME;
		goto RET;
	}
	
	// 更新证书内容
	in_len -= 11;
	memcpy(&g_cer_buf[g_cer_len],&buf[SEC_POS_EXT_DATA+3],in_len);
	g_cer_len += in_len;
	g_cer_frm = frm;

	// 如果是最后一帧，更新证书
	if(frm != frm_sum)
	{
		ret = SEC_ERR_OK;
		goto RET;
	}
		
	// 验证证书管理工具证书的有效性
	g_cer_len = esam_yw_cer_verify(g_cer_buf,g_cer_len);
	if(g_cer_len < 0)
	{
		ret = SEC_ERR_FRAME;
		goto RET;
	}

	// 取终端随机数
	len = esam_get_random(g_sec_out+SEC_POS_EXT_DATA,SEC_DATA_LEN);
	if(len != SEC_RANDOM_LEN)
	{
		ret = SEC_ERR_FRAME;
		goto RET;
	}

	// 保存运维随机数
	memcpy(g_sec_yw_random,g_sec_out+SEC_POS_EXT_DATA,SEC_RANDOM_LEN);
	memcpy(g_sec_yw_random+SEC_RANDOM_LEN,g_sec_yw_random,SEC_RANDOM_LEN);
	for(i=0;i<SEC_RANDOM_LEN;i++)
	{
		g_sec_yw_random[SEC_RANDOM_LEN*2+i] = ~g_sec_yw_random[i];
	}

	// 终端响应证书管理工具的认证请求， 应用类型 0x31
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	*retvalue = 0;
	return SEC_FRAME_OK_EXT;

// 分帧数据传输结果返回，应用类型 0x45	
RET:
	if(ret == SEC_ERR_OK)
	{
		*retvalue = 0;
	}
	else
	{
		*retvalue = -1;
	}
	g_sec_out[SEC_POS_EXT_DATA]		= (ret>>8)&0xff; // 返回错误码
	g_sec_out[SEC_POS_EXT_DATA+1]	= (ret>>0)&0xff; // 返回错误码
	len = 2;

	//终端向证书管理工具返回认证结果， 应用类型 0x33
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = 0x45; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;
}


// 证书管理工具对终端认证请求的响应， 应用类型 0x32
int _sec_msg_yw_auth2(u8 at,u8 *buf,int *retvalue)
{
	int len,ret;
	u16 in_len,esam_errno=SEC_ERR_OK;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0x40)
	{
		esam_errno = SEC_ERR_AUTH;
		ret = -1;
		goto RET;
	}

	// 运维工具签名，终端验证正确性
	len = esam_yw_sign_verify( &buf[SEC_POS_EXT_DATA],in_len);
	if(len< 0)
	{
		esam_errno = SEC_ERR_AUTH;
		ret = -2;
		goto RET;
	}

	ret = 0;
	esam_errno = SEC_ERR_OK;

RET:
	if(esam_errno == SEC_ERR_OK)
	{
		*retvalue = 0;
	}
	else
	{
		*retvalue = -1;
	}
	g_sec_out[SEC_POS_EXT_DATA]		= (esam_errno>>8)&0xff; // 返回错误码
	g_sec_out[SEC_POS_EXT_DATA+1]	= (esam_errno>>0)&0xff; // 返回错误码
	len = 2;

	//终端向证书管理工具返回认证结果， 应用类型 0x33
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;
}


// 主站获取终端芯片序列号， 应用类型 0x54
// 获取终端内置安全芯片序列号， 应用类型 0x38
int _sec_msg_sn(u8 at,u8 *buf)
{
	int len;
	u16 in_len;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0x00)
	{
		return -1;
	}

	// 得到芯片序列号
	len = esam_get_sn(g_sec_out+SEC_POS_EXT_DATA,SEC_DATA_LEN);
	if(len != 8)
	{
		return -2;
	}

	// 终端返回内置芯片的序列号， 应用类型 0x55
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

}


// 获取终端序列号， 应用类型 0x36
int _sec_msg_sn_zt(u8 at,u8 *buf)
{
	int len;
	u16 in_len;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0x00)
	{
		return -1;
	}

	// 得到终端序列号
	len = set_get_fixed_arg(FIXED_SET_ID,g_sec_out+SEC_POS_EXT_DATA,SEC_DATA_LEN);
	if(len != 0)
	{
		return -2;
	}
	len = 24;

	// 终端返回内置芯片的序列号， 应用类型 0x55
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

}



// 主站获取终端密钥版本， 应用类型 0x60
// 运维获取终端密钥版本， 应用类型 0x34
int _sec_msg_version(u8 at,u8 *buf)
{
	int len;
	u16 in_len;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0x00)
	{
		return -2;
	}

	// 得到芯片密钥版本
	len = esam_get_version(g_sec_out+SEC_POS_EXT_DATA,SEC_DATA_LEN);
	if(len != 1)
	{
		return -3;
	}
	
	// 取终端随机数
	len = esam_get_random(g_sec_out+SEC_POS_EXT_DATA+1,SEC_DATA_LEN);
	if(len != 8)
	{
		return -4;
	}

	// 终端向主站返回密钥版本， 应用类型 0x61
	len += 1;
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

}

// TODO: 需要加密上送
// 获取终端安全芯片公钥， 应用类型 0x3A
int _sec_msg_pubkey(u8 at,u8 *buf)
{
	int len;
	u16 in_len;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0x00)
	{
		return -1;
	}

	// 得到芯片公钥
	len = esam_yw_get_pubkey(g_sec_out+SEC_POS_EXT_DATA,SEC_DATA_LEN);
	if(len != 64)
	{
		return -2;
	}

	// 终端提取内置安全芯片的公钥，使用现场运维上行数据保护密钥对公
	// 钥进行加密，并将加密报文发送给证书管理工具， 应用类型 0x3B
	// 延后使用统一加密流程
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_ENCRYPT;

}


// 主站执行远程密钥更新， 应用类型 0x62
// 主站执行远程密钥恢复， 应用类型 0x64
int _sec_msg_key_update(u8 at,u8 *buf,int chn)
{
	int len,ret;
	u16 in_len,esam_errno=SEC_ERR_OK ;

	if(g_sec_lnk[chn].status != SEC_ST_BUSINESS)
	{
		esam_errno = SEC_ERR_KEY_UPDATE;
		ret = -1;
		goto RET;
	}
	
	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0xf6)
	{
		esam_errno = SEC_ERR_KEY_UPDATE;
		ret = -1;
		goto RET;
	}

	// 检查密钥版本
	// 如果更新密钥，密钥版本必定大于0
	// 如果恢复密钥，密钥版本必定等于0
	if(at == 0x62 && buf[SEC_POS_EXT_DATA] == 0)
	{
		esam_errno = SEC_ERR_KEY_UPDATE;
		ret = -2;
		goto RET;
	}
	if(at == 0x64 && buf[SEC_POS_EXT_DATA] != 0)
	{
		esam_errno = SEC_ERR_KEY_UPDATE;
		ret = -3;
		goto RET;
	}

	// 更新对称密钥
	len = esam_key_update(buf[SEC_POS_EXT_DATA+in_len-1],buf+SEC_POS_EXT_DATA,in_len-1);
	if(len != 0)
	{
		esam_errno = SEC_ERR_KEY_UPDATE;
		ret = -4;
		goto RET;
	}

	ret = 0;
RET:	
	g_sec_out[SEC_POS_EXT_DATA]		= (esam_errno>>8)&0xff; // 返回错误码
	g_sec_out[SEC_POS_EXT_DATA+1]	= (esam_errno>>0)&0xff; // 返回错误码

	// 终端向主站返回密钥更新结果， 应用类型 0x63
	// 终端向主站返回密钥恢复结果， 应用类型 0x65
	len = 2;
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

}


// 证书管理工具恢复终端密钥， 应用类型 0x46
int _sec_msg_key_restore_yw(u8 at,u8 *buf,int chn)
{
	int len,ret;
	u16 in_len,esam_errno=SEC_ERR_OK;

	if(g_sec_lnk[chn].status != SEC_ST_BUSINESS)
	{
		esam_errno = SEC_ERR_KEY_RESTORE;
		ret = -1;
		goto RET;
	}

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0xb9)
	{
		esam_errno = SEC_ERR_KEY_RESTORE;
		ret = -1;
		goto RET;
	}

	// 恢复对称密钥
	len = esam_yw_key_restore(buf+SEC_POS_EXT_DATA,in_len);
	if(len < 0)
	{
		esam_errno = SEC_ERR_KEY_RESTORE;
		ret = -2;
		goto RET;
	}

	ret = 0;

RET:	
	g_sec_out[SEC_POS_EXT_DATA]		= (esam_errno>>8)&0xff; // 返回错误码
	g_sec_out[SEC_POS_EXT_DATA+1]	= (esam_errno>>0)&0xff; // 返回错误码

	// 终端向证书管理工具返回密钥恢复结果， 应用类型 0x47
	len = 2;
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

}


// 主站向终端发起 CA 证书/主站证书/网关证书远程更新， 应用类型0x70
// 主站向终端发起远程下载终端证书， 应用类型 0x72
// 证书管理工具将配电应用 CA 证书、主站证书、网关证书、终端证书导入终端， 应用类型 0x3E
int _sec_msg_cer_update(u8 at,u8 *buf,int chn)
{
	int len,ret=0;
	u16 in_len,esam_errno=SEC_ERR_OK;
	u8 idx,frm,frm_sum;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len < 0x03)
	{
		esam_errno = (at == 0x3e) ? SEC_ERR_CER_IN : SEC_ERR_CER_UPDATE;
		ret = -1;
		goto RET;
	}

	// 得到证书标识，最大为6
	idx = buf[SEC_POS_EXT_DATA];
	if(idx > 6)
	{
		esam_errno = (at == 0x3e) ? SEC_ERR_CER_IN : SEC_ERR_CER_UPDATE;
		ret = -1;
		goto RET;
	}

	// 运维更新终端证书需要权限，更新其它证书不要权限
	if(at == 0x3e && (idx >= 6) && (g_sec_lnk[chn].status != SEC_ST_BUSINESS))	
	{
		esam_errno = SEC_ERR_CER_IN;
		ret = -1;
		goto RET;
	}

	// 主站更新证书需要权限
	if((at == 0x70 || at == 0x72 ) && (g_sec_lnk[chn].status != SEC_ST_BUSINESS))	
	{
		esam_errno = SEC_ERR_CER_UPDATE;
		ret = -1;
		goto RET;
	}

	frm_sum = buf[SEC_POS_EXT_DATA+1];
	frm = buf[SEC_POS_EXT_DATA+2];

	// 如果是首帧，初始化
	if(frm == 1)
	{
		g_cer_idx = idx;
		g_cer_frm = 0;
		g_cer_len = 0;
	}

	// 检查下载过程的合法性
	if((frm != g_cer_frm+1) || (idx != g_cer_idx) || (frm > frm_sum))
	{
		esam_errno = SEC_ERR_FRAME;
		ret = -3;
		if(at == 0x3e)
		{
			at = 0x44; // 加一变成0x45,分帧数据传输结果返回
		}
		goto RET;
	}
	
	// 更新证书内容
	in_len -= 3;
	memcpy(&g_cer_buf[g_cer_len],&buf[SEC_POS_EXT_DATA+3],in_len);
	g_cer_len += in_len;
	g_cer_frm = frm;

	// 如果是主站更新，直接返回。如果运维工具更新，返回分帧数据传输结果
	if(frm != frm_sum)
	{
		if(at != 0x3e)
		{
			return SEC_FRAME_OK;
		}
		
		esam_errno = SEC_ERR_OK;
		ret = 0;
		at = 0x44; // 加一变成0x45,分帧数据传输结果返回
		goto RET;
	}
	
	// 如果是维护工具更新证书，全是明文
	 if(at == 0x3e)
	{
		if(g_cer_idx < 6)
		{
			ret = esam_cer_zz_update(g_cer_idx,g_cer_buf,g_cer_len);
		}
		else
		{
			ret = esam_cer_zd_update(g_cer_buf,g_cer_len);
		}
		if(ret < 0)
		{
			esam_errno = SEC_ERR_CER_IN;
			ret = -4;
			goto RET;
		}
		
		esam_errno = SEC_ERR_OK;
	}
	// 如果是主站更新终端证书，是明文，直接写入
	else if(at == 0x72)
	{
		len = esam_cer_zd_update(g_cer_buf,g_cer_len);
		if(len < 0)
		{
			esam_errno = SEC_ERR_CER_UPDATE;
			ret = -4;
			goto RET;
		}
	
		esam_errno = SEC_ERR_OK;
	}
	// 如果是主站更新证书，全是密文0x70
	else
	{
		// 以下是主站端证书，解密后再写入
		// 先对称解密
		// [CerID:1,Cer:N,Date:6,Scer:64,asKID:1,MAC:4]
		// in0:CerID+Cer+Date+Scer+asKID+MAC
		// out:CerID+Cer+Date+Scer+asKID
		len = 0;
		memcpy(g_sec_in+len,g_sec_zz_random,SEC_RANDOM_LEN*2); // IVData，随机数组合，16字节
		len += SEC_RANDOM_LEN*2;
		memcpy(g_sec_in+len,g_cer_buf,g_cer_len);				// enData，需解密的数据
		len += g_cer_len;
		len = esam_decrypt(g_sec_in,len,g_sec_out,SEC_BUF_SIZE);
		if(len < 0)
		{
			esam_errno = SEC_ERR_CER_UPDATE;
			ret = -5;
			goto RET;
		}

		// 验签
		// in0:asKID
		// in1:CerID+Cer+Date+Scer 
		len--;
		ret = esam_sign_verify_yk(g_sec_out[len],g_sec_out,len);
		if(ret < 0)
		{
			esam_errno = SEC_ERR_CER_UPDATE;
			ret = -6;
			goto RET;
		}

		// 更新证书,只要证书内容，去掉其它所有数据
		//  in0:CerID
		//  in1:Cer
		len -= 1 + 6 + 64;
		len = esam_cer_zz_update(g_sec_out[0],g_sec_out+1,len);
		if(len < 0)
		{
			esam_errno = SEC_ERR_CER_UPDATE;
			ret = -7;
			goto RET;
		}

		ret = 0;
		esam_errno = SEC_ERR_OK;
	}
	
RET:
	g_sec_out[SEC_POS_EXT_DATA]		= (esam_errno>>8)&0xff; // 返回错误码
	g_sec_out[SEC_POS_EXT_DATA+1]	= (esam_errno>>0)&0xff; // 返回错误码

	// 终端向主站返回证书远程更新结果， 应用类型 0x71
	// 终端向主站返回证书远程下载结果， 应用类型 0x73
	// 终端返回证书导入结果，应用类型 0x3F,运维
	// 分帧数据传输结果返回，应用类型 0x45,运维
	len = 2;
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

}


// 主站提取终端证书， 应用类型 0x74
// 证书管理工具导出终端公钥证书， 应用类型 0x42
int _sec_msg_cer_get(u8 at,u8 *buf,u8 *out,int chn)
{
	int len,frame_num,frame_len;
	u16 in_len;

	if(g_sec_lnk[chn].status != SEC_ST_BUSINESS)
	{
		// return -1;
	}

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0x00)
	{
		return -1;
	}

	// 提取证书
	g_cer_len = esam_cer_zd_get(g_cer_buf,SEC_BUF_SIZE);
	if(g_cer_len < 0)
	{
		return -2;
	}
	if(g_cer_len > SEC_DATA_LEN)
	{
		return -3;
	}

	g_cer_at = at + 1;
	g_cer_idx = 6;
	g_cer_frm = 1;

	frame_num = (g_cer_len + SEC_CER_FRAME_LEN -1)/SEC_CER_FRAME_LEN;
	frame_len = g_cer_len > SEC_CER_FRAME_LEN ? SEC_CER_FRAME_LEN : g_cer_len;
	out[SEC_POS_EXT_DATA]		= g_cer_idx;// 证书标识
	out[SEC_POS_EXT_DATA+1]	= frame_num;// 总帧数
	out[SEC_POS_EXT_DATA+2]	= g_cer_frm;// 当前帧序号
	memcpy(&out[SEC_POS_EXT_DATA+3],g_cer_buf,frame_len);

	// 终端向主站返回证书， 应用类型 0x77
	len = frame_len+3;
	out[4] = buf[4]; 			// 报文类型0
	out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	out[6] = g_cer_at; 		// 应用类型
	out[7] = (len>>8)&0xff;	// 扩展区长度0
	out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(out,NULL,len+5);

	return SEC_FRAME_OK_EXT;
}


// 证书管理工具导出终端公钥证书应答， 应用类型 0x45
int _sec_msg_cer_echo(u8 at,u8 *buf,u8 *out)
{
	int len,frame_num,frame_len;
	u16 in_len,msg_ret;

	// 如果是主站获取终端证书，直接连续发送
	if(at == 0x74)
	{
		g_cer_frm++;
	}
	else
	{
		// 检查长度
		in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
		if(in_len != 0x02)
		{
			return -1;
		}

		// 检查返回结果，如果正常传下一帧，否则重传前一帧。
		msg_ret = (buf[SEC_POS_EXT_LEN+2]<<8) | buf[SEC_POS_EXT_LEN+3];
		if(msg_ret == SEC_ERR_OK)
		{
			g_cer_frm++;
		}
	}

	// 检查当前帧
	frame_num = (g_cer_len + SEC_CER_FRAME_LEN -1)/SEC_CER_FRAME_LEN;
	if(g_cer_frm > frame_num)
	{
		return -2;
	
	}
	
	frame_len = g_cer_len - (g_cer_frm-1)*SEC_CER_FRAME_LEN;
	frame_len = frame_len > SEC_CER_FRAME_LEN ? SEC_CER_FRAME_LEN : frame_len;
	out[SEC_POS_EXT_DATA]		= g_cer_idx;// 证书标识
	out[SEC_POS_EXT_DATA+1]	= frame_num;// 总帧数
	out[SEC_POS_EXT_DATA+2]	= g_cer_frm;// 当前帧序号
	memcpy(&out[SEC_POS_EXT_DATA+3],g_cer_buf+(g_cer_frm-1)*SEC_CER_FRAME_LEN,frame_len);

	// 终端向主站返回证书， 应用类型 0x77
	len = frame_len+3;
	out[4] = buf[4]; 			// 报文类型0
	out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	out[6] = g_cer_at; 		// 应用类型
	out[7] = (len>>8)&0xff;	// 扩展区长度0
	out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(out,NULL,len+5);

	return SEC_FRAME_OK_EXT;
}




// 主站向终端返回证书提取结果， 应用类型 0x76
// 证书管理工具向终端返回证书导出结果，应用类型 0x44
int _sec_msg_cer_get_result(u8 at,u8 *buf)
{
	u16 in_len,err;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0x02)
	{
		return -1;
	}
	err = (buf[SEC_POS_EXT_DATA]<<8) | buf[SEC_POS_EXT_DATA+1];

	rt_printf("终端证书提取结果:at=0x%02x,err=0x%04x.\r\n",at,err);

	return 0;
}


//  终端初始证书回写， 应用类型 0x40
int _sec_msg_cer_zd_restore(u8 at,u8 *buf)
{
	int len,ret=0;
	u16 in_len,cer_len,esam_errno=SEC_ERR_OK;

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len != 0x00)
	{
		esam_errno = SEC_ERR_CER_IN;
		ret = -1;
		goto RET;
	}

	// 得到证书长度
	len = esam_cer_zd_test_get_len((u8 *)&cer_len,2);
	if(len != 2)
	{
		esam_errno = SEC_ERR_CER_IN;
		ret = -2;
		goto RET;
	}

	//得到证书
	g_cer_len = esam_cer_zd_test_get(cer_len,g_cer_buf,SEC_BUF_SIZE);
	if(g_cer_len < 0)
	{
		esam_errno = SEC_ERR_CER_IN;
		ret = -3;
		goto RET;
	}
	if(g_cer_len > SEC_DATA_LEN)
	{
		esam_errno = SEC_ERR_CER_IN;
		ret = -4;
		goto RET;
	}

	// 回写证书
	len = esam_cer_zd_update(g_cer_buf,g_cer_len);
	if(len < 0)
	{
		esam_errno = SEC_ERR_CER_IN;
		ret = -5;
		goto RET;
	}

	esam_errno = SEC_ERR_OK;

RET:
	g_sec_out[SEC_POS_EXT_DATA]		= (esam_errno>>8)&0xff; // 返回错误码
	g_sec_out[SEC_POS_EXT_DATA+1]	= (esam_errno>>0)&0xff; // 返回错误码

	// 终端返回初始证书回写结果， 应用类型 0x41
	len = 2;
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

}


// 证书管理工具将生成的证书请求文件发给终端， 应用类型 0x3C
int _sec_msg_cer_sign(u8 at,u8 *buf,int chn)
{
	int len;
	u16 in_len;
	u8 frm,frm_sum;
	int ret=0;

	if(g_sec_lnk[chn].status != SEC_ST_BUSINESS)
	{
		// TODO:不知道返回啥
		return -1;
	}

	// 检查长度
	in_len = (buf[SEC_POS_EXT_LEN]<<8) | buf[SEC_POS_EXT_LEN+1];
	if(in_len < 0x02) //2+N
	{
		return -1;
	}

	frm_sum = buf[SEC_POS_EXT_DATA];
	frm 	= buf[SEC_POS_EXT_DATA+1];

	// 如果是首帧，初始化
	if(frm == 1)
	{
		g_cer_idx = -1;
		g_cer_frm = 0;
		g_cer_len = 0;
	}

	// 检查下载过程的合法性,帧序号从 1 开始计算
	if((frm != g_cer_frm+1) || (frm > frm_sum))
	{
		return -2;
	}
	
	// 更新证书内容
	in_len -= 2;
	memcpy(&g_cer_buf[g_cer_len],&buf[SEC_POS_EXT_DATA+2],in_len);
	g_cer_len += in_len;
	g_cer_frm = frm;

	// 如果不是最后一帧，直接返回
	if(frm != frm_sum)
	{
		ret = SEC_ERR_OK;
		goto RET;
	}
		
	// 用私钥签名
	len = esam_yw_sign(g_cer_buf,g_cer_len,g_sec_out+SEC_POS_EXT_DATA,SEC_BUF_SIZE);
	if(len < 0)
	{
		return -3;
	}

	// 向证书管理工具返回签名结果， 应用类型 0x3D
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = at+1; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

// 分帧数据传输结果返回，应用类型 0x45	
RET:
	g_sec_out[SEC_POS_EXT_DATA]		= (ret>>8)&0xff; // 返回错误码
	g_sec_out[SEC_POS_EXT_DATA+1]	= (ret>>0)&0xff; // 返回错误码
	len = 2;

	//终端向证书管理工具返回认证结果， 应用类型 0x33
	g_sec_out[4] = buf[4]; 			// 报文类型0
	g_sec_out[5] = buf[5]&SEC_MSG_OBJECT_MASK;// 报文类型1
	g_sec_out[6] = 0x45; 			// 应用类型
	g_sec_out[7] = (len>>8)&0xff;	// 扩展区长度0
	g_sec_out[8] = (len>>0)&0xff;	// 扩展区长度1

	_sec_pack(g_sec_out,NULL,len+5);

	return SEC_FRAME_OK_EXT;

	
}


static const	u8 g_msg_tool[]=  // 打开维护软件端口的特殊报文
{0xEB,0x00,0x0A,0xEB,0x00,0x01,0x00,0x06,0x68,0x04,0x03,0x55,0xaa,0xff,0x74,0xD7};
int _sec_msg_app(int chn,u8 *buf,bool b101)
{
	int ret,len;
	u16 i,msg_len;
	u8 at=0,mt;
	
	// 判断是否符合业务流程 即 是否通过了认证
	if(g_sec_lnk[chn].status != SEC_ST_BUSINESS && memcmp(buf,g_msg_tool,sizeof(g_msg_tool)))
	{
		ret= SEC_ERR_PROC;
		goto RET;
	}

	// 报文类型和应用类型
	mt = buf[SEC_POS_TYPE];
	at = buf[SEC_POS_APP];

	// 得到规约报文数据，数据区第一个字节是规约报文长度
	if(at!=8)
	{
		len = buf[SEC_POS_DATA];
		if(len)memcpy(g_sec_in,&buf[SEC_POS_DATA+1],len);
		msg_len = len;	
	}
	else
	{
		msg_len=0;
	}
	// 验证签名
	if(at==0x01 || at==0x03 || at==0x05 || at==0x07)
	{
		// 得到信息安全区数据，安全区前2个字节为长度
		i = SEC_POS_DATA+1+len;
		len = (buf[i]<<8) | buf[i+1];
		memcpy(g_sec_in+msg_len,&buf[i+2],len);
		msg_len += len -1;  // -1为去掉asKID

		// 签名验证
		i += 2 + len - 1;  // askID的位置
		ret = esam_sign_verify_yk(buf[i],g_sec_in,msg_len);
		if(ret < 0)
		{
			ret= SEC_ERR_VERIFY;
			goto RET;
		}
	}

	// 判断指令时效
	if(at==0x04 || at==0x05 || at==0x06 || at== 0x07||at==0x08)
	{	
		u8 *pdat;
		struct rtc_time_t tm;
		struct timespec ts,tsnow;
		if(at==8)
		{
			pdat=&buf[SEC_POS_DATA+2];
		}
		else
		{
			len = buf[SEC_POS_DATA];
			pdat=&buf[SEC_POS_DATA+len+1+2];
		}
		tm.year	=pdat[0];
		tm.month	=pdat[1];
		tm.day	=pdat[2];
		tm.hour	=pdat[3];
		tm.min	=pdat[4];
		tm.ms	=pdat[5]*1000;

		//获取当前时间
		rtc_to_timespec(&tm,&ts);
		clk_time_get(&tsnow);
		if(abs(tsnow.tv_sec-ts.tv_sec)>tRunPara.dSM2Time)
		{
			ret= SEC_ERR_TIME;
			goto RET;
		}
	}

	//取随机数
	if(at==0x03 || at==0x06 || at== 0x07||at==0x08)
	{
		u8 *pdat;
		u8 tlen=0;
		if(at==8)
		{
			pdat=&buf[SEC_POS_DATA+2+6];
		}
		else
		{
			len = buf[SEC_POS_DATA];
			if(at==6||at==7)tlen=6;  // 时间6个字节
			pdat=&buf[SEC_POS_DATA+len+1+2+tlen];
		}
		for(i=0;i<SEC_RANDOM_LEN;i++)
		{
			if(g_sec_zd_random[i]!=pdat[i])
			{
				ret= SEC_ERR_RANDOM;  // 随机数验证错误 
				goto RET;
			}
		}		
	}		
	
	if(at==0x08) // 如果类型为8，直接对/tmp下的升级程序进行MD5验证
	{
		// 得到信息安全区数据，安全区前2个字节为长度
		i = SEC_POS_DATA;
		len = (buf[i]<<8) | buf[i+1];
		//memcpy(g_sec_md5_dat,&buf[i+2],len);
		ret=sec_md5_check(&buf[i+2],len);
		if(ret<0)
		{
			ret= SEC_ERR_VERIFY;  // 验证错误 
			goto RET;
		}
		g_sec_md5_ret=0;
		rt_printf("\r\n08报文md5校验成功");

		// 直接返回，且不需要后续处理
		return SEC_FRAME_OK;
	}
	else
	{
		// 返回明文
		len=buf[SEC_POS_DATA];
		memcpy(buf,g_sec_in,len);				
		// 判断报文类型是否符合业务要求规范
		{
			u8 ti,cot,se,jm,jm1,at1;
			iec_GetMsgInfo(buf,len,&ti,&cot,&se,b101);
			_sec_get_app_type(ti,cot,se, &at1,&jm1);	

			jm=(mt&SEC_MSG_ENCRYPT)?1:0;
			if(at!=at1)
			{
				ret=SEC_ERR_TYPE;
				goto RET;
			}
			if(jm!=jm1)
			{
				ret=SEC_ERR_WJM;
				goto RET;
			}
		}
		return SEC_FRAME_OK_APP;
	}
	
RET:
	if(at==0x08)
	{
		g_sec_md5_ret=ret;
		return SEC_FRAME_OK;  // 08报文，在收到程序升级结束后再应答
	}

	return ret;
}

int _sec_msg_ext(int chn,u8 *buf,bool b101)
{
	int ret;
	u8 at,mt,mt_obj;

	// 报文类型和应用类型
	mt = buf[SEC_POS_TYPE];
	at = buf[SEC_POS_APP];
	mt_obj = mt & SEC_MSG_OBJECT_MASK;

	ret = SEC_ERR_PROC;
	switch(at)
	{
	// 以下网关
	case 0x20: // 网关认证1
		ret = _sec_msg_auth1(at,buf);
		if(ret >= 0)
		{
			g_sec_lnk[chn].status = SEC_ST_AUTH_GETWAY;
			g_sec_lnk[chn].obj   = mt_obj;
		}
	break;
	
	case 0x22: // 网关认证2
		if(g_sec_lnk[chn].status == SEC_ST_AUTH_GETWAY)
		{
			int retvalue;
			
			ret = _sec_msg_auth2(at,buf,&retvalue);
			if(retvalue >= 0)
			{
				g_sec_lnk[chn].status = SEC_ST_AUTH1;
				g_sec_lnk[chn].obj   = SEC_MSG_OBJECT_ZZ;
				rt_printf_time("通道%d网关认证通过.\r\n",chn);
			}
			else
			{
				g_sec_lnk[chn].status = SEC_ST_IDLE;
			}
		}
	break;

	//以下开始运维
	case 0x30: // 证书管理工具发起认证请求， 应用类型 0x30
	{
		int retvalue;
		
		ret = _sec_msg_yw_auth1(at,buf,&retvalue);
		if(retvalue >= 0)
		{
			g_sec_lnk[chn].status = SEC_ST_AUTH2;
			g_sec_lnk[chn].obj   = mt_obj;
		}
		else
		{
			g_sec_lnk[chn].status = SEC_ST_IDLE;
		}
	}
	break;
	
	case 0x32: // 证书管理工具对终端认证请求的响应， 应用类型 0x32
		if(g_sec_lnk[chn].status == SEC_ST_AUTH2)
		{
			int retvalue;
			ret = _sec_msg_yw_auth2(at,buf,&retvalue);
			if(retvalue >= 0)
			{
				g_sec_lnk[chn].status = SEC_ST_BUSINESS;
				rt_printf_time("通道%d运维认证通过.\r\n",chn);
			}
			else
			{
				g_sec_lnk[chn].status = SEC_ST_IDLE;
			}
		}

	break;

	case 0x34: // 获取终端密钥版本， 应用类型 0x34
		if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_version(at,buf);
		}
	break;
	
	case 0x36: // 获取终端序列号， 应用类型 0x36
		if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_sn_zt(at,buf);
		}
	break;
	
	case 0x38: // 获取终端内置安全芯片序列号， 应用类型 0x38
		if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_sn(at,buf);
		}
	break;
	
	case 0x3a: // 获取终端安全芯片公钥， 应用类型 0x3A
		if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_pubkey(at,buf);
		}
	break;

	case 0x3c: // 对证书请求文件进行签名， 应用类型 0x3C
		//if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_cer_sign(at,buf,chn);
		}
	break;
	
	case 0x3e: // 将证书导入终端， 应用类型 0x3E
	{
		//u8 idx;
		//idx = buf[SEC_POS_EXT_DATA];
		
		// 证书导入导出时不需要进行身份认证,终端证书(idx==6)导入导出时需要认证
		//if(idx < 6 || g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_cer_update(at,buf,chn);
		}
	}
	break;
	
	case 0x40: // 终端初始证书回写， 应用类型 0x40
		// if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_cer_zd_restore(at,buf);
		}
	break;

	case 0x42: // 证书管理工具导出终端公钥证书， 应用类型 0x42
		// 证书导入导出时不需要进行身份认证,终端证书(idx==6)导入导出时需要认证
		// if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_cer_get(at,buf,g_sec_out,chn);
		}
	break;
	case 0x44: // 证书管理工具向终端返回证书导出结果，应用类型 0x44
		// 证书导入导出时不需要进行身份认证
		// if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_cer_get_result(at,buf);
			
			// 直接返回，不需要后续处理
			return SEC_FRAME_OK;
		}
	break;
	case 0x45: // 维护工具对分帧的应答，不处理
		// 证书导入导出时不需要进行身份认证
		// if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_cer_echo(at,buf,g_sec_out);
		}
	break;
	
	case 0x46: // 证书管理工具恢复终端密钥， 应用类型 0x46
		// if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_key_restore_yw(at,buf,chn);
		}
	break;
	
	//case 0x48: // 证书管理工具向终端发送配电数据，应用类型 0x48
	//break;

	// 以下开始主站
	case 0x50: // 主站认证1
		if(g_sec_lnk[chn].status >= SEC_ST_AUTH1 || b101)  //江西测试，101不需要网关认证
		//if(g_sec_lnk[chn].status >= SEC_ST_AUTH1) // 据最新消息，101需要网关认证
		{
			ret = _sec_msg_auth1(at,buf);
			if(ret >= 0)
			{
				g_sec_lnk[chn].status = SEC_ST_AUTH2;
			}
			else
			{
				g_sec_lnk[chn].status = SEC_ST_AUTH1;
				rt_printf_time("通道%d认证状态退出（认证失败）.\r\n",chn);
			}
		}
	break;
	
	case 0x52: // 主站认证2
		if(g_sec_lnk[chn].status == SEC_ST_AUTH2)
		{
			int retvalue;
			ret = _sec_msg_auth2(at,buf,&retvalue);
			if(retvalue >= 0)
			{
				g_sec_lnk[chn].status = SEC_ST_BUSINESS;
				rt_printf_time("通道%d主站认证通过.\r\n",chn);
			}
			else
			{
				g_sec_lnk[chn].status = SEC_ST_AUTH1;
				rt_printf_time("通道%d认证状态退出（认证失败）.\r\n",chn);
			}
		}
	break;
	
	case 0x54: // 获取序列号ID
		if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_sn(at,buf);
		}
	break;

	case 0x60: // 得到密钥版本
		if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_version(at,buf);
		}
	break;
	
	case 0x62: // 主站远程密钥更新
		//if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_key_update(at,buf,chn);
		}
	break;
	
	case 0x64: // 主站远程密钥恢复
		//if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_key_update(at,buf,chn);
		}
	break;

	case 0x70: // 主站向终端发起 CA 证书/主站证书/网关证书远程更新， 应用类型0x70
		//if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_cer_update(at,buf,chn);
		}
	break;
	
	case 0x72: // 主站向终端发起远程下载终端证书， 应用类型 0x72
		//if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_cer_update(at,buf,chn);
		}
	break;
	
	case 0x74: //  主站提取终端证书， 应用类型 0x74
		if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			u16 ext_len;
			u8 *out;

			// 得到证书第一帧
			ext_len = 0;
			out = g_sec_out+ext_len+2;
			ret = _sec_msg_cer_get(at,buf,out,chn);
			if(ret < 0)
			{
				break;
			}

			// 取后续证书，注意buf不能溢出,目前判断不严格，主要是提醒用
			do
			{
				ext_len += (out[1]<<8) + out[2] + 6;
				if(ext_len > SEC_DATA_LEN)
				{
					rt_printf("证书太长:ext_len=%d.\r\n",ext_len);
					break;
				}
				out = g_sec_out+ext_len+2;
				ret = _sec_msg_cer_echo(at,buf,out);
			}while(ret > 0);

			g_sec_out[0] = ext_len >> 8;
			g_sec_out[1] = ext_len & 0xff;
			ret = SEC_FRAME_OK_MULTI;
		}
	break;
	
	case 0x76: // 主站向终端返回证书提取结果， 应用类型 0x76
		if(g_sec_lnk[chn].status == SEC_ST_BUSINESS)
		{
			ret = _sec_msg_cer_get_result(at,buf);
			// 直接返回，不需要后续处理
			return SEC_FRAME_OK;
		}
	break;

	default:
		rt_printf("未实现的应用类型:at=0x%02x。\r\n",at);
		return -1;	
	}

	// 如果需要，加密
	if(ret == SEC_FRAME_OK_ENCRYPT)
	{
		int len;
		u16 msg_len;

		msg_len = (g_sec_out[1]<<8) | g_sec_out[2];
		msg_len -= 2;

		len = 0;
		memcpy(g_sec_in+len,g_sec_yw_id,SEC_YW_ID_LEN);
		len += SEC_YW_ID_LEN;
		memcpy(g_sec_in+len,g_sec_yw_random,sizeof(g_sec_yw_random));
		len += sizeof(g_sec_yw_random);
		memcpy(g_sec_in+len,g_sec_out+SEC_POS_APP,msg_len);
		len += msg_len;
		
		len = esam_yw_encrypt(g_sec_in,len,g_sec_out+SEC_POS_APP,SEC_DATA_LEN);
		if(len < 0)
		{
			return -111;
		}

		g_sec_out[5] |= SEC_MSG_ENCRYPT | SEC_MSG_KID_ZD;// 报文类型1
		_sec_pack(g_sec_out,NULL,len+2);

		ret = SEC_FRAME_OK_EXT;
	}
	else if(ret < 0)
	{
		ret -= 100;
	}

	return ret;
}


int sec_msg_deal(int chn,u8 *buf, int len,u8 *out,bool b101)
{
	int ret;
	u16 i,msg_len;
	u8 cs,at,mt,mt_obj;
	u8 *pdat=buf;
	
	// 检查buf
	if(buf == 0)
	{
		return -1;
	}

	// 得到检查长度
	msg_len = (buf[1]<<8) | buf[2];
	if((len != msg_len + 6) || (msg_len <3))
	{
		return -2;
	}

	// 检查首尾标识字符
	if(buf[0] != 0xeb || buf[3] != 0xeb || buf[len-1] != 0xd7)
	{
		return -3;
	}

	// 检查检验和
	cs=0;
	pdat += 4;
	for(i=0;i<msg_len;i++)
	{			
		cs+=*pdat++;
	}
	if(*pdat != cs)
	{
		return -4;
	}

	// 报文类型和应用类型
	mt = buf[SEC_POS_TYPE];
	at = 0; // 先初始化为0，保证解密失败后，会返回错误代码报文。
	mt_obj = mt & SEC_MSG_OBJECT_MASK;
	
	// 如果需要解密，解密
	if(mt&SEC_MSG_ENCRYPT)
	{
		// 主站对称解密
		if(((mt & SEC_MSG_OBJECT_MASK) == SEC_MSG_OBJECT_ZZ) && ((mt & SEC_MSG_KID_MASK) == SEC_MSG_KID_ZZ))  
		{
			len = 0;
			memcpy(g_sec_in+len,g_sec_zz_random,SEC_RANDOM_LEN*2); // IVData，随机数组合，16字节
			len += SEC_RANDOM_LEN*2;
			memcpy(g_sec_in+len,buf+SEC_POS_APP,msg_len-2);				// enData，需解密的数据
			len += msg_len-2;
			len = esam_decrypt(g_sec_in,len,g_sec_out,SEC_BUF_SIZE);
			if(len < 0)
			{
				{
					int sz_len;
					char sz[128];
					sprintf(sz,"主站随机数解密错误:esam_errno=%04x,len=%d.",g_esam_errno,len);
					sz_len = strlen(sz);
					for(i=0;i<SEC_RANDOM_LEN*2;i++)
					{
						sprintf(sz+sz_len,"%02x ",g_sec_zz_random[i]);
						sz_len += 3;
					}
					sprintf(sz+sz_len,"\r\n");
					rt_printf(sz);
				}
				ret= SEC_ERR_JM;
				goto RET;
			}
		}
		// 现场运维工具对称解密
		else if(((mt & SEC_MSG_OBJECT_MASK) == SEC_MSG_OBJECT_YW) && ((mt & SEC_MSG_KID_MASK) == SEC_MSG_KID_YW))
		{
			len = 0;
			memcpy(g_sec_in+len,g_sec_yw_id,SEC_YW_ID_LEN);			// ID：证书管理工具 ID，8 字节；
			len += SEC_YW_ID_LEN;
			memcpy(g_sec_in+len,g_sec_yw_random,SEC_RANDOM_LEN*3); // R1+IVData，随机数组合，24字节
			len += SEC_RANDOM_LEN*3;
			memcpy(g_sec_in+len,buf+SEC_POS_APP,msg_len-2);				// enData，需解密的数据
			len += msg_len-2;
   			len = esam_yw_decrypt(g_sec_in,len,g_sec_out,SEC_BUF_SIZE);
			if(len < 0)
			{
				ret= SEC_ERR_JM;
				goto RET;
			}
		}
		else
		{
			ret= SEC_ERR_UNKNOWN;
			goto RET;
		}

		// 将明文放入原始报文的位置，明文长度一定小于密文长度，所以可以直接copy
		memcpy(buf+SEC_POS_APP,g_sec_out,len);
	}

	// 得到应用类型，并检查合法性
	at = buf[SEC_POS_APP];
	if(	   (at >= 0x00 && at < 0x20 && mt_obj != SEC_MSG_OBJECT_ZZ) 
		|| (at >= 0x20 && at < 0x30 && mt_obj != SEC_MSG_OBJECT_WG)
		|| (at >= 0x30 && at < 0x50 && mt_obj != SEC_MSG_OBJECT_YW)
		|| (at >= 0x50 && at < 0x80 && mt_obj != SEC_MSG_OBJECT_ZZ))
	{
		ret= SEC_ERR_TYPE;
		goto RET;
	}

	// 如果报文的连接对象和通道连接对象不一样，
	// 且不是开始的网关认证报文或运维认证报文，则流程错误
	if( g_sec_lnk[chn].status && mt_obj != g_sec_lnk[chn].obj && at != 0x20 && at != 0x30)
	{
		ret= SEC_ERR_PROC;
		goto RET;
	}

	// 业务报文处理
	if(at < 0x20)
	{
		ret = _sec_msg_app(chn,buf,b101);
	}
	// 安全扩展报文处理
	else
	{
		ret = _sec_msg_ext(chn,buf,b101);
	}

RET:

	if(ret>SEC_ERR_OK) 
	{
		// 目前，如果出错，业务需返回错误报文；扩展没有固定错误报文，需自己处理。
		if(at < 0x20)
	//	if(1)
		{
			_sec_echo_error(buf,ret);
			ret = SEC_FRAME_OK_EXT;
		}
		else
		{
			ret = -ret;
		}
	}

	if(ret == SEC_FRAME_OK_EXT)  // 应答安全扩展应用类型报文
	{
		u16 msg_len;
		msg_len = (g_sec_out[1]<<8)+g_sec_out[2]+6;
		out[0] = msg_len >> 8;
		out[1] = msg_len & 0xff;
		memcpy(out+2,g_sec_out,msg_len);
	}
	else if(ret == SEC_FRAME_OK_MULTI)
	{
		u16 msg_len;
		msg_len = (g_sec_out[0]<<8)+g_sec_out[1] + 2;
		memcpy(out,g_sec_out,msg_len);
		ret = SEC_FRAME_OK_EXT;
	}
	else if(ret < 0)
	{
		ret -= 100;
	}
	
	return ret;
}


void  sec_recv_reset(iec_rbuf_t *pt,int bErr) 
{
	pt->sts = 0;
	pt->len = 0;
	pt->cnt = 0;

	if(bErr == 1)
	{
		s_stat_rx_errframe(pt->chn);//统计接收错误帧数
	}
	else if(bErr > 1)
	{
		s_stat_rx_err(pt->chn,1);//统计接收错误字节数
	}
}

int  sec_recv(iec_rbuf_t *pt,u8 c,u8 *out,bool b101) 
{
	pt->buf[pt->cnt++]=c;	
	s_stat_rx(pt->chn,1);
	
	switch(pt->sts)
	{
	case 0: // 首标识符1
		if( c == 0xEB)
		{
			pt->sts++;
			memset(&pt->buf[1],0,30);
			
			s_stat_rx_frame(pt->chn);//统计接收帧数
		}
		else
		{
			sec_recv_reset(pt,2);
		}
		break;
	case 1: // 长度
		if(pt->cnt == 3)
		{
			pt->len=(pt->buf[1]<<8) | pt->buf[2];
			pt->len += 4;
			pt->sts++;
			if((pt->len + 2) > IEC_RECV_BUF_SIZE)
			{
				rt_printf("接收缓冲太小(chn=%d,len=%d,size=%d)!\r\n",pt->chn,pt->len+2,IEC_RECV_BUF_SIZE);
				sec_recv_reset(pt,1);
			}
		}
		break;
	case 2: // 首标识符2
		if( c == 0xEB)
		{
			pt->sum = 0;
			pt->sts++;
		}
		else
		{
			sec_recv_reset(pt,1);
		}
		break;
	case 3: // 报文类型和数据域
		pt->sum += c;
		if(pt->cnt >= pt->len)	
		{
			pt->sts++;
		}
		break;
	case 4: // 校验和
		if( c == pt->sum)
	//	if(1)
		{
			pt->sts++;
		}
		else
		{
			rt_printf("sec_recv:checksum error!\r\n");
			sec_recv_reset(pt,1);
		}
		break;
	case 5: // 尾标识符
		if( c == 0xD7)
		{
			int ret;
			
			// 报文接受完毕
			// 接收到一帧普通报文：
			// 1、设置普通帧接收标志
			// 2、唤醒主循环
			ret=sec_msg_deal(pt->chn,pt->buf,pt->len+2,out,b101);
			if(ret >= 0)
			{
				g_sec_lnk[pt->chn].us0 = ustimer_get_origin();
			}
			else
			{
				rt_printf("sec_msg_deal:ret=%d.\r\n",ret);
			}
			
			sec_recv_reset(pt,0); 
			mainloop_wakeup();
			
			return ret;
		}
		else
		{
			sec_recv_reset(pt,1);
		}
		break;
	default:		
		sec_recv_reset(pt,1);
		break;
	}
	
	return 0;
}


int  sec_encrpt_iec(u8 ti,u8 cot,u8 se,u8 *in,u8 in_len,u8 **out) 
{
	int msg_len,len,ext_len,ext_idx;
	u8 at,jm;

	// 检查参数
	if(in == NULL || out == NULL)
	{
		return -1;
	}

	//得到报文应用类型和是否加密
	_sec_get_app_type(ti,cot,se, &at,&jm );	
	 
	// 开始组输入加密芯片的明文
	msg_len = 0;

	// 主站随机密钥组合，16字节
	if(jm)
	{
		memcpy(g_sec_in+msg_len,g_sec_zz_random,SEC_RANDOM_LEN*2);
		msg_len += SEC_RANDOM_LEN*2;
	}

	// 应用类型、应用数据长度、应用数据
	g_sec_in[msg_len++] = at;
	g_sec_in[msg_len++] = in_len;
	memcpy(g_sec_in+msg_len,in,in_len); 
	msg_len +=in_len;

	//扩展区长度,如信息安全扩展区为空，仍增加 2 字节的长度，内容为 00。
	ext_len	= 0;
	ext_idx = msg_len;
	msg_len += 2;
	
	// 扩展区时间
	if(at==0x04 || at==0x05 || at==0x06 || at== 0x07)
	{
		struct rtc_time_t tm;
		struct timespec ts;

		//获取当前时间
		clk_time_get(&ts);
		timespec_to_rtc(ts,&tm,0);
		g_sec_in[msg_len++]=tm.year;
		g_sec_in[msg_len++]=tm.month;
		g_sec_in[msg_len++]=tm.day;
		g_sec_in[msg_len++]=tm.hour;
		g_sec_in[msg_len++]=tm.min;
		g_sec_in[msg_len++]=tm.ms/1000;		

		ext_len += 6;
	}

	// 扩展区随机数
	if(at==0x02 || at==0x03 || at==0x06 || at== 0x07)
	{
		len = esam_get_random(g_sec_in+msg_len,SEC_RANDOM_LEN);
		if(len != SEC_RANDOM_LEN)
		{
			return -1;
		}

		// 程序远程升级交互流程，需保存启动时上送的随机数
		if(at==0x02)
		{
			memcpy(g_sec_zd_random,g_sec_in+msg_len,SEC_RANDOM_LEN);
		}
		msg_len += SEC_RANDOM_LEN;
		ext_len += SEC_RANDOM_LEN;
	}

	// 扩展区签名
	if(at==0x01 || at==0x03 || at==0x05 || at==0x07)
	{
		// 上行规约数据没有签名
		rt_printf("上行规约数据没有签名\r\n");
		return -2;		
	}

	// 修正扩展长度域
	g_sec_in[ext_idx++] = (ext_len >> 8) &0xff;
	g_sec_in[ext_idx++] = (ext_len >> 0) &0xff;

	// 加密
	if(jm)
	{

		len = esam_encrypt(g_sec_in,msg_len,g_sec_out+SEC_POS_APP,SEC_DATA_LEN);
		if(len < 0)
		{
			return -3;
		}
	}
	else
	{
		len = msg_len;
		memcpy(g_sec_out+SEC_POS_APP,g_sec_in ,len);
	}

	// 填写报文类型域
	g_sec_out[4] = 0x00;
	g_sec_out[5] = 0x01; // 对象和密钥标识都用主站
	if(jm)
	{
		g_sec_out[5] |= SEC_MSG_ENCRYPT;
	}
	len += 2;

	// 封装报文
	_sec_pack(g_sec_out,0,len);
	len += 6;

	*out = g_sec_out;
	return len;
}

#ifdef CPU_FUXI
int sec_md5(char *pdata, int pdata_len,  char *presult) 
{
	return 1;
}
#else
int sec_md5(char *pdata, int pdata_len,  char *presult) 
{
	struct scatterlist  *sg;
	struct crypto_hash *tfm;
	struct hash_desc   desc;
	int ret = 0;
	int i,page_cnt;

	if((!pdata) || (!presult))
	{
		return -1;
	}

	//计算需要多少页
	page_cnt = (pdata_len+SEC_MD5_PAGE_SIZE-1)/SEC_MD5_PAGE_SIZE;
	
	//分配足够的内存
	sg=rt_malloc(sizeof(struct scatterlist ) * page_cnt);

	if(!sg)
	{
		return -2;
	}

	//创建一个MD5的hash
	tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
    	if (IS_ERR(tfm))
    	{
		ret =  -3;
		goto OUT;
	}

	//初始化hash_desc
	desc.tfm = tfm;
    	desc.flags = 0;

	//初始化 scatterlist
	sg_init_table(sg, page_cnt);

	//指定每一个scatterlist的大小.注意大小不能超过一页
	for(i=0;i<(page_cnt-1);i++)
	{
		sg_set_buf(&sg[i], pdata+i*SEC_MD5_PAGE_SIZE,  SEC_MD5_PAGE_SIZE);
	}

	//指定最后一个scatterlist的大小
	sg_set_buf(&sg[i], pdata+i*SEC_MD5_PAGE_SIZE,  pdata_len - i*SEC_MD5_PAGE_SIZE);

	//计算MD5摘要值
	ret = crypto_hash_digest(&desc, sg, pdata_len, presult);
	if (ret)
	{
		printk("error crypto_hash_digest=%d \r\n", ret);
		ret = -4;
		goto OUT;
	}
OUT:
	rt_free(sg);
	 crypto_free_hash(tfm);
	
	return ret;
} 
#endif

int sec_md5_file(char *filename,u8 *md5)
{
	int fd,ret;
	char *p;
	struct stat s;	

	// 检查参数
	if(filename == 0 || md5 == 0)
	{
		return -1;
	}

	//获取文件属性
	if(sys_newstat(filename, &s))
	{
		return -2;
	}

	// 分配内存
	p=rt_malloc(s.st_size);
	if(!p)
	{
		return -3;
	}

	// 打开文件并读取数据
	fd = sys_open(filename, O_RDONLY, 0);
	if(fd < 0)
	{
		rt_free(p);
		return -4;
	}
	ret=sys_read(fd, p, s.st_size);
	sys_close(fd);
	if(ret !=  s.st_size)
	{
		rt_free(p);
		return -5;
	}

	// 摘要计算
	ret=sec_md5(p, s.st_size, md5);
	rt_free(p);
	if(ret < 0)
	{
		ret -= 100;
	}

	return ret;
}


int sec_md5_check(char *buf,u16 len)
{
	int ret;
	u8 md5[SEC_MD5_LEN];
	char filename[64];
	sprintf(filename,"%s%s","/tmp/",KO_FILE_NAME_1);
	ret = sec_md5_file(filename,md5);
	if(ret < 0)
	{
		rt_printf("sec_md5_file error:ret=%d.\r\n",ret);
		return -1;
	}
	if(len!=0x4f)return -1;
	memcpy(g_sec_in,md5,SEC_MD5_LEN);
	memcpy(g_sec_in+SEC_MD5_LEN,buf,len-1);
	ret=esam_sign_verify_yk(buf[len-1],g_sec_in,(len-1+SEC_MD5_LEN));
	return ret;
}

// 配合加密盒测试，提供文件校验信息
int sec_md5_get_inf(char *md5)
{
	int ret;
	char filename[64];
	memset(md5,0,SEC_MD5_LEN);	
	sprintf(filename,"%s%s","/tmp/",KO_FILE_NAME_1);
	ret = sec_md5_file(filename,md5);
	if(ret < 0)
	{
		rt_printf("sec_md5_file error:ret=%d.\r\n",ret);
	}
	return SEC_MD5_LEN;
}


u16  sec_md5_echo(u8 *out)
{
	out[4] = 0; // 报文类型0
	out[5] = 0;// 报文类型1
	out[6] = 0x1f; 			// 应用类型
	out[7] = 0x00;	// 扩展区长度0
	out[8] = 0x02;	// 扩展区长度1
	out[9] = (BYTE)(g_sec_md5_ret>>8);	// 错误码
	out[10] =(BYTE)(g_sec_md5_ret>>0);	//错误码
	_sec_pack(out,NULL,7);
	return 13;
}

void sec_app(void)
{
	int i;

	for(i=0; i<COMM_CHANNEL_NUM; i++)
	{
		if(g_sec_lnk[i].status)
		{
			if(ustimer_get_duration(g_sec_lnk[i].us0) > tRunPara.dSM2Time*USTIMER_SEC*2)
			{
				memset(&g_sec_lnk[i],0,sizeof(g_sec_lnk[i]));
				rt_printf_time("通道%d认证状态退出.\r\n",i);
			}
		}
	}
}

/*------------------------------ 内部函数 -------------------------------------
内部函数以下划线‘_’开头，不需要检查参数的合法性.
*/


/*------------------------------ 测试函数 -------------------------------------
一个实体文件必须带一个本模块的测试函数来进行单元测试，如果的确不方便在本模块中
进行单元测试，必须在此注明实际的测试位置（例如在哪个实体文件中使用哪个测试函数）.
*/
int sec_info_printf(void)
{
#if 1
	int ret;
	u8 md5[SEC_MD5_LEN];

	ret = sec_md5_file(KO_FILE_NAME,md5);
	rt_printf("sec_md5_file:ret=%d",ret);
	print_mem("md5:",md5,SEC_MD5_LEN);
#endif
	return 0;
}


/*------------------------------ 文件结束 -------------------------------------
*/


