首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >嵌入式linux之go语言开发(三)卡库的封装

嵌入式linux之go语言开发(三)卡库的封装

作者头像
杨永贞
发布2020-08-04 10:24:20
1K0
发布2020-08-04 10:24:20
举报

卡库的封装和调用,这是一个重头戏,完成了它,则就完整了所有的封装。至于网络通信,记录存储等,则可以

使用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(&para[0]))
	cardType := (*C.uchar)(unsafe.Pointer(&tpe[0]))
	rfPara := (*C.uchar)(unsafe.Pointer(&para[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}]

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-01-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档