Go语言银联8583报文解析库,支持联小额免密付和银商聚合支付

2021-03-05 11:01:34 浏览数 (1)

很早之前就整过一个Go语言版的银联8583报文解析库,不过是用来测试的。

最近整合了进了银联小额双免交易和银商的聚合支付交易通道,这可以是网上最简单的8583报文解析库了。

银联双免支付通道支持银行卡免密和云闪付二维码交易,而银商的聚合支付交易通道支持支付宝付款码,微信付款码和云闪付二维码。

如果配置了正确的秘钥参数,可直接用来交易。

附代码实现和使用demo:

代码语言:javascript复制
/**
银联8583报文,
包含签到,云闪付二维码交易,银联卡小额免密交易
Author:yangyongzhen
QQ:534117529
*/
package up8583

import (
	"errors"
	"fmt"
	"go8583/easy8583"
	"go8583/utils"
	"strconv"
	"strings"
)

type Up8583 struct {
	Ea         *easy8583.Easy8583
	ManNum     string //商户号
	PosNum     string //终端号
	MainKey    string //主密钥
	TPDU       string
	CommSn     int    //通信流水
	RecSn      int    //售卡方系统跟踪号
	PiciNum    []byte //批次号
	LicenceNum []byte

	MacKey string //MAC key

	UpBinNum  string //银行卡卡号
	CardSnNum string //持卡序号
	CardDate  string //卡有效期
	Fd35Data  string //二磁道数据
}

func memcpy(dst, src []byte, size int) {
	for i := 0; i < size; i   {
		dst[i] = src[i]
	}
	return
}

func equals(src1 []byte, src2 []byte) bool {

	if src1 == nil || src2 == nil {
		return false
	}
	le1 := len(src1)
	le2 := len(src2)
	if le1 != le2 {
		return false
	}
	for i := 0; i < le1; i   {
		if src1[i] != src2[i] {
			return false
		}
	}
	return true
}

/*
银联8583签到组包
*/
func (up *Up8583) Frame8583QD() {

	s := up.Ea
	field := up.Ea.Field_S

	s.Init8583Fields(field)

	//消息类型
	s.Msgtype[0] = 0x08
	s.Msgtype[1] = 0x00

	//11域,受卡方系统跟踪号BCD 通讯流水
	field[10].Ihave = true
	field[10].Len = 3
	sn := fmt.Sprintf("d", up.CommSn)

	field[10].Data = utils.HexStringToBytes(sn)

	//41域,终端号
	field[40].Ihave = true
	field[40].Len = 8
	field[40].Data = []byte(up.PosNum)
	//42域,商户号
	field[41].Ihave = true
	field[41].Len = 15
	field[41].Data = []byte(up.ManNum)
	//60域
	field[59].Ihave = true
	field[59].Len = 0x11
	field[59].Data = make([]byte, 6)
	field[59].Data[0] = 0x00
	memcpy(field[59].Data[1:], up.PiciNum, 3)
	field[59].Data[4] = 0x00
	field[59].Data[5] = 0x30
	//62域
	field[61].Ihave = true
	field[61].Len = 0x25
	field[61].Data = make([]byte, 25)
	str := "Sequence No12"
	memcpy(field[61].Data, []byte(str), 13)
	memcpy(field[61].Data[13:], up.LicenceNum, 4)
	memcpy(field[61].Data[17:], []byte(up.PosNum), 8)

	//63域
	field[62].Ihave = true
	field[62].Len = 0x03
	field[62].Data = make([]byte, 3)
	field[62].Data[0] = 0x30
	field[62].Data[1] = 0x30
	field[62].Data[2] = 0x31
	/*报文组帧,自动组织这些域到Pack的TxBuffer中*/
	s.Pack8583Fields()

	up.CommSn   //通讯流水每次加一

	//s.PrintFields(up.Ea.Field_S)

}

func (up *Up8583) Ans8583QD(rxbuf []byte, rxlen int) error {

	r := up.Ea
	fields := up.Ea.Field_S
	fieldr := up.Ea.Field_R

	ret := r.Ans8583Fields(rxbuf, rxlen)
	if ret == 0 {
		fmt.Println("解析成功")
		r.PrintFields(fieldr)
	} else {
		fmt.Println("解析失败")
		return errors.New("error,failed to ans..")
	}
	//消息类型判断
	if (r.Msgtype[0] != 0x08) || (r.Msgtype[1] != 0x10) {
		//Log.d(TAG,"消息类型错!");
		return errors.New("error,wrong Msgtype ")
	}
	//应答码判断
	if (fieldr[38].Data[0] != 0x30) || (fieldr[38].Data[1] != 0x30) {
		//Log.d(TAG,"应答码不正确!");
		return errors.New("error,wrong resp code:"   fmt.Sprintf("xx", fieldr[38].Data[0], fieldr[38].Data[1]))
	}
	//跟踪号比较
	//memcmp
	if !equals(fields[10].Data, fieldr[10].Data) {
		return errors.New("error,wrong comm no ")
	}

	//终端号比较
	if !equals(fields[40].Data, fieldr[40].Data) {
		return errors.New("error,posnum not equal ")
	}
	//商户号比较
	if !equals(fields[41].Data, fieldr[41].Data) {
		return errors.New("error,mannum not equal ")
	}
	//3DES解密PIN KEY
	data := make([]byte, 16)
	memcpy(data, fieldr[61].Data, 16)
	pinkey, err := utils.Des3Decrypt(data, utils.HexStringToBytes(up.MainKey))
	if err != nil {
		return errors.New("1"   err.Error())
	}
	//解密后的结果对8Byte全0做3DES加密运算
	tmp := make([]byte, 8)
	out, err := utils.Des3Encrypt(tmp, pinkey)
	if err != nil {
		return errors.New("2"   err.Error())
	}
	check := make([]byte, 4)
	pincheck := make([]byte, 4)
	memcpy(check, out, 4)
	memcpy(pincheck, fieldr[61].Data[16:], 4)
	if !equals(check, pincheck) {
		return errors.New("error,Er PIK")
	}
	//3DES解密MAC KEY
	memcpy(data, fieldr[61].Data[20:], 16)
	mackey, err := utils.Des3Decrypt(data, utils.HexStringToBytes(up.MainKey))
	if err != nil {
		return errors.New("3"   err.Error())
	}
	out, err = utils.DesEncrypt(tmp, mackey[0:8])
	if err != nil {
		return errors.New("4"   err.Error())
	}
	maccheck := make([]byte, 4)
	memcpy(check, out, 4)
	memcpy(maccheck, fieldr[61].Data[36:], 4)
	if !equals(check, maccheck) {
		return errors.New("error,Er MAC")
	}
	memcpy(up.PiciNum, fieldr[59].Data[1:], 3)
	up.MacKey = utils.BytesToHexString(mackey[0:8])
	fmt.Printf("mackey:%sn", up.MacKey)
	up.Ea.SetMacKey(up.MacKey)
	return nil
}

func (up *Up8583) Ans8583Qrcode(rxbuf []byte, rxlen int) error {
	r := up.Ea
	fields := up.Ea.Field_S
	fieldr := up.Ea.Field_R

	ret := r.Ans8583Fields(rxbuf, rxlen)
	if ret == 0 {
		fmt.Println("解析成功")
		r.PrintFields(fieldr)
	} else {
		fmt.Println("解析失败")
		return errors.New("error,failed to ans..")
	}
	//消息类型判断
	if (r.Msgtype[0] != 0x02) || (r.Msgtype[1] != 0x10) {
		//Log.d(TAG,"消息类型错!");
		return errors.New("error,wrong Msgtype ")
	}
	//应答码判断
	if (fieldr[38].Data[0] != 0x30) || (fieldr[38].Data[1] != 0x30) {
		//Log.d(TAG,"应答码不正确!");
		return errors.New("error,wrong resp code:"   fmt.Sprintf("xx", fieldr[38].Data[0], fieldr[38].Data[1]))
	}
	//跟踪号比较
	//memcmp
	if !equals(fields[10].Data, fieldr[10].Data) {
		return errors.New("error,wrong comm no ")
	}

	//终端号比较
	if !equals(fields[40].Data, fieldr[40].Data) {
		return errors.New("error,posnum not equal ")
	}
	//商户号比较
	if !equals(fields[41].Data, fieldr[41].Data) {
		return errors.New("error,mannum not equal ")
	}
	return nil
}

/*
银联8583 二维码交易组包
qrcode:二维码内容
money:交易金额
recSn:交易流水
*/
func (up *Up8583) Frame8583Qrcode(qrcode string, money int, recSn int) {

	s := up.Ea
	field := up.Ea.Field_S

	s.Init8583Fields(field)

	//消息类型
	s.Msgtype[0] = 0x02
	s.Msgtype[1] = 0x00

	//3域 交易处理码
	field[2].Ihave = true
	field[2].Len = 3
	field[2].Data = make([]byte, 3)
	//4域 交易金额
	field[3].Ihave = true
	field[3].Len = 6
	field[3].Data = utils.HexStringToBytes(fmt.Sprintf("2d", money))
	//11域,受卡方系统跟踪号BCD 通讯流水
	field[10].Ihave = true
	field[10].Len = 3
	sn := fmt.Sprintf("d", recSn)

	field[10].Data = utils.HexStringToBytes(sn)

	//22域
	field[21].Ihave = true
	field[21].Len = 2
	field[21].Data = []byte{0x03, 0x20}
	//25域
	field[24].Ihave = true
	field[24].Len = 1
	field[24].Data = make([]byte, 1)

	//41域,终端号
	field[40].Ihave = true
	field[40].Len = 8
	field[40].Data = []byte(up.PosNum)
	//42域,商户号
	field[41].Ihave = true
	field[41].Len = 15
	field[41].Data = []byte(up.ManNum)

	//49域 交易货币代码
	field[48].Ihave = true
	field[48].Len = 3
	field[48].Data = []byte{0x31, 0x35, 0x36}
	//59域,扫码的数据
	field[58].Ihave = true
	field[58].Len = 0x24
	field[58].Data = make([]byte, 24)
	field[58].Data[0] = 'A' //TAG Len(019)
	field[58].Data[1] = '3'
	field[58].Data[2] = '0'
	field[58].Data[3] = '1'
	field[58].Data[4] = '9'
	memcpy(field[58].Data[5:], []byte(qrcode), 19)

	//60域
	field[59].Ihave = true
	field[59].Len = 0x13
	field[59].Data = make([]byte, 7)
	field[59].Data[0] = 0x22
	memcpy(field[59].Data[1:], up.PiciNum, 3)
	field[59].Data[4] = 0x00
	field[59].Data[5] = 0x06
	field[59].Data[6] = 0x00

	//MAC,64域
	field[63].Ihave = true
	field[63].Len = 0x08
	field[63].Data = make([]byte, 8)
	//这个域要求填MAC,只需按这样填,MAC的计算在pack8583Fields自动完成了
	/*报文组帧,自动组织这些域到Pack的TxBuffer中*/
	s.Pack8583Fields()

	//CommSn   //通讯流水每次加一

	//s.PrintFields(up.Ea.Field_S)

}

func NewUp8583() *Up8583 {

	var up = new(Up8583)
	up.Ea = easy8583.New8583()
	up.TPDU = "6000000001"
	up.ManNum = "000000000000000"
	up.PosNum = "00000000"
	up.MainKey = "00000000000000000000000000000000"
	up.CommSn = 1
	up.RecSn = 1 //终端交易流水,连续,且不能重复
	up.PiciNum = make([]byte, 3)
	up.LicenceNum = []byte{0x33, 0x30, 0x36, 0x30}
	up.MacKey = "0000000000000000"
	up.Ea.Tpdu = utils.HexStringToBytes(up.TPDU)
	return up

}

/**
Setup
初始化参数配置
manNum:商户号
posNum:终端号
mainKey:主密钥
*/
func (up *Up8583) Setup(manNum, posNum, mainKey, tpdu string) {
	up.TPDU = tpdu
	up.ManNum = manNum
	up.PosNum = posNum
	up.MainKey = mainKey
	up.Ea.Tpdu = utils.HexStringToBytes(up.TPDU)
}

/**
使用demo
*/
func main() {

	fmt.Println("test...")

	up := NewUp8583()
	up.Setup("888888888888888", "12345678", "11111111111111111111111111111111", "6005010000")
	//up.Frame8583QD()

	//recvstr := "007960000001386131003111080810003800010AC0001450021122130107200800085500323231333031343931333239303039393939393930363030313433303137303131393939390011000005190030004046F161A743497B32EAC760DF5EA57DF5900ECCE3977731A7EA402DDF0000000000000000CFF1592A"

	//recv := utils.HexStringToBytes(recvstr)
	//ret := up.Ea.Ans8583Fields(recv, len(recv))
	//if ret == 0 {
	// 	fmt.Println("解析成功")
	// 	up.Ea.PrintFields(up.Ea.Field_R)
	// } else {
	// 	fmt.Println("解析失败")
	// }

	up.Frame8583QD()
	up.Ea.PrintFields(up.Ea.Field_S)
	//
	//fmt.Println(utils.BytesToHexSrxbuf, err := utils.UpHttpsPost(Url, up.Ea.Txbuf)
	// err = up.Ans8583QD(rxbuf, rxlen)
	// if err == nil {
	// 	log.Println("签到成功")
	// }tring(up.Ea.Txbuf))
	up.Frame8583Qrcode("6220485073630469936", 1, 1)
	up.Ea.PrintFields(up.Ea.Field_S)

}

使用demo:云闪付二维码交易:

代码语言:javascript复制
/**
使用demo,银联二维码交易
*/
func QrcodeProc(qrcode string, money int, recSn int) error {
	if Url == "" {
		return errors.New("error: Url must not null")
	}
	//up8583.RecSn   //交易流水加加
	up.Frame8583Qrcode(qrcode, money, recSn)
	up.Ea.PrintFields(up.Ea.Field_S)
	log.Printf("connect:server=%sn", Url)
	rxbuf, err := utils.UpHttpsPost(Url, up.Ea.Txbuf)
	rxlen := len(rxbuf)
	if err == nil {
		log.Printf("recv ok!len=%dn", rxlen)
		err = up.Ans8583Qrcode(rxbuf, rxlen)
		if err == nil {
			log.Println("交易成功")
		} else {
			log.Println("交易失败")
		}
	}
	return err

}

func main() {

	fmt.Println("test...")

	up := NewUp8583()
    //配置进去商户号,终端号,主密钥参数
	up.Setup("888888888888888", "12345678", "11111111111111111111111111111111", "6005010000")
	//up.Frame8583QD()

	//recvstr := "007960000001386131003111080810003800010AC0001450021122130107200800085500323231333031343931333239303039393939393930363030313433303137303131393939390011000005190030004046F161A743497B32EAC760DF5EA57DF5900ECCE3977731A7EA402DDF0000000000000000CFF1592A"

	//recv := utils.HexStringToBytes(recvstr)
	//ret := up.Ea.Ans8583Fields(recv, len(recv))
	//if ret == 0 {
	// 	fmt.Println("解析成功")
	// 	up.Ea.PrintFields(up.Ea.Field_R)
	// } else {
	// 	fmt.Println("解析失败")
	// }

	up.Frame8583QD()
	up.Ea.PrintFields(up.Ea.Field_S)
	//
	//fmt.Println(utils.BytesToHexSrxbuf, err := utils.UpHttpsPost(Url, up.Ea.Txbuf)
	// err = up.Ans8583QD(rxbuf, rxlen)
	// if err == nil {
	// 	log.Println("签到成功")
	// }tring(up.Ea.Txbuf))
	//up.Frame8583Qrcode("6220485073630469936", 1, 1)
	//up.Ea.PrintFields(up.Ea.Field_S)
    err = QrcodeProc()
    if err == nil {
       log.Println("交易成功")
    }

}

0 人点赞