📄 ic_card.c
字号:
/********************************************************************* * Designed by xiaohuiyang 2005.06.08 E-mail: yxh2001@21cn.com
* *********************************************************************/#include <string.h>#include <stdio.h>#include <stdlib.h>#include "ic_card.h"#include "tl.h" //Include Transport Layerchar m_chErrMsg[20];int ICOpenCom(){ if(TL_Open(2, 9600) != NO_ERR) { return -1; } return 0;}int ICCloseCom(){ TL_Close(); return 0;}int ICPowerOn(){ unsigned char recvbuf[256]; unsigned char cmd[] = "\x12"; unsigned char recvlen = 0; memset(recvbuf, 0x00, sizeof(recvbuf)); SendCmd(cmd, 1, recvbuf, &recvlen); if(recvbuf[1] == 0x3B) return 0; return -1;}int ICPowerDown(){ unsigned char recvbuf[256]; unsigned char cmd[] = "\x11"; unsigned char recvlen = 0; memset(recvbuf, 0x00, sizeof(recvbuf)); SendCmd(cmd, 1, recvbuf, &recvlen); return 0;}int ReadAccount(stMACDATA *pst/*char *account*/){ return PbocSelectPboc(pst/*account*/);}/*=============================================================================//函数名称: SendICCommand//输入参数: char *ICSendbuf : 发送字符串//输出参数: char *ICRecvbuf : 接收字符串// char *ICSW : 判断符 //返 回: 0--成功; <0: 失败//功 能: 发送ic卡命令//开发人员: yangxh//修改记录: 1. 第一次编写.===============================================================================*/short SendICCommand(char *ICSendbuf, char *ICRecvbuf, char *ICSW){ int ret,datalen; char chLen[3]; ret=SendICC(ICSendbuf, 0, ICRecvbuf, ICSW); memset(chLen, 0x00, 3); if(strncmp(ICSW,"61",2)==0) { memcpy(chLen,&ICSW[2],2); sscanf(chLen,"%02X",&datalen); datalen = datalen&0XFF; memset(ICSW, '\0', 5); ret = PbocGetResponse(ICRecvbuf, datalen, ICSW); } return ret;}/*=============================================================================//函数名称: PbocGetResponse//输入参数: char *ICSendbuf : 发送字符串// unsigned int datalen : 发送字符串长度//输出参数: char *SW : 判断符 //返 回: 0--成功; <0: 失败//功 能: 发送ic卡响应命令//开发人员: yangxh//修改记录: 1. 第一次编写.===============================================================================*/short PbocGetResponse(char *ICRecvbuf, unsigned int datalen, char *SW){ int ret; char chSend1[128], chLen[3]; stAPDU apdu; if( datalen<0 || datalen>256 ) return 102; //102代表数据长度错 memset( &apdu, '\0', sizeof(stAPDU) ); strcpy(apdu.cla,"00"); strcpy(apdu.ins,"C0"); strcpy(apdu.p1,"00"); strcpy(apdu.p2,"00"); sprintf(apdu.p3, "%02X", datalen); memset( chSend1, '\0', 128); sprintf(chSend1,"%s%s%s%s%s%s",apdu.cla,apdu.ins,apdu.p1,apdu.p2,apdu.p3,apdu.data); ret = SendICCommand(chSend1,ICRecvbuf,SW); if( ret ) return ret; ret =CheckSW(SW); if( ret ) return ret; memset(chLen,'\0',3); if(strncmp(SW,"6C",2)==0 || strncmp(SW,"61",2)==0) { memcpy(chLen,&SW[2],2); sscanf(chLen,"%02X",&datalen); datalen = datalen&0XFF; return PbocGetResponse(ICRecvbuf, datalen,SW); } return 0;}/*=============================================================================//函数名称: CheckSW//输入参数: char *pSW : 判断字符串//输出参数:无//返 回: 0--成功; <0: 失败//功 能: 检查ic卡响应//开发人员: yangxh//修改记录: 1. 第一次编写.===============================================================================*/short CheckSW(char *pSW){ unsigned int nSW; memset(m_chErrMsg,'\0',20); if((strncmp(pSW, "9000", 4)==0 || strncmp(pSW, "61", 2)==0 || strncmp(pSW, "6C", 2)==0 )) { return 0; } sscanf(pSW, "%04X", &nSW); GetICSWErrMsg(nSW); return nSW;}/*=============================================================================//函数名称: GetICSWErrMsg//输入参数: unsigned int SW : 错误标志//输出参数:无//返 回: 0--成功; <0: 失败//功 能: 获取错误信息//开发人员: yangxh//修改记录: 1. 第一次编写.===============================================================================*/void GetICSWErrMsg(unsigned int SW){ memset(m_chErrMsg,'\0',20); if( SW==0X6700 ) strcpy(m_chErrMsg,"Lc错误!"); else if( SW==0X6901 ) strcpy(m_chErrMsg,"命令不接受!"); else if( SW==0X6982 ) strcpy(m_chErrMsg,"不满足安全状态!"); else if( SW==0X6985 ) strcpy(m_chErrMsg,"使用条件不满足!"); else if( SW==0X6A81 ) strcpy(m_chErrMsg,"不支持此功能!"); else if( SW==0X6A82 ) strcpy(m_chErrMsg,"文件未找到!"); else if( SW==0X6A86 ) strcpy(m_chErrMsg,"参数P1, P2错误!"); else if( SW==0X6D00 ) strcpy(m_chErrMsg,"INS错误!"); else if( SW==0X6E00 ) strcpy(m_chErrMsg,"CLA错误!"); else if( SW==0X9302 ) strcpy(m_chErrMsg,"MAC无效!"); else if( SW==0X9303 ) strcpy(m_chErrMsg,"应用已经永久锁定!"); else if( SW==0X9401 ) strcpy(m_chErrMsg,"金额不足!"); else if( SW==0X9403 ) strcpy(m_chErrMsg,"密钥索引不支持!"); else if( SW==0X9406 ) strcpy(m_chErrMsg,"所需的MAC不可用!"); else strcpy(m_chErrMsg,"系统出错");}/****************************************************************//* Description : Sends Command to the reader and displays *//* answer or error code . *//* Input : *//* unsigned char *pszCmd -> Command *//* unsigned char ucLgcmd -> Command Length *//* Output : None *//* Returns : Error Code *//* Global Variables : None *//****************************************************************/short int SendCmd( unsigned char *pszCmd, unsigned char ucLgcmd, unsigned char *szRep, unsigned char *ucLgRep){// unsigned char szRep[ 256 ], ucLgRep ; short int siRet;//#ifdef MMI unsigned char ucIndice ; printf( "\n->" ); /*Display Command*/ for ( ucIndice = 0 ; ucIndice < ucLgcmd ; ucIndice++ ) printf( " %02Xh", pszCmd[ ucIndice ] ) ;//#endif /*Send the command and retrieves the answer*/ siRet = TL_SendReceive( ucLgcmd, pszCmd, ucLgRep, szRep ); /*If no error occured then display answer*/ if ( siRet == NO_ERR ) {//#ifdef MMI printf( "\n<-" ); for ( ucIndice = 0 ; ucIndice < *ucLgRep ; ucIndice++ ) printf( " %02Xh", szRep[ ucIndice ] ) ; printf( "\n" );//#endif } else { /*dispay error code value*///#ifdef MMI printf( "\nError occured : %X\n", siRet );//#endif /*Close port*/ TL_Close() ; /*Leave application*/ exit( -1 ) ; } return ( siRet ) ;}/*=============================================================================//函数名称: SendICC//输入参数: char *ICSendbuf : 发送字符串// int sendlen : 发送长度//输出参数:char *ICRecvbuf : 接收字符串// char *ICSW : 接收标志//返 回: 0--成功; <0: 失败//功 能: 发送IC卡指令//开发人员: yangxh//修改记录: 1. 第一次编写.===============================================================================*/int SendICC(char *ICSendbuf, int sendlen, char *ICRecvbuf, char *ICSW){ unsigned char ucLgRep; SendCmd((unsigned char *)ICSendbuf, sendlen, (unsigned char *)ICRecvbuf, &ucLgRep) ; return 0;}/*=============================================================================//函数名称: PbocICSelect//输入参数: char *file_id : 文件名称// int filelen :文件长度//输出参数:unsigned char *recvbuf : 接收字符串//返 回: 0--成功; <0: 失败//功 能: 文件选择//开发人员: yangxh//修改记录: 1. 第一次编写.===============================================================================*/int PbocICSelect(char *file_id, int filelen, unsigned char *recvbuf){ unsigned char recvlen = 0; unsigned char SendCommand[128]; int sendlen; short ret;// int i; memset((char *)SendCommand, 0x00, sizeof(SendCommand)); sprintf((char *)SendCommand, "%c%c%c%c%c%c", 0x14, 0x00, 0xA4, 0x04, 0x00, filelen); memcpy(SendCommand+6, file_id, filelen); sendlen = filelen + 6; ret = SendCmd(SendCommand, sendlen, recvbuf, &recvlen);/* printf("Pboc IC select:["); for(i = 0; i < recvlen; i++) { printf("%02X ", recvbuf[i]); } printf("]\n");*/ if(recvbuf[1] == 0x61) { sprintf((char *)SendCommand, "%c%c%c%c%c%c", 0x13, 0x00, 0xC0, 0x00, 0x00, recvbuf[2]); SendCmd(SendCommand, 6, recvbuf, &recvlen); } return 0;}/*=============================================================================//函数名称: PbocSelectPboc//输入参数: 无//输出参数:无//返 回: 0--成功; <0: 失败//功 能: 金融应用选择//开发人员: yangxh//修改记录: 1. 第一次编写.===============================================================================*/int PbocSelectPboc(stMACDATA *pst/*char *Account*/){ short ret; short sfi; char *ptr, tmpfilename[256]; char chPSE[50]; unsigned char recvbuf[256];// unsigned char datalen;// char cardno[21]; memset(tmpfilename, 0x00, sizeof(tmpfilename)); memset(recvbuf,'\0',256); memset(chPSE, '\0', 50); memcpy(tmpfilename, "1PAY.SYS.DDF01", 14); strcpy(chPSE, tmpfilename); PbocICSelect("1PAY.SYS.DDF01", strlen(tmpfilename), recvbuf);// if( ret )// return ret; printf("strstr\n"); ptr = strstr((char *)(recvbuf+1), "\x88\x01"); if(ptr == NULL) return -1; ptr += 2; sfi = ptr[0] & 0XFF; memset(recvbuf, 0x00, sizeof(recvbuf));/* for(i = 1; ; i++) { printf("Send Read Record\n"); ret = PbocReadRecord(0x14, ABS_RECORD, sfi, i, 0, (char *)recvbuf); if( ret ) return ret; printf("start strstr find data ...\n"); ptr = strstr((char *)(recvbuf+1),"\x4F"); if(ptr == NULL) return -1; if(strncmp(ptr+2, chPSE, 14) != 0 ) break; } printf("come here\n"); datalen = ptr[1] & 0XFF; memset(tmpfilename, 0x00, sizeof(tmpfilename)); memcpy(tmpfilename, ptr+2, datalen);*/ ret = PbocICSelect("\xD1\x56\x00\x00\x01\x45\x44\x2F\x45\x50\x00\x00\x00\x00\x00\x00", 16, recvbuf); if( ret ) return ret; //Unpackage Receive Data// memset(cardno, 0x00, sizeof(cardno)); GetInfo((char *)recvbuf, pst); // ret = PbocReadBinary(0x14, 21, 0, 30, (char *)recvbuf); return 0;}/*=============================================================================//函数名称: PbocReadRecord//输入参数: char head : 发送头标志// short readmode: 读取模式// short sfi:// short recno: 记录数// short reclen: 接收长度//输出参数:char *recvbuf: 接收数据//返 回: 0--成功; <0: 失败//功 能: 读记录//开发人员: yangxh//修改记录: 1. 第一次编写.===============================================================================*/short PbocReadRecord(char head, short readmode, short sfi, short recno, short reclen, char *recvbuf){ unsigned char recvlen = 0; unsigned char datalen; int sendlen; unsigned char SendCommand[128]; short ret, p2; p2 = ( sfi << 3 ) | readmode; memset((char *)SendCommand, 0x00, sizeof(SendCommand)); sprintf((char *)SendCommand, "%c%c%c%c%c%c", head, 0x00, 0xB2, recno, p2, reclen); sendlen = 6; printf("Send Read Record\n"); ret = SendCmd(SendCommand, sendlen, (unsigned char *)recvbuf, &recvlen); if(recvbuf[1] == 0x6C || recvbuf[1] == 0x61) { datalen = recvbuf[2] & 0XFF; return PbocReadRecord(0x13, readmode, sfi, recno, datalen, recvbuf); } return 0;}/*=============================================================================//函数名称: PbocReadBinary//输入参数: char head : 发送头标志// short sfi:// short offset: 偏移量// short readlen: 接收长度//输出参数:char *recvbuf: 接收数据//返 回: 0--成功; <0: 失败//功 能: 读二进制文件//开发人员: yangxh//修改记录: 1. 第一次编写.===============================================================================*/short PbocReadBinary(char head, short sfi, short offset, short readlen, char *recvbuf){ short datalen, ret, p1; int sendlen; unsigned char recvlen = 0; unsigned char SendCommand[128]; if( sfi > 30 || (sfi<21 && sfi!=0 ) ) return FALSE; if( sfi!=0 ) p1 = 0x80 | sfi; else p1 = sfi; memset((char *)SendCommand, 0x00, sizeof(SendCommand)); sprintf((char *)SendCommand, "%c%c%c%c%c%c", head, 0x00, 0xB0, p1, offset, readlen); sendlen = 6; printf("Send ReadBinary\n"); ret = SendCmd(SendCommand, sendlen, (unsigned char *)recvbuf, &recvlen); if(recvbuf[1] == 0x6C || recvbuf[1] == 0x61) { datalen = recvbuf[2] & 0XFF; return PbocReadBinary(0x13, sfi, offset, datalen, recvbuf); } return 0;}/*=============================================================================//函数名称: GetInfo//输入参数: char *recvbuf: 接收数据//输出参数:char *cardno : 卡号//返 回: 0--成功; <0: 失败//功 能: 获取返回信息//开发人员: yangxh//修改记录: 1. 第一次编写.===============================================================================*/int GetInfo(char *recvbuf, stMACDATA *pst/*char *cardno*/){ int i; char startday[10], endday[10]; char temp[50]; char *ptr; memset(temp, 0x00, sizeof(temp)); memset(startday, 0x00, sizeof(startday)); memset(endday, 0x00, sizeof(endday)); if(recvbuf[0] != 0x00) return -1; if(recvbuf[1] != 0x6f) // FCI 模板 return -2; printf("FCI:[%02X]\n", recvbuf[2]); if(recvbuf[3] != 0x84) // DF 名 return -3; memcpy(temp, recvbuf+5, recvbuf[4]); printf("DF name:\n"); for(i = 0; i < recvbuf[4]; i++) { printf("%02X ", temp[i]); } printf("\n"); ptr = recvbuf + recvbuf[4] + 5; if(ptr[0] != 0xa5) // FCI 专用数据 return -4;// printf("FCI Special Data:[%02X]\n", ptr[1]);// ptr = strstr(ptr, "\x9f\x08"); // 应用版本号// printf("Version NO:[%02x%02x]\n", ptr[2], ptr[3]);// ptr += 4; ptr = strstr(ptr, "\x9f\x0c"); // 应用版本号 if(ptr != NULL)// 发送方自定义数据 FCI { printf("Sender self define fci:[%02x]\n", ptr[2]); } else return -5; ptr += 3; printf("Author card flag:"); // 发卡方标识符 memcpy(pst->bank_id, ptr, 8); for(i = 0; i < 8; i++) { printf("%02x ", ptr[i]); } printf("\n"); ptr += 8; printf("use type:[%02x]\n", ptr[0]); // 应用类型标识 printf("version:[%02X]\n", ptr[1]); // 发卡方应用版本号 memset(temp, 0x00, sizeof(temp)); memcpy(temp, ptr+2, 10); // 应用序列号 memcpy(pst->card_no, ptr+2, 10);/* for(i = 0; i < 10; i++) { printf("%02X", temp[i]); sprintf(cardno+i*2, "%02X", temp[i]); } for(i = 0; i < 20; i++) { if(cardno[i] == 'F') { cardno[i] = '\0'; break; } } printf("card no:[%s]\n", cardno);*/ memset(temp, 0x00, sizeof(temp)); memcpy(temp, ptr+12, 4); // 应用启用日期 for(i = 0; i < 4; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -