原来的pos用c语言开发的,与银联后台通信走的是8583协议。那么用go来做,得实现个go语言8583协议报文解析
且若想在电脑上跑交易,做个工具。用c语音处理起来不方便。用go还可以在电脑上跑交易。
于是用go语言做一个8583解析,方便使用
https://github.com/yangyongzhen/go8583/
package up8583 import ( "errors" "fmt" "go8583/byteutil" "go8583/desutil" "go8583/easy8583" "strconv" ) var ( ManNum string = "000000000000000" PosNum string = "00000000" MainKey string = "00000000000000000000000000000000" TPDU string = "6000000000" CommSn int = 1 RecSn int = 1 PiciNum []byte = make([]byte, 3) LicenceNum = []byte{0x33, 0x30, 0x36, 0x30} MacKey string = "0000000000000000" ) type Up8583 struct { Ea *easy8583.Easy8583 } 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("%06d", CommSn) field[10].Data = byteutil.HexStringToBytes(sn) //41域,终端号 field[40].Ihave = true field[40].Len = 8 field[40].Data = []byte(PosNum) //42域,商户号 field[41].Ihave = true field[41].Len = 15 field[41].Data = []byte(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:], 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:], LicenceNum, 4) memcpy(field[61].Data[17:], []byte(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() 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("%02x%02x", 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 := desutil.Des3Decrypt(data, byteutil.HexStringToBytes(MainKey)) if err != nil { return errors.New("1" + err.Error()) } //解密后的结果对8Byte全0做3DES加密运算 tmp := make([]byte, 8) out, err := desutil.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 := desutil.Des3Decrypt(data, byteutil.HexStringToBytes(MainKey)) if err != nil { return errors.New("3" + err.Error()) } out, err = desutil.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(PiciNum, fieldr[59].Data[1:], 3) MacKey = byteutil.BytesToHexString(mackey[0:8]) fmt.Printf("mackey:%s\n", MacKey) up.Ea.SetMacKey(MacKey) return nil } /* 银联8583 二维码交易组包 */ func (up *Up8583) Frame8583Qrcode(qrcode string, money 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 = byteutil.HexStringToBytes(fmt.Sprintf("%012d", money)) //11域,受卡方系统跟踪号BCD 通讯流水 field[10].Ihave = true field[10].Len = 3 sn := fmt.Sprintf("%06d", RecSn) field[10].Data = byteutil.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(PosNum) //42域,商户号 field[41].Ihave = true field[41].Len = 15 field[41].Data = []byte(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:], 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.Ea.Tpdu = byteutil.HexStringToBytes(TPDU) return up } /* 银联8583 电子现金交易组包 */ //获取55域 IC卡数据域 /* 9F26 08 9F27 01 9F10 9F37 04 9F36 02 95 05 9A 03 9C 01 9F02 06 5F2A 02 82 02 9F1A 02 9F03 06 9F33 03 9F1E 08 84 9F09 02 9F41 04 9F34 03 9F35 01 9F63 10 9F74 06 8A 02 */ func getfield55() { } func (up *Up8583) Frame8583UpCash(cardbin string, money int, cardvailddata string, cardholdsn string, field55 []byte) { s := up.Ea field := up.Ea.Field_S s.Init8583Fields(field) //消息类型 s.Msgtype[0] = 0x02 s.Msgtype[1] = 0x00 //2域 卡号 field[1].Ihave = true tmp := fmt.Sprintf("%02d", len(cardbin)) t, _ := strconv.ParseInt(tmp, 16, 16) if len(cardbin)%2 != 0 { cardbin += "0" } field[1].Len = int(t) field[1].Data = byteutil.HexStringToBytes(cardbin) //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 = byteutil.HexStringToBytes(fmt.Sprintf("%012d", money)) //11域,受卡方系统跟踪号BCD 通讯流水 field[10].Ihave = true field[10].Len = 3 sn := fmt.Sprintf("%06d", RecSn) field[10].Data = byteutil.HexStringToBytes(sn) //14域 卡有效期,能获取到时存在 if len(cardvailddata) > 0 { field[13].Ihave = true field[13].Len = 2 field[13].Data = byteutil.HexStringToBytes(cardvailddata) } //22域 field[21].Ihave = true field[21].Len = 2 field[21].Data = []byte{0x07, 0x20} //23域,卡序列号 能获取时存在 if len(cardholdsn) > 0 { field[22].Ihave = true field[22].Len = 2 field[22].Data = byteutil.HexStringToBytes(cardholdsn) } //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(PosNum) //42域,商户号 field[41].Ihave = true field[41].Len = 15 field[41].Data = []byte(ManNum) //49域 交易货币代码 field[48].Ihave = true field[48].Len = 3 field[48].Data = []byte{0x31, 0x35, 0x36} //55域 IC卡数据域 field[54].Ihave = true tmp = fmt.Sprintf("%04d", len(field55)) b := byteutil.HexStringToBytes(tmp) field[54].Len = int(b[0])<<8 | int(b[1]) field[54].Data = field55 //60域 field[59].Ihave = true field[59].Len = 0x13 field[59].Data = make([]byte, 7) field[59].Data[0] = 0x36 memcpy(field[59].Data[1:], PiciNum, 3) field[59].Data[4] = 0x00 field[59].Data[5] = 0x06 field[59].Data[6] = 0x00 //63域 field[62].Ihave = true field[62].Len = 0x03 field[62].Data = make([]byte, 3) memcpy(field[62].Data, []byte("CUP"), 3) //MAC,64域 field[63].Ihave = true field[63].Len = 0x08 field[63].Data = make([]byte, 8) //这个域要求填MAC,只需按这样填,MAC的计算在pack8583Fields自动完成了 /*报文组帧,自动组织这些域到Pack的TxBuffer中*/ s.Pack8583Fields() } func (up *Up8583) Ans8583UpCash(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("解析失败") r.PrintFields(fieldr) 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("%02x%02x", 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 ") } //MAC验证 mac, err := easy8583.UpGetMac(rxbuf[13:], rxlen-13-8, easy8583.MacKey) if err != nil { fmt.Println(err) panic("calc mac error!") } if !equals(fieldr[63].Data, mac) { return errors.New("error,mac check err") } return nil } func main() { fmt.Println("test...") up := NewUp8583() //up.Frame8583QD() //recvstr := "007960000001386131003111080810003800010AC0001450021122130107200800085500323231333031343931333239303039393939393930363030313433303137303131393939390011000005190030004046F161A743497B32EAC760DF5EA57DF5900ECCE3977731A7EA402DDF0000000000000000CFF1592A" //recv := byteutil.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(byteutil.BytesToHexString(up.Ea.Txbuf)) up.Frame8583Qrcode("6220485073630469936", 1) up.Ea.PrintFields(up.Ea.Field_S) }
/** * Created by yangyongzhen on 2019/01/11 * simple 8583 Protocol Analysis */ package easy8583 import ( "bytes" "fmt" "strconv" ) type Field struct { Ihave bool //是否存在该域 Ltype int //长度类型 (NOVAR,LLVAR,LLLVAR) Dtype int //数据类型 (BCD,ASCII) Len int //域的数据内容的长度 Data []byte //域的有效数据 } type Easy8583 struct { Len []byte Tpdu []byte Head []byte Msgtype []byte Bitmap []byte Txbuf []byte Field_S []Field //发送的域 Field_R []Field //接收的域 } //定义枚举类型 长度类型定义 const ( NOVAR = iota //value = 0,定长, LLVAR //value = 1,长度为1字节 LLLVAR //value = 2,长度为2字节 ) //定义枚举类型 数据类型定义 const ( UN = iota //value = 0, 未定义,定长的域无需关注类型 BIN //value = 1,BIN BCD //value = 2,BCD ) //各个域的初始配置 func (ea *Easy8583) Init8583Fields(fds []Field) { for i := 0; i < 64;i++ { fds[i].Ihave = false } fds[0].Ltype = 0 fds[1].Ltype = LLVAR //LLVAR fds[1].Dtype = BCD fds[2].Ltype = 0 fds[2].Len = 3 fds[3].Ltype = 0 fds[3].Len = 6 fds[10].Ltype = 0 fds[10].Len = 3 fds[11].Ltype = 0 fds[11].Len = 3 fds[12].Ltype = 0 fds[12].Len = 2 fds[13].Ltype = 0 fds[13].Len = 2 fds[14].Ltype = 0 fds[14].Len = 2 fds[21].Ltype = 0 fds[21].Len = 2 fds[22].Ltype = 0 fds[22].Len = 2 fds[24].Ltype = 0 fds[24].Len = 1 fds[25].Ltype = 0 fds[25].Len = 1 fds[31].Ltype = LLVAR //LLVAR fds[31].Dtype = BCD fds[34].Ltype = LLVAR //LLVAR fds[34].Dtype = BCD fds[36].Ltype = 0 fds[36].Len = 12 fds[37].Ltype = 0 fds[37].Len = 6 fds[38].Ltype = 0 fds[38].Len = 2 fds[39].Ltype = LLVAR fds[40].Ltype = 0 fds[40].Len = 8 fds[41].Ltype = 0 fds[41].Len = 15 fds[43].Ltype = LLVAR fds[47].Ltype = LLLVAR fds[47].Dtype = BCD fds[48].Ltype = 0 fds[48].Len = 3 fds[51].Ltype = 0 fds[51].Len = 8 fds[52].Ltype = 0 fds[52].Len = 8 fds[54].Ltype = LLLVAR //LLLVAR fds[58].Ltype = LLLVAR fds[59].Ltype = LLLVAR fds[59].Dtype = BCD fds[60].Ltype = LLLVAR fds[60].Dtype = BCD fds[61].Ltype = LLLVAR fds[62].Ltype = LLLVAR fds[63].Ltype = 0 fds[63].Len = 8 } /* 构造函数,初始化 */ func New8583() *Easy8583 { var ea = new(Easy8583) ea.Txbuf = make([]byte, 0, 1024) ea.Txbuf = ea.Txbuf[0:23] ea.Len = []byte{0x00, 0x00} ea.Tpdu = []byte{0x60, 0x05, 0x01, 0x00, 0x00} ea.Head = []byte{0x61, 0x31, 0x00, 0x31, 0x11, 0x08} ea.Msgtype = []byte{0x08, 0x00} ea.Bitmap = make([]byte, 8) ea.Field_S = make([]Field,64) ea.Field_R = make([]Field,64) ea.Init8583Fields(ea.Field_S) ea.Init8583Fields(ea.Field_R) return ea } func memcpy(dst, src []byte, size int) { for i := 0; i < size; i++ { dst[i] = src[i] } return } func bytesToHexStr(data []byte, lenth int) string { buf := data[0:lenth] hexStr := fmt.Sprintf("%x", buf) //fmt.Println(hexStr) return hexStr } // bytes to hex string func bytesToHexString(b []byte) string { var buf bytes.Buffer for _, v := range b { t := strconv.FormatInt(int64(v), 16) if len(t) > 1 { buf.WriteString(t) } else { buf.WriteString("0" + t) } } return buf.String() } // hex string to bytes func hexStringToBytes(s string) []byte { bs := make([]byte, 0) for i := 0; i < len(s); i = i + 2 { b, _ := strconv.ParseInt(s[i:i+2], 16, 16) bs = append(bs, byte(b)) } return bs } //例:0x19 --> 19, 0x0119 -> 119 func bcdToInt(data []byte, lenth int) int { buf := data[0:lenth] hexStr := fmt.Sprintf("%x", buf) out, _ := strconv.ParseInt(hexStr, 10, 32) return int(out) } func toZero(p []byte) { for i := range p { p[i] = 0 } } /* 8583报文打包 */ func (ea *Easy8583) Pack8583Fields() int { fmt.Printf("pack 8583 fields\n") //ea.Txbuf[] ea.Txbuf = ea.Txbuf[0:23] toZero(ea.Txbuf) memcpy(ea.Txbuf[2:], ea.Tpdu, 5) memcpy(ea.Txbuf[7:], ea.Head, 6) memcpy(ea.Txbuf[13:], ea.Msgtype, 2) memcpy(ea.Txbuf[15:], ea.Bitmap, 8) j := 0 len := 23 tmplen := 0 seat := 0x80 for i := 0; i < 64; i++ { seat = (seat >> 1) if (i % 8) == 0 { j++ seat = 0x80 } if ea.Field_S[i].Ihave { ea.Bitmap[j-1] |= byte(seat) if ea.Field_S[i].Ltype == NOVAR { ea.Txbuf = ea.Txbuf[0 : len+ea.Field_S[i].Len] memcpy(ea.Txbuf[len:], ea.Field_S[i].Data, ea.Field_S[i].Len) len += ea.Field_S[i].Len } else if ea.Field_S[i].Ltype == LLVAR { ea.Txbuf = ea.Txbuf[0 : len+1] ea.Txbuf[len] = byte(ea.Field_S[i].Len) tmplen = bcdToInt(ea.Txbuf[len:],1) if ea.Field_S[i].Dtype == BCD { tmplen = ((tmplen/2) + (tmplen%2)) } len += 1 ea.Txbuf = ea.Txbuf[0 : len+tmplen] memcpy(ea.Txbuf[len:], ea.Field_S[i].Data, tmplen) len += tmplen } else if ea.Field_S[i].Ltype == LLLVAR { ea.Txbuf = ea.Txbuf[0 : len+2] ea.Txbuf[len] = byte(ea.Field_S[i].Len>>8) ea.Txbuf[len+1] = byte(ea.Field_S[i].Len) tmplen = bcdToInt(ea.Txbuf[len:],2) if ea.Field_S[i].Dtype == BCD { tmplen = ((tmplen/2) + (tmplen%2)) } len += 2 ea.Txbuf = ea.Txbuf[0 : len+tmplen] memcpy(ea.Txbuf[len:], ea.Field_S[i].Data, tmplen) len += tmplen } } //报文总长度 ea.Txbuf[0] = byte((len-2)>>8) ea.Txbuf[1] = byte((len-2)) memcpy(ea.Len,ea.Txbuf,2) } return 0 } /* 8583报文解包 */ func (ea *Easy8583) Ans8583Fields( rxbuf []byte,rxlen int) int { fmt.Printf("ans 8583 fields\n") ea.Init8583Fields(ea.Field_R) len := 0 tmplen := 0 bitMap := make([]byte,8) var seat,buf uint64 = 1,0 memcpy(bitMap,rxbuf[15:],8) memcpy(ea.Len,rxbuf[0:],2) //memcpy(ea.Tpdu,rxbuf[2:],5) memcpy(ea.Head,rxbuf[7:],6) memcpy(ea.Msgtype,rxbuf[13:],2) memcpy(ea.Bitmap,rxbuf[15:],8) len += 23 for i := 0;i < 8;i++ { buf = ((buf<<8) | uint64(bitMap[i])) } for i := 0; i < 64; i++ { if (buf & (seat << uint(63 - i))) > 0 { ea.Field_R[i].Ihave = true if ea.Field_R[i].Ltype == NOVAR { ea.Field_R[i].Data = make([]byte,ea.Field_R[i].Len) memcpy(ea.Field_R[i].Data, rxbuf[len:], ea.Field_R[i].Len) len += ea.Field_R[i].Len } else if ea.Field_R[i].Ltype == LLVAR { ea.Field_R[i].Len = int(rxbuf[len]) tmplen = bcdToInt(rxbuf[len:],1) if ea.Field_R[i].Dtype == BCD { tmplen = ((tmplen/2) + (tmplen%2)) } len += 1 ea.Field_R[i].Data = make([]byte,tmplen) memcpy(ea.Field_R[i].Data, rxbuf[len:], tmplen) len += tmplen } else if ea.Field_R[i].Ltype == LLLVAR { ea.Field_R[i].Len = ( ( int(rxbuf[len])<<8 ) | int(rxbuf[len+1] ) ) tmplen = bcdToInt(rxbuf[len:],2) if ea.Field_R[i].Dtype == BCD { tmplen = ((tmplen/2) + (tmplen%2)) } len += 2 ea.Field_R[i].Data = make([]byte,tmplen) memcpy(ea.Field_R[i].Data, rxbuf[len:], tmplen) len += tmplen } } } if(len > rxlen){ return 1; } return 0 } /* 打印信息,调试用 */ func (ea *Easy8583) PrintFields(fds []Field){ fmt.Println("Print fields...") fmt.Printf("\n==========================================\n") fmt.Printf("Len:\t%s\n", bytesToHexString(ea.Len)) fmt.Printf("Tpdu:\t%s\n", bytesToHexString(ea.Tpdu)) fmt.Printf("Head:\t%s\n", bytesToHexString(ea.Head)) fmt.Printf("Msge:\t%s\n", bytesToHexString(ea.Msgtype)) fmt.Printf("Bitmap:\t%s\n", bytesToHexString(ea.Bitmap)) fmt.Printf("\n==========================================\n") for i:=0; i < 64; i++{ if fds[i].Ihave { fmt.Printf("[field:%d] ",i+1) if fds[i].Ltype == LLVAR{ fmt.Printf("[len:%02x] ",fds[i].Len) }else if fds[i].Ltype == LLLVAR{ fmt.Printf("[len:%04x] ",fds[i].Len) } fmt.Printf("[%s]\n",bytesToHexString(fds[i].Data)) fmt.Printf("\n------------------------------\n") } } } func main() { fmt.Println("test...") }