java版银联8583协议解析,超简单超直观的实现及示例

一直以来做嵌入式软件开发,跟银联8583协议通信打交道太多了。

最近有需要把8383协议的解析用到android上,但是搜遍了整个互联网,没发现有哪个简单好用点的java版8583解析库。就自己动手自己做一个吧,让其尽可能的简单,直观

如果在这个互联网上谁遇到过比这个还简单直观的,请留言我,我观摩下再进一步改进。

来做个对比,J8583CN :中国版的8583报文Java实现,实现了对8583报文创建、编辑、读写、解析。使用起来比较简单,且能灵活配置。 j8583cn 的报文标准参考了中国银联2.0和部分商行的标准。代码参考了源j8583程序

附带J8583CN的下载链接:https://sourceforge.net/projects/j8583cn/?source=typ_redirect

这份代码我下载下来了看,在懂8383协议的基础上一时半会儿也没看明白怎么用的,也不想花时间研究他了

我的github地址

https://github.com/yangyongzhen/Easy8583Ans.git

以下来看一个银联签到报文的组包:

不用关注BitMap如何填,如何组织,不用关注报文结构和长度,只需要根据协议填 你需要的域就行啦!

就是这么简单,filed[0] 到filed[63] 分别对应 1到 64域。

有多么简单?有多么直观? 

请看以下签到报文组包示例:

/**
 * 签到报文组帧 yangyongzhen add 180627
 * @param field
 * @param tx
 */
public void frame8583QD( __8583Fields[] field, Pack tx){
init8583Fields(<span style="color:#9876aa;">fieldsSend</span>)<span style="color:#cc7832;">;

//消息类型
tx.msgType[0] = 0x08;
tx.msgType[1] = 0x00;
//11域,受卡方系统跟踪号BCD 通讯流水
field[10].ishave = 1;
field[10].len = 3;
String tmp = String.format("%06d",commSn);
field[10].data = hexStringToBytes(tmp);
//41域,终端号
field[40].ishave = 1;
field[40].len = 8;
field[40].data = posNum.getBytes();
//42域,商户号
field[41].ishave = 1;
field[41].len = 15;
field[41].data = manNum.getBytes();
//60域
field[59].ishave = 1;
field[59].len = 0x11;
field[59].data = new byte[6];
field[59].data[0] = 0x00;
arraycopy(piciNum,0,field[59].data,1,3);
field[59].data[4] = 0x00;
field[59].data[5] = 0x30;
//62域
field[61].ishave = 1;
field[61].len = 0x25;
field[61].data = new byte[25];
String str = “Sequence No12”;
arraycopy(str.getBytes(),0,field[61].data,0,13);
arraycopy(licenceNum,0,field[61].data,13,4);
arraycopy(posNum.getBytes(),0,field[61].data,17,8);
//63域
field[62].ishave = 1;
field[62].len = 0x03;
field[62].data = new byte[3];
field[62].data[0] = 0x30;
field[62].data[1] = 0x30;
field[62].data[2] = 0x31;
/报文组帧,自动组织这些域到Pack的TxBuffer中/
pack8583Fields(field,tx);
commSn++; //通讯流水每次加一
}

/**
* 8583签到的响应报文解析
* @param rxbuf
* @param rxlen
* @return 0,成功 非0,失败
*/
public int ans8583QD(byte[] rxbuf,int rxlen){

<span style="color:#cc7832;">int </span>ret = <span style="color:#6897bb;">0</span><span style="color:#cc7832;">;

ret = ans8583Fields(rxbuf,rxlen,fieldsRecv);
if(ret != 0) {
//Log.d(TAG,“解析失败!”);
System.out.println("<-Er 解析失败!");
return ret;
}
//Log.d(TAG,“解析成功!”);
System.out.println("->ok 解析成功!");
//消息类型判断
if((pack.msgType[0] != 0x08)||(pack.msgType[1]!= 0x10)) {
//Log.d(TAG,“消息类型错!”);
return 2;
}
//应答码判断
if((fieldsRecv[38].data[0] != 0x30)||(fieldsRecv[38].data[1] != 0x30)){
//Log.d(TAG,“应答码不正确!”);
//Log.d(TAG,String.format(“应答码:%02x%02x”,fieldsRecv[38].data[0],fieldsRecv[38].data[1]));
return 3;
}
//跟踪号比较
if(!Arrays.equals(fieldsSend[10].data,fieldsRecv[10].data)){
//return 4;
}
//终端号比较
if(!Arrays.equals(fieldsSend[40].data,fieldsRecv[40].data)){
//return 5;
}
//商户号比较
if(!Arrays.equals(fieldsSend[41].data,fieldsRecv[41].data)){
//return 6;
}
//3DES解密PIN KEY
byte[] data = new byte[16];
arraycopy(fieldsRecv[61].data,0,data,0,16);
byte[] pinkey = DES_decrypt_3(data,hexStringToBytes(mainKey));
//解密后的结果对8Byte全0做3DES加密运算
System.out.println(“pinkey:”+bytesToHexString(pinkey));
byte[] tmp= {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
byte[] out = DES_encrypt_3(tmp,pinkey);
//对比pincheck是否一致
byte[] check = new byte[4];
byte[] pincheck = new byte[4];
arraycopy(out,0,check,0,4);
arraycopy(fieldsRecv[61].data,16,pincheck,0,4);
if(!Arrays.equals(check,pincheck)) {
System.out.println("<-Er PIK错误");
return 7;
}
else {
System.out.println("<-ok PIK正确");
}
//3DES解密MAC KEY
arraycopy(fieldsRecv[61].data,20,data,0,16);
byte[] mackey = DES_decrypt_3(data,hexStringToBytes(mainKey));
//解密后的结果对8Byte全0做DES加密运算
System.out.println(“mackey:”+bytesToHexString(mackey));
out = DES_encrypt(tmp,mackey);

byte[] maccheck = new byte[4];
arraycopy(out,0,check,0,4);
arraycopy(fieldsRecv[61].data,36,maccheck,0,4);
if(!Arrays.equals(check,maccheck)) {
System.out.println("<-Er MAC错误");
return 8;
}
else {
System.out.println("<-ok MAC正确");
setMacKey(bytesToHexString(mackey));
}
//签到成功
return 0;
}

最终组织好的报文在哪呢?在报文结构类Pack中的Txbuffer中,长度为Txlen

关键方法

pack8583Fields

它完成自动的配置位图和计算长度,并把组织好的报文放到TxBuffer中,供通信发送使用。

解析部分关键方法

ans8583Fields

它完成自动解析收到的报文,把各个解析出来的域和长度放到fieldRecv的各个域中。

需要外部设置的参数在哪放?

外部需要配置的有:终端号,商户号,主秘钥,TPDU。这些在类里定义的有set和get方法。

请看 报文结构类定义:

/**
* Created by yangyongzhen on 2018/06/27
* simple 8583 Protocol Analysis
*/
public class Easy8583Ans {
<span style="color:#cc7832;">private static final </span>String <span style="color:#9876aa;"><em>TAG</em></span>= <span style="color:#6a8759;">" Easy8583Ans"</span><span style="color:#cc7832;">;

private static String macKey ; //工作秘钥

public static void setMacKey(String macKey) {
Easy8583Ans.macKey = macKey;
}
public static String getMacKey() {
return macKey;
}
/**
* 定义8583的报文协议包结构 Len+Tpdu+Head+MsgType+BitMap+Data
*/
public class Pack {

    <span style="color:#cc7832;">public byte</span>[] <span style="color:#9876aa;">len</span><span style="color:#cc7832;">;

public byte[] tpdu;
public byte[] head;
public byte[] msgType;
public byte[] bitMap;

public byte[] txBuffer;
public int txLen;
public Pack() {
len = new byte[2];
tpdu = new byte[]{0x60, 0x05, 0x01, 0x00, 0x00};
head = new byte[]{0x61, 0x31, 0x00, 0x31, 0x11,0x08};//这几项一般固定,不会变动
msgType = new byte[2];
bitMap = new byte[8];
txBuffer = new byte[1024];
txLen = 0;
}

    <span style="color:#bbb529;">@Override

public String toString() {
return “Pack{” +
“len=” + bytesToHexString(len) +
“, tpdu=” + bytesToHexString(tpdu) +
“, head=” + bytesToHexString(head) +
“, msgType=” + bytesToHexString(msgType) +
“, bitMap=” + bytesToHexString(bitMap) +
“, txLen=” + txLen +
“, txBuffer=” + bytesToHexString(txBuffer) +
‘}’;
}
}

<span style="color:#629755;"><em>/**

* 域定义
*/
public class __8583Fields {
int ishave; /是否存在/
int type; /类型(取值范围0-2,组帧时0:表示不计长度 1:表示长度占1字节,2:表示2长度占2字节)/
int len; /域长度(需根据各个域的定义要求正确取值)/
byte[] data; /域内容/
__8583Fields()
{
ishave = 0;
type = 0;
len = 0;
data =null;
}
}

<span style="color:#cc7832;">public </span>__8583Fields[] <span style="color:#9876aa;">fieldsSend</span><span style="color:#cc7832;">; </span><span style="color:#808080;">//发送的域

public __8583Fields[] fieldsRecv; //接收的域
public Pack pack;

public Easy8583Ans()
{
fieldsSend = new __8583Fields[64];
fieldsRecv = new __8583Fields[64];
pack = new Pack();
init8583(fieldsSend);
init8583(fieldsRecv);
init8583Fields(fieldsSend);
init8583Fields(fieldsRecv);
}

如何发送报文给银联后台呢?

假如你通信有Send(byte[] sendbuf, int len) 方法

那么只需 Send(pack.TxBuffer,pack.TxLen)

想打印出来报文日志在哪看? 直接pack.ToString()即可

附带一个调用的demo:

public static void main(String[] args) {
My8583Ans myans = new My8583Ans();
//签到组包
myans.frame8583QD(myans.fieldsSend,myans.pack);
//打印出待发送的报文
byte[] send = new byte[myans.pack.txLen];
arraycopy(myans.pack.txBuffer,0,send,0,myans.pack.txLen);
System.out.println("->send:");
System.out.println(My8583Ans.bytesToHexString(send));
System.out.println(myans.pack.toString());
System.out.println(myans.getFields(myans.fieldsSend));
//接收解析,假设收到的报文在recv中
String recvstr =“007960000001386131003111080810003800010AC0001450021122130107200800085500323231333031343931333239303039393939393930363030313433303137303131393939390011000005190030004046F161A743497B32EAC760DF5EA57DF5900ECCE3977731A7EA402DDF0000000000000000CFF1592A”;
System.out.println("->recv:"+recvstr);
byte[] recv = My8583Ans.hexStringToBytes(recvstr);
// mypack.ans8583Fields(bt,bt.length,mypack.fieldsRecv);
//解析
System.out.println(“开始解析…”);
int ret = myans.ans8583QD(recv,recv.length);
if(ret == 0){
//打印出解析成功的各个域
System.out.println(“签到成功!”);
System.out.println(myans.getFields(myans.fieldsRecv));
}

做了个getDields方法打印出了各个域的信息。

输出结果如下,连带每个域的日志都有了,够简单直观了吧:
 com.example.yang.myapplication.My8583Ans
->send:

0057600501000061310031110808000020000000c0001600000139393939393930363030313433303137303131393939390011000000000030002553657175656e6365204e6f31323330363039393939393930360003303031

Pack{len=0057, tpdu=6005010000, head=613100311108, msgType=0800, bitMap=0020000000c00016, txLen=89, txBuffer=0057600501000061310031110808000020000000c0001600000139393939393930363030313433303137303131393939390011000000000030002553657175656e6365204e6f31323330363039393939393930360003303031}
Len: 0057
TPDU: 6005010000
Head: 613100311108
MsgType: 0800
BitMap: 0020000000c00016
-------------------------------------------------
[field:11] [000001]
-------------------------------------------------
[field:41] [3939393939393036]
-------------------------------------------------
[field:42] [303031343330313730313139393939]
-------------------------------------------------
[field:60] [len:0011] [000000000030]
-------------------------------------------------
[field:62] [len:0025] [53657175656e6365204e6f3132333036303939393939393036]
-------------------------------------------------
[field:63] [len:0003] [303031]
-------------------------------------------------
----------------------------------------------------------------------------------------------------

->recv:

007960000001386131003111080810003800010AC0001450021122130107200800085500323231333031343931333239303039393939393930363030313433303137303131393939390011000005190030004046F161A743497B32EAC760DF5EA57DF5900ECCE3977731A7EA402DDF0000000000000000CFF1592A

开始解析…
->ok 解析成功!
pinkey:d931648f3de313a4a22c15dca4f4299e
<-ok PIK正确
mackey:ab7c577cc7a180455fc2a085d7208a04
<-ok MAC正确
签到成功!
Len: 0079
TPDU: 6000000138
Head: 613100311108
MsgType: 0810
BitMap: 003800010ac00014
-------------------------------------------------
[field:11] [500211]
-------------------------------------------------
[field:12] [221301]
-------------------------------------------------
[field:13] [0720]
-------------------------------------------------
[field:32] [len:08] [00085500]
-------------------------------------------------
[field:37] [323231333031343931333239]
-------------------------------------------------
[field:39] [3030]
-------------------------------------------------
[field:41] [3939393939393036]
-------------------------------------------------
[field:42] [303031343330313730313139393939]
-------------------------------------------------
[field:60] [len:0011] [000005190030]
-------------------------------------------------
[field:62] [len:0040] [46f161a743497b32eac760df5ea57df5900ecce3977731a7ea402ddf0000000000000000cff1592a]

-------------------------------------------------

附带一个使用retrofit网络库访问的输出结果:

D/OkHttp: --> POST https://1xx.xx.xx.xx:xxxx/ http/1.1
          Content-Type: x-ISO-TPDU/x-auth
D/OkHttp: Content-Length: 89
          User-Agent: Donjin Http 0.1
          Cache-Control: no-cache
          Accept-Encoding:
D/OkHttp: Host: xxx.xxx.xxx.xx:xxxx
          Connection: Keep-Alive
          --> END POST
D/OkHttp: <-- 200 OK https://xxx.xxx.xxx.xx:xxxx/ (421ms)
D/OkHttp: Allow: POST, PUT
          Content-Type: x-ISO-TPDU/x-auth
          Date: Sat, 30 Jun 2018 09:58:41 GMT
D/OkHttp: Content-Length: 123
D/OkHttp: Server: Access-Guard-1000-Software/1.0
          Connection: close
          <-- END HTTP
D/AA: 成功
      Response{protocol=http/1.1, code=200, message=OK, url=https://xxxxxxxx:xxxxx/}
D/respondAA:: 007960000005016131003111080810003800010ac0001400000117563506300800094900313735363335353837303233303037333738323231343839383431313334313331303031340011000007500030004050bc9eb4774a92544c29dad2c764150bb93eba92d9f11a222efa9c2300000000000000002b580802
I/System.out: 开始解析…
I/System.out: ->ok 解析成功!
I/System.out: pinkey:b1a7ab3cb49c9757390f39a19ce71ae7
I/System.out: <-Er PIK错误

源码如下:
/*
* Created by yangyongzhen on 2018/06/30
* simple 8583 Protocol Analysis,业务处理
*/
public class My8583Ans extends Easy8583Ans {
<span style="color:#cc7832;">private static final </span>String <span style="color:#9876aa;"><em>TAG</em></span>= <span style="color:#6a8759;">" My8583Ans"</span><span style="color:#cc7832;">;


//通信涉及到的一些参数,内部使用
private static long commSn = 1; //通讯流水号
private static byte[] piciNum = new byte[3];//批次号
private static byte[] licenceNum = {0x33,0x30,0x36,0x30};//入网许可证编号

//需要外部设置的参数有:商户号,终端号,主秘钥,TPDU(以下的为默认值,并提供set和get方法)
//需要持久化存储这些参数,每次使用时加载
private static String manNum = “898411341310014”; //商户号
private static String posNum = “73782214”; //终端号
private static String mainKey = “258FB0Ab70D025CDB99DF2C4D302D646”; //主秘钥
private static String TPDU = “6005010000”;
private static long posSn = 1; //终端交易流水
My8583Ans(){

    <span style="color:#808080;">//通过子类修改父类的配置

pack.tpdu = hexStringToBytes(TPDU);
}
/**
* 签到报文组帧
* @param field
* @param tx
*/
public void frame8583QD( __8583Fields[] field, Pack tx){

    init8583Fields(<span style="color:#9876aa;">fieldsSend</span>)<span style="color:#cc7832;">;

//消息类型
tx.msgType[0] = 0x08;
tx.msgType[1] = 0x00;
//11域,受卡方系统跟踪号BCD 通讯流水
field[10].ishave = 1;
field[10].len = 3;
String tmp = String.format("%06d",commSn);
field[10].data = hexStringToBytes(tmp);
//41域,终端号
field[40].ishave = 1;
field[40].len = 8;
field[40].data = posNum.getBytes();
//42域,商户号
field[41].ishave = 1;
field[41].len = 15;
field[41].data = manNum.getBytes();
//60域
field[59].ishave = 1;
field[59].len = 0x11;
field[59].data = new byte[6];
field[59].data[0] = 0x00;
arraycopy(piciNum,0,field[59].data,1,3);
field[59].data[4] = 0x00;
field[59].data[5] = 0x30;
//62域
field[61].ishave = 1;
field[61].len = 0x25;
field[61].data = new byte[25];
String str = “Sequence No12”;
arraycopy(str.getBytes(),0,field[61].data,0,13);
arraycopy(licenceNum,0,field[61].data,13,4);
arraycopy(posNum.getBytes(),0,field[61].data,17,8);
//63域
field[62].ishave = 1;
field[62].len = 0x03;
field[62].data = new byte[3];
field[62].data[0] = 0x30;
field[62].data[1] = 0x30;
field[62].data[2] = 0x31;
/报文组帧,自动组织这些域到Pack的TxBuffer中/
pack8583Fields(field,tx);
commSn++; //通讯流水每次加一
}

package com.example.yang.myapplication;

import java.util.Arrays;
import static com.example.yang.myapplication.DesUtil.DES_encrypt;
import static java.lang.System.arraycopy;
/**
* Created by yangyongzhen on 2018/06/27
* simple 8583 Protocol Analysis
*/
public class Easy8583Ans {
<span style="color:#cc7832;">private static final </span>String <span style="color:#9876aa;"><em>TAG</em></span>= <span style="color:#6a8759;">" Easy8583Ans"</span><span style="color:#cc7832;">;

private static String macKey ; //工作秘钥

public static void setMacKey(String macKey) {
Easy8583Ans.macKey = macKey;
}
public static String getMacKey() {
return macKey;
}
/**
* 定义8583的报文协议包结构 Len+Tpdu+Head+MsgType+BitMap+Data
*/
public class Pack {

    <span style="color:#cc7832;">public byte</span>[] <span style="color:#9876aa;">len</span><span style="color:#cc7832;">;

public byte[] tpdu;
public byte[] head;
public byte[] msgType;
public byte[] bitMap;

public byte[] txBuffer;
public int txLen;
public Pack() {
len = new byte[2];
tpdu = new byte[]{0x60, 0x05, 0x01, 0x00, 0x00};
head = new byte[]{0x61, 0x31, 0x00, 0x31, 0x11,0x08};//这几项一般固定,不会变动
msgType = new byte[2];
bitMap = new byte[8];
txBuffer = new byte[1024];
txLen = 0;
}

    <span style="color:#bbb529;">@Override

public String toString() {
return “Pack{” +
“len=” + bytesToHexString(len) +
“, tpdu=” + bytesToHexString(tpdu) +
“, head=” + bytesToHexString(head) +
“, msgType=” + bytesToHexString(msgType) +
“, bitMap=” + bytesToHexString(bitMap) +
“, txLen=” + txLen +
“, txBuffer=” + bytesToHexString(txBuffer) +
‘}’;
}
}

<span style="color:#629755;"><em>/**

* 域定义
*/
public class __8583Fields {
int ishave; /是否存在/
int type; /类型(取值范围0-2,组帧时0:表示不计长度 1:表示长度占1字节,2:表示2长度占2字节)/
int len; /域长度(需根据各个域的定义要求正确取值)/
byte[] data; /域内容/
__8583Fields()
{
ishave = 0;
type = 0;
len = 0;
data =null;
}
}

<span style="color:#cc7832;">public </span>__8583Fields[] <span style="color:#9876aa;">fieldsSend</span><span style="color:#cc7832;">; </span><span style="color:#808080;">//发送的域

public __8583Fields[] fieldsRecv; //接收的域
public Pack pack;

public Easy8583Ans()
{
fieldsSend = new __8583Fields[64];
fieldsRecv = new __8583Fields[64];
pack = new Pack();
init8583(fieldsSend);
init8583(fieldsRecv);
init8583Fields(fieldsSend);
init8583Fields(fieldsRecv);
}

<span style="color:#629755;"><em>/**

* 各个域的配置,初始化
* @param field
*/
private void init8583(__8583Fields[] field){
for(int i = 0; i < 64; i++)
{
field[i] = new __8583Fields();
}
}
public void init8583Fields(__8583Fields[] field) {

    <span style="color:#cc7832;">for</span>(<span style="color:#cc7832;">int </span>i = <span style="color:#6897bb;">0</span><span style="color:#cc7832;">;</span>i &lt;<span style="color:#6897bb;">64</span><span style="color:#cc7832;">; </span>i++){
        field[i].<span style="color:#9876aa;">ishave </span>= <span style="color:#6897bb;">0</span><span style="color:#cc7832;">;

}
field[0].type = 0;
field[1].type = 1;//LLVAR

field[2].type = 0;
field[2].len = 3;

field[3].type = 0;
field[3].len = 6;

field[10].type = 0;
field[10].len = 3;

field[11].type = 0;
field[11].len = 3;

field[12].type = 0;
field[12].len = 2;

field[13].type = 0;
field[13].len = 2;
field[14].type = 0;
field[14].len = 2;

field[21].type = 0;
field[21].len = 2;
field[22].type = 0;
field[22].len = 2;

field[24].type = 0;
field[24].len = 1;
field[25].type = 0;
field[25].len = 1;

field[31].type = 1;//LLVAR

field[34].type = 1;//LLVAR

field[36].type = 0;
field[36].len = 12;

field[37].type = 0;
field[37].len = 6;
field[38].type = 0;
field[38].len = 2;

field[39].type = 1;

field[40].type = 0;
field[40].len = 8;
field[41].type = 0;
field[41].len = 15;

field[43].type = 1;

field[47].type = 2;
field[48].type = 0;
field[48].len = 3;
field[51].type = 0;
field[51].len = 8;
field[52].type = 0;
field[52].len = 8;

field[54].type = 2;//LLLVAR
field[58].type = 2;

field[59].type = 2;
field[60].type = 2;
field[61].type = 2;
field[62].type = 2;

field[63].type = 0;
field[63].len = 8;
}
/**
* 该方法不需要外部调用,该方法自动完成各个域的组包和BitMap的形成及报文长度的计算
* 该方法最终组织各个域中的内容到 Pack的TxBuffer中,形成一完整报文
* @param field
* @param pk
*/
public void pack8583Fields( __8583Fields[] field, Pack pk)
{
int j = 0;
int len = 23;
int tmplen = 0;
int seat = 0x80;

Arrays.fill(pack.txBuffer,(byte)0);

for(int i = 0;i < 64; i++) {
seat = (seat >>1 );
if((i%8) == 0) {
j++;
seat = 0x80;
}
if(field[i].ishave == 1) {
pk.bitMap[j-1] |= seat;//根据每个filed中的ishave是否为1,自动计算BitMap
if(field[i].type == 0){
//根据每个域的数据类型,自动截取长度组包
//System.out.println(“i = “+i);
arraycopy(field[i].data,0,pk.txBuffer,len,field[i].len);//数据
len += field[i].len;
}
else if(field[i].type == 1){
//域长度
pk.txBuffer[len] = (byte)field[i].len;
tmplen = Integer.parseInt(String.format(”%02x”,pk.txBuffer[len]),10);
//域数据
if((i==1)||(i==31)||(i==34)||(i==47)||(i==59)||(i==60))
{
tmplen = ((tmplen/2) + (tmplen%2));
}
len += 1;
arraycopy(field[i].data,0,pk.txBuffer,len,tmplen);//数据
len += tmplen;
}
else if(field[i].type == 2){
pk.txBuffer[len] = (byte)(field[i].len>>8);
pk.txBuffer[len+1] = (byte)field[i].len;
tmplen = Integer.parseInt(String.format("%02x%02x",pk.txBuffer[len],pk.txBuffer[len+1]),10);
if((i==1)||(i==31)||(i==34)||(i==47)||(i==59)||(i==60))
{
tmplen = ((tmplen/2) + (tmplen%2));
}
len += 2;
arraycopy(field[i].data,0,pk.txBuffer,len,tmplen);//数据
len += tmplen;
}

        }
    }
    pk.<span style="color:#9876aa;">txLen </span>= len<span style="color:#cc7832;">;

pk.len[0] = (byte)((len-2) << 8);
pk.len[1] = (byte)(len-2);

arraycopy(pk.len,0,pk.txBuffer,0,2);
arraycopy(pk.tpdu,0,pk.txBuffer,2,5);
arraycopy(pk.head,0,pk.txBuffer,7,6);
arraycopy(pk.msgType,0,pk.txBuffer,13,2);
arraycopy(pk.bitMap,0,pk.txBuffer,15,8);

//如果64域存在,自动计算MAC并填充
if(field[63].ishave == 1){
byte[] mac = upGetMac(pk.txBuffer,13,len-13-8,hexStringToBytes(macKey));
arraycopy(mac,0,pk.txBuffer,len-8,8);
arraycopy(mac,0,field[63].data,0,8);
}
}

<span style="color:#629755;"><em>/**

* 解析8583报文,解析成功后,可在fieldRecv中查看各个域
* @param rxbuf
* @param rxlen
* @param fieldrcv
* @return
*/
public int ans8583Fields( byte[] rxbuf,int rxlen,__8583Fields[] fieldrcv)
{
int len = 0;
int tmplen = 0;
long buf = 0,seat=1;
byte[] bitMap = new byte[8];

init8583Fields(fieldsRecv);

arraycopy(rxbuf,15,bitMap,0,8);
arraycopy(rxbuf,0,pack.len,0,2);
arraycopy(rxbuf,7,pack.head,0,6);
arraycopy(rxbuf,13,pack.msgType,0,2);
arraycopy(rxbuf,15,pack.bitMap,0,8);
len += 23;
for(int i = 0;i < 8;i++) {
buf = ((buf<<8) | (bitMap[i]&0xff));
}
for(int i = 0; i < 64; i++) {
if ((buf & (seat << (63 - i))) > 0) {
fieldrcv[i].ishave = 1;
if(fieldrcv[i].type == 0){
fieldrcv[i].data = new byte[fieldrcv[i].len];
arraycopy(rxbuf,len,fieldrcv[i].data,0,fieldrcv[i].len);
len += fieldrcv[i].len;
}
else if(fieldrcv[i].type == 1){
fieldrcv[i].len = rxbuf[len];
tmplen = Integer.parseInt(String.format("%02x",rxbuf[len]),10);
if((i==1)||(i==31)||(i==47)||(i==59)||(i==60))
{
tmplen = ((tmplen/2) + (tmplen%2));
}
len += 1;
fieldrcv[i].data = new byte[tmplen];
arraycopy(rxbuf,len,fieldrcv[i].data,0,tmplen);
len += tmplen;

}
else if(fieldrcv[i].type == 2){
fieldrcv[i].len = ((rxbuf[len]<<8) | rxbuf[len+1]);
tmplen = Integer.parseInt(String.format("%02x%02x",rxbuf[len],rxbuf[len+1]),10);
if((i==1)||(i==31)||(i==47)||(i==59)||(i==60))
{
tmplen = ((tmplen/2) + (tmplen%2));
}
len += 2;
fieldrcv[i].data = new byte[tmplen];
arraycopy(rxbuf,len,fieldrcv[i].data,0,tmplen);
len += tmplen;
}

        }
    }
    <span style="color:#cc7832;">if</span>(len &gt; rxlen)
    {
        <span style="color:#cc7832;">return </span><span style="color:#6897bb;">1</span><span style="color:#cc7832;">;

}
return 0;
}

<span style="color:#cc7832;">public </span>String <span style="color:#ffc66d;">getFields</span>( __8583Fields[] field){

    StringBuffer str= <span style="color:#cc7832;">new </span>StringBuffer()<span style="color:#cc7832;">;

str.append(String.format(“Len:\t%s\n”,bytesToHexString(pack.len)));
str.append(String.format(“TPDU:\t%s\n”,bytesToHexString(pack.tpdu)));
str.append(String.format(“Head:\t%s\n”,bytesToHexString(pack.head)));
str.append(String.format(“MsgType:\t%s\n”,bytesToHexString(pack.msgType)));
str.append(String.format(“BitMap:\t%s\n”,bytesToHexString(pack.bitMap)));
str.append("-------------------------------------------------\n");
for(int i = 0; i < 64; i++) {
if(field[i].ishave == 1) {
str.append(String.format("[field:%d] “, i+1));
if(field[i].type == 1) {
str.append(String.format(”[len:%02x] “, field[i].len));
}else if(field[i].type == 2){
str.append(String.format(”[len:%04x] “, field[i].len));
}
str.append(String.format(”[%s]", bytesToHexString(field[i].data)));
str.append("\n-------------------------------------------------\n");
}
}
return str.toString();

}

<span style="color:#cc7832;">private static void </span><span style="color:#ffc66d;">dataXor1</span>(<span style="color:#cc7832;">byte</span>[] in<span style="color:#cc7832;">,int</span>[] out<span style="color:#cc7832;">, int </span>len){
    <span style="color:#cc7832;">for</span>(<span style="color:#cc7832;">int </span>i =<span style="color:#6897bb;">0</span><span style="color:#cc7832;">; </span>i &lt; len<span style="color:#cc7832;">; </span>i++){
        out[i] |= (in[i]&amp;<span style="color:#6897bb;">0xff</span>)<span style="color:#cc7832;">;

}
}

<span style="color:#cc7832;">private static void </span><span style="color:#ffc66d;">dataXor</span>(<span style="color:#cc7832;">byte</span>[] source<span style="color:#cc7832;">, byte</span>[] dest<span style="color:#cc7832;">, int </span>size<span style="color:#cc7832;">, byte</span>[] out ) {
    <span style="color:#cc7832;">for</span>( <span style="color:#cc7832;">int </span>i = <span style="color:#6897bb;">0</span><span style="color:#cc7832;">; </span>i &lt; size<span style="color:#cc7832;">; </span>i++ ) {
        out[i] = (<span style="color:#cc7832;">byte</span>)((dest[i]&amp;<span style="color:#6897bb;">0xff</span>) ^ (source[i]&amp;<span style="color:#6897bb;">0xff</span>))<span style="color:#cc7832;">;

}
}

<span style="color:#629755;"><em>/**

* 计算通信的MAC
* @param buf
* @param datasize
* @param mackey
* @return
*/
public byte[] upGetMac( byte[] buf, int seat,int datasize, byte[] mackey){

    <span style="color:#cc7832;">int </span>x = datasize / <span style="color:#6897bb;">8</span><span style="color:#cc7832;">;     </span><span style="color:#808080;">//计算有多少个完整的块

int n = datasize % 8;
int[] val = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
byte[] block = new byte[1024];
Arrays.fill(block, (byte) 0);//清零
arraycopy(buf,seat,block,0,datasize);
//y非0,则在其后补上0x00…
if( n != 0 ){
x += 1; //将补上的这一块加上去
}
byte[] tmp = new byte[8];
for(int i = 0,j = 0;i < x;i++){
arraycopy(block,j,tmp,0,8);
dataXor1(tmp,val,8);
j += 8;
}
String Bbuf = String.format("%02x%02x%02x%02x%02x%02x%02x%02x",val[0],val[1],
val[2],val[3],val[4],val[5],val[6],val[7]);
byte[] bbuf = Bbuf.getBytes();
byte[] b1 = new byte[8];
byte[] b2 = new byte[8];
arraycopy(bbuf,0,b1,0,8);
arraycopy(bbuf,8,b2,0,8);
byte[] tmpmac;
tmpmac = DES_encrypt(b1,mackey);

byte[] Abuf = new byte[8];
dataXor( tmpmac, b2, 8, Abuf );
tmpmac = DES_encrypt(Abuf,mackey);

String str1 = String.format("%02x%02x%02x%02x%02x%02x%02x%02x",tmpmac[0],tmpmac[1],tmpmac[2]
,tmpmac[3],tmpmac[4],tmpmac[5],tmpmac[6],tmpmac[7]);

byte[] mac = new byte[8];
arraycopy(str1.getBytes(),0,mac,0,8);
return mac;
}

<span style="color:#cc7832;">private static byte </span><span style="color:#ffc66d;">charToByte</span>(<span style="color:#cc7832;">char </span>c) {
    <span style="color:#cc7832;">return </span>(<span style="color:#cc7832;">byte</span>) <span style="color:#6a8759;">"0123456789ABCDEF"</span>.indexOf(c)<span style="color:#cc7832;">;

}

<span style="color:#cc7832;">public static </span>String <span style="color:#ffc66d;">bytesToHexString</span>(<span style="color:#cc7832;">byte</span>[] src){
    StringBuilder stringBuilder = <span style="color:#cc7832;">new </span>StringBuilder(<span style="color:#6a8759;">""</span>)<span style="color:#cc7832;">;

if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}

<span style="color:#cc7832;">public static byte</span>[] <span style="color:#ffc66d;">hexStringToBytes</span>(String hexString) {
    <span style="color:#cc7832;">if </span>(hexString == <span style="color:#cc7832;">null </span>|| hexString.equals(<span style="color:#6a8759;">""</span>)) {
        <span style="color:#cc7832;">return null;

}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));

}
return d;
}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值