卡库的封装和调用,这是一个重头戏,完成了它,则就完整了所有的封装。至于网络通信,记录存储等,则可以使用go本身的模块去做。后续做一版完整的go语言版B503应用。
截至目前,非接触式卡库的封装接近尾声,这部分花了不少精力。
package drivers /* #cgo CFLAGS: -Iinclude #cgo LDFLAGS: -Llib -lpicc #include <stdlib.h> #include "pcd_apis.h" */ import "C" import "unsafe" import ( "fmt" "log" ) const ( DEF_PCD_SeleTypeA int = 1 DEF_PCD_SeleTypeB int = 2 ) type __Pcd14443Cfg struct { PPS int //AB 0:标准的支持PPS,非0:强制不支持PPS M1CPU int //AB 0:自动识别,1:强制M1,2:强制CPU } type __Pcd14443Info struct { ATQA []byte //A专用 REQA命令返回的ATQA值 固定有效2字节 UID []byte //A专用 卡片的UID, 长度为4,7,10字节 UID_Size byte //A专用 卡片的UID长度 长度为4,7,10字节 SAK byte //A专用 卡片选卡成功返回的SAK值 固定有效1字节 TypeAB byte //A/B共用 当前是A卡还是B卡 DEF_PCD_SeleTypeA=A卡,DEF_PCD_SeleTypeB=B卡 ATS_Size byte //A专用 接收到的ATS数据长度 BActive byte //B激活状态 0:非激活 非0:激活 Rvs08bit byte Rvs16bit byte ATS []byte //A专用 ATS接收数据缓冲区 按中国金融规定 PICC回的数据最长为21字节 ATQB []byte //B专用 卡片应答数据 } //14443应用数据结构 var ( Pcd14443CfgMode int = DEF_PCD_SeleTypeA //PCD选择TypeA卡 操作PICC类型定义 Pcd14443CfgA __Pcd14443Cfg Pcd14443CfgB __Pcd14443Cfg Pcd14443Info __Pcd14443Info //14443协议层数据缓冲区 PiccCid int ) func init() { Pcd14443Info.ATQA = make([]byte, 4) Pcd14443Info.UID = make([]byte, 16) Pcd14443Info.ATS = make([]byte, 40) Pcd14443Info.ATQB = make([]byte, 20) } func ICC_PCD_SysCfg(mode, m1, pps int) { Pcd14443CfgMode = mode if DEF_PCD_SeleTypeA == Pcd14443CfgMode { Pcd14443CfgA.PPS = pps Pcd14443CfgA.M1CPU = m1 } else if DEF_PCD_SeleTypeB == Pcd14443CfgMode { Pcd14443CfgB.PPS = pps Pcd14443CfgB.M1CPU = m1 } } func ICC_PCD_Init() int { tpe := make([]byte, 4) para := make([]byte, 50) //var cardType *C.uchar = (*C.uchar)(unsafe.Pointer(&tpe[0])) //var rfPara *C.uchar = (*C.uchar)(unsafe.Pointer(¶[0])) cardType := (*C.uchar)(unsafe.Pointer(&tpe[0])) rfPara := (*C.uchar)(unsafe.Pointer(¶[0])) ret := C.PcdInit(cardType, rfPara) if ret != 0 { return 1 } fmt.Println(tpe) fmt.Println(para) ret = C.PiccOpen() return int(ret) } func ICC_PCD_Open() int { ret := C.PiccOpen() return int(ret) } func ICC_PCD_Close() { C.PiccClose() } //ISO14443 A/B 使卡进入HALT状态 func ICC_PCD_Halt() int { //nc_iso14443_debug("%s","ICC_PCD_Halt\n"); ret := C.PiccRemove('H', C.uchar(PiccCid)) return int(ret) } //ISO14443 A/B 使已经进入HALT状态的卡激活,并且进行冲突循环,选卡操作 func ICC_PCD_WakeUp() int { ret := ICC_PCD_Request(Pcd14443CfgMode) return int(ret) } func ICC_PCD_Request(mode int) int { tpe := make([]byte, 4) sno := make([]byte, 100) oth := make([]byte, 100) pid := make([]byte, 1) lenth := 0 ptr := 0 ret := C.uchar(0) cardType := (*C.uchar)(unsafe.Pointer(&tpe[0])) serialNo := (*C.uchar)(unsafe.Pointer(&sno[0])) other := (*C.uchar)(unsafe.Pointer(&oth[0])) piccid := (*C.uchar)(unsafe.Pointer(&pid[0])) if DEF_PCD_SeleTypeA == Pcd14443CfgMode { if DEF_PCD_SeleTypeA == Pcd14443CfgA.M1CPU { //强制M1 ret = C.PiccDetect('M', cardType, serialNo, piccid, other) } else if DEF_PCD_SeleTypeB == Pcd14443CfgA.M1CPU { //强制CPUA ret = C.PiccDetect('A', cardType, serialNo, piccid, other) } else if 3 == Pcd14443CfgA.M1CPU { //自动检测A,B,无法检测到纯M1 操作一次28ms ret = C.PiccDetect(0x01, cardType, serialNo, piccid, other) } else { //自动CPUA/M1 操作一次18ms ret = C.PiccDetect('X', cardType, serialNo, piccid, other) } // printf(">>>>>>>>>>>>PiccDetect, ret=%d count=%d\n", ret, count++); } else if DEF_PCD_SeleTypeB == Pcd14443CfgMode { //强制CPUB ret = C.PiccDetect('B', cardType, serialNo, piccid, other) } else { log.Fatal("err config!") } //fmt.Printf("ret = %d\n", int(ret)) PiccCid = int(pid[0]) if ret == 0 { //fmt.Printf("tpe:%x\n", tpe) //fmt.Printf("sno:%x\n", sno) //fmt.Printf("oth:%x\n", oth) if 'B' == tpe[0] { Pcd14443Info.TypeAB = byte(DEF_PCD_SeleTypeB) //TYPE B } else if 'M' == tpe[0] { Pcd14443Info.TypeAB = byte(DEF_PCD_SeleTypeA) //TYPE A } else { Pcd14443Info.TypeAB = byte(DEF_PCD_SeleTypeA) //TYPE A } if sno[0] > 10 { //序列号长度不能大于10 return 1 } Pcd14443Info.UID_Size = sno[0] copy(Pcd14443Info.UID, sno[1:1+Pcd14443Info.UID_Size]) if oth[0] > 2 { ptr = 3 lenth = int(oth[ptr]) ptr += 1 if ptr+lenth < len(oth) { copy(Pcd14443Info.ATQA, oth[ptr:ptr+2]) //fmt.Printf("ATQA:%x\n", Pcd14443Info.ATQA) } ptr += lenth lenth = int(oth[ptr]) ptr += 1 if ptr+lenth < len(oth) { Pcd14443Info.SAK = oth[ptr] } ptr += lenth lenth = int(oth[ptr]) if 'A' == tpe[0] && (ptr+lenth < len(oth)) { copy(Pcd14443Info.ATS, oth[ptr:ptr+lenth]) Pcd14443Info.ATS_Size = byte(lenth) } //fmt.Println(Pcd14443Info) fmt.Printf("ATQA:%x\n", Pcd14443Info.ATQA) fmt.Printf("SAK:%x\n", Pcd14443Info.SAK) fmt.Printf("UID:%x\n", Pcd14443Info.UID) } } else { Pcd14443Info.ATQA[0] = 0 Pcd14443Info.ATQA[1] = 0 Pcd14443Info.ATQA[2] = 0 Pcd14443Info.ATQA[3] = 0 } return int(ret) } //ISO14443 A/B 检测卡片是否存在,卡片激活状态后调用 func ICC_PCD_CheckPICCRounge() int { ret := C.PiccRemove('C', C.uchar(PiccCid)) //nc_iso14443_debug("PiccRemove('C').ret=%d\n", ret); if 0x06 == ret { //卡片仍在感应区 //nc_iso14443_debug( "%s", "Card exist\n" ); //PiccRemove('C')停活卡片,需要重新寻卡以激活卡片 return 0 //返回卡片仍在 } else { //nc_iso14443_debug( "%s", "Card removed\n" ); return 1 //返回卡片离开 } } //ISO14443 A/B 检测PICC是否移出工作场 func ICC_PCD_CheckPICCrf() int { ret := C.PiccRemove('R', C.uchar(PiccCid)) //nc_iso14443_debug("PiccRemove('C').ret=%d\n", ret); if 0x06 == ret { //卡片仍在感应区 //nc_iso14443_debug( "%s", "Card exist\n" ); //PiccRemove('C')停活卡片,需要重新寻卡以激活卡片 return 0 //返回卡片仍在 } else { //nc_iso14443_debug( "%s", "Card removed\n" ); return 1 //返回卡片离开 } } //ISO14443 A/B 等待PICC移出工作场 func ICC_PCD_WaitPICCrf() int { for true { ret := C.PiccRemove('C', C.uchar(PiccCid)) //nc_iso14443_debug("PiccRemove('C').ret=%d\n", ret); if 0x06 == ret { //nc_iso14443_debug( "%s", "Card exist\n" ); continue //返回卡片仍在 } else { //nc_iso14443_debug( "%s", "Card removed\n" ); break //卡片移出 } } return 0 } //ISO14443 A/B 复位工作场 func ICC_PCD_ResetPCDrf() int { C.PiccClose() ret := C.PiccOpen() //nc_iso14443_debug("ICC_PCD_ResetPCDrf. ret = %d\n", ret); return int(ret) } func ICC_PCD_APDUCommand(in []byte, inlen int, out []byte, outlen *int, maxsize int, lc, le byte) int { var ApduSend C.APDU_SEND var ApduResp C.APDU_RESP ApduSend.Command[0] = C.uchar(in[0]) ApduSend.Command[1] = C.uchar(in[1]) ApduSend.Command[2] = C.uchar(in[2]) ApduSend.Command[3] = C.uchar(in[3]) ApduSend.Lc = C.ushort(lc) for i := 0; i < int(lc); i++ { ApduSend.DataIn[i] = C.uchar(in[5+i]) } if le != 0 { //此处须填非0值,若le非0则填实际值,否则固定填256 ApduSend.Le = C.ushort(le) } else { ApduSend.Le = 256 } fmt.Printf("->APDU:%x\n", in[0:inlen]) ret := C.PiccIsoCommand(C.uchar(PiccCid), &ApduSend, &ApduResp) if ret != 0 { return int(ret) } if (le != 0) && (byte(ApduResp.LenOut) != le) { } if int(ApduResp.LenOut+2) < maxsize { //还有两个字节的状态字节 SWA/SWB //memcpy( out, &ApduResp.DataOut[0], ApduResp.LenOut ); for i := 0; i < int(ApduResp.LenOut); i++ { out[i] = byte(ApduResp.DataOut[i]) } out[ApduResp.LenOut] = byte(ApduResp.SWA) out[ApduResp.LenOut+1] = byte(ApduResp.SWB) } else { //memcpy( out, &ApduResp.DataOut[0], maxsize-2 ); for i := 0; i < maxsize-2; i++ { out[i] = byte(ApduResp.DataOut[i]) } out[ApduResp.LenOut] = byte(ApduResp.SWA) out[ApduResp.LenOut+1] = byte(ApduResp.SWB) } *outlen = int(ApduResp.LenOut + 2) fmt.Printf("<-APDU:%x\n", out[0:ApduResp.LenOut+2]) return 0 } func main() { fmt.Println("Hello Go") ret := ICC_PCD_Init() if ret == 0 { fmt.Println("ICC PCD init ok!") ICC_PCD_SysCfg(DEF_PCD_SeleTypeA, 0, 1) for i := 0; i < 100; i++ { ret = ICC_PCD_Request(DEF_PCD_SeleTypeA) if ret == 0 { fmt.Println("find card ok!") } else { fmt.Println("not find card!") } } } else { fmt.Printf("ICC PCD init err!,code=%d\n", ret) } name := "" fmt.Println("over!press any key to continue: ") fmt.Scanln(&name) }
package card import ( "encoding/hex" "fmt" "go8583/drivers" "math/rand" "time" ) func ICF_GetChallenge8B(Rnd []byte, ich int) int { CmdBuffer[0] = 0x00 //CLA CmdBuffer[1] = 0x84 //INS CmdBuffer[2] = 0x00 //P1 CmdBuffer[3] = 0x00 //P2 CmdBuffer[4] = 0x08 //Le rcode := drivers.ICC_APDU_Exchange(ich, CmdBuffer, 5, RcvBuffer, &Grcv_Len, 260, 0, CmdBuffer[4]) if rcode != 0 { fmt.Printf("ICC_APDU_Exchange err,code=%d\n", rcode) return rcode } if Grcv_Len < 2 { return 2 } rcode = ((int(RcvBuffer[Grcv_Len-2]) << 8) | int(RcvBuffer[Grcv_Len-1])) if rcode != 0x9000 { return rcode } copy(Rnd, RcvBuffer[0:8]) return rcode } func ICF_SelectAID(AID []byte, ilen int, ich int) int { CmdBuffer[0] = 0x00 //CLA CmdBuffer[1] = 0xA4 //INS CmdBuffer[2] = 0x04 //P1 CmdBuffer[3] = 0x00 //P2 CmdBuffer[4] = byte(ilen) //Lc copy(CmdBuffer[5:], AID[0:ilen]) rcode := drivers.ICC_APDU_Exchange(ich, CmdBuffer, ilen+5, RcvBuffer, &Grcv_Len, 260, CmdBuffer[4], 0) if rcode != 0 { fmt.Printf("ICC_APDU_Exchange err,code=%d\n", rcode) return rcode } if Grcv_Len < 2 { return 2 } rcode = ((int(RcvBuffer[Grcv_Len-2]) << 8) | int(RcvBuffer[Grcv_Len-1])) if rcode != 0x9000 { return rcode } return rcode } //{9f38 18 9f66049f02069f03069f1a0295055f2a029a039c019f3704} func UP_GPO(pdoc []byte, lenth byte, ich int) int { CmdBuffer[0] = 0x80 //CLA CmdBuffer[1] = 0xA8 //INS CmdBuffer[2] = 0x00 //P1 CmdBuffer[3] = 0x00 //P2 ‘01’用于ED(电子存折,需要个人密码PIN ‘02’用于EP(电子钱包) CmdBuffer[4] = lenth + 2 //Lc CmdBuffer[5] = 0x83 CmdBuffer[6] = lenth copy(CmdBuffer[7:], pdoc[0:lenth]) rcode := drivers.ICC_APDU_Exchange(ich, CmdBuffer, int(lenth+8), RcvBuffer, &Grcv_Len, 260, CmdBuffer[4], 0) if rcode != 0 { fmt.Printf("ICC_APDU_Exchange err,code=%d\n", rcode) return rcode } if Grcv_Len < 2 { return 2 } rcode = ((int(RcvBuffer[Grcv_Len-2]) << 8) | int(RcvBuffer[Grcv_Len-1])) if rcode != 0x9000 { return rcode } return rcode } /* *双免GPO组包 */ //{9f38 18 9f66049f02069f03069f1a0295055f2a029a039c019f3704} func UP_qUICS(money int, opdt string, ich int) int { t9F66 := "........" //交易属性 t9F02 := fmt.Sprintf("%012d", money) //授权金额 t9F03 := "000000000000" t9F1A := "0156" t95 := "0000000000" t5F2A := "0156" t9A := opdt t9C := "00" rand.Seed(time.Now().Unix()) t9F37 := fmt.Sprintf("%08x", rand.Int31()) pdoc := t9F66 + t9F02 + t9F03 + t9F1A + t95 + t5F2A + t9A + t9C + t9F37 fmt.Printf("pdoc:%s\n", pdoc) bpdoc, err := hex.DecodeString(pdoc) if err != nil { fmt.Printf("DecodeString error:%s\n", err.Error()) } fmt.Printf("bpdoc:%x\n", bpdoc) return UP_GPO(bpdoc, byte(len(bpdoc)), ich) }
root@b503_lcd:/app/city_app/opt# ./cardlib Hello Go ATQA:08000000 SAK:20 UID:5deaa62a000000000000000000000000 find card ok! ATQA:04000000 SAK:28 UID:2f7bb136000000000000000000000000 find card ok! ->APDU:00a404000e325041592e5359532e4444463031 <-APDU:6f30840e325041592e5359532e4444463031a51ebf0c1b61194f08a000000333010101500a50424f432044454249548701019000 ICF_SelectAID ok! [{6f 30 840e325041592e5359532e4444463031a51ebf0c1b61194f08a000000333010101500a50424f43204445424954870101} {84 0e 325041592e5359532e4444463031} {a5 1e bf0c1b61194f08a000000333010101500a50424f43204445424954870101} {bf0c 1b 61194f08a000000333010101500a50424f43204445424954870101} {61 19 4f08a000000333010101500a50424f43204445424954870101} {4f 08 a000000333010101} {50 0a 50424f43204445424954} {87 01 01}]