卡库的封装和调用,这是一个重头戏,完成了它,则就完整了所有的封装。至于网络通信,记录存储等,则可以
使用go本身的模块去做。后续做一版完整的go语言版B503应用。
截至目前,非接触式卡库的封装接近尾声,这部分花了不少精力。
package drivers
/*
#cgo CFLAGS: -Iinclude
#cgo LDFLAGS: -Llib -lpicc
#include
#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
");
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
", 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
", int(ret))
PiccCid = int(pid[0])
if ret == 0 {
//fmt.Printf("tpe:%x
", tpe)
//fmt.Printf("sno:%x
", sno)
//fmt.Printf("oth:%x
", 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
", 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
", Pcd14443Info.ATQA)
fmt.Printf("SAK:%x
", Pcd14443Info.SAK)
fmt.Printf("UID:%x
", 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
", ret);
if 0x06 == ret { //卡片仍在感应区
//nc_iso14443_debug( "%s", "Card exist
" ); //PiccRemove('C')停活卡片,需要重新寻卡以激活卡片
return 0 //返回卡片仍在
} else {
//nc_iso14443_debug( "%s", "Card removed
" );
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
", ret);
if 0x06 == ret { //卡片仍在感应区
//nc_iso14443_debug( "%s", "Card exist
" ); //PiccRemove('C')停活卡片,需要重新寻卡以激活卡片
return 0 //返回卡片仍在
} else {
//nc_iso14443_debug( "%s", "Card removed
" );
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
", ret);
if 0x06 == ret {
//nc_iso14443_debug( "%s", "Card exist
" );
continue //返回卡片仍在
} else {
//nc_iso14443_debug( "%s", "Card removed
" );
break //卡片移出
}
}
return 0
}
//ISO14443 A/B 复位工作场
func ICC_PCD_ResetPCDrf() int {
C.PiccClose()
ret := C.PiccOpen()
//nc_iso14443_debug("ICC_PCD_ResetPCDrf. ret = %d
", 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
", 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
", 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
", 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
", 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
", 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
", 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
", pdoc)
bpdoc, err := hex.DecodeString(pdoc)
if err != nil {
fmt.Printf("DecodeString error:%s
", err.Error())
}
fmt.Printf("bpdoc:%x
", 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}]