ISO8583报文中的编、解码总结

ISO8583报文中的编、解码总结

 

1.pos收单流程

从POS机的角度看,一个典型的收单交易流程为:

1. 根据报文格式进行组包,向后台发起交易请求;
2. 后台收到请求后解包进行验证,验证完成后重新组包返回应答报文;
3. POS终端收到应答报文后解包,得到最终交易结果,整个流程结束。

其中,组包就是编码的过程,解包就是解码的过程。

2.计算机编码基础

计算机可以存储数字、字母、中文、特殊符号、图像等等各种复杂的数据,但不管是何种数据,最终都是通过底层的二进制数字(0和1)来表示,那计算机是怎么通过0和1的一长串组合来表示那么多复杂的数据呢?

2.1整型的存储

首先,我们来看一下最简单的数据:整型,在计算机中如何表示。
计算机通过补码来表示一个整型值,补码是在原码的基础上取反码加1。

- 原码:一个数在计算机中的二进制表示形式,其中最高位存放符号,正数为0,负数为1。比如-3用一个字节(8位)来表示就为10000011
- 反码:反码是在原码的基础上变化而来的,正数的反码和原码相同,负数的反码是在原码的基础上,符号位不变,其余各个位取反。比如-3的反码表示为11111100
- 补码:正数的补码和原码相同,负数的补码是在原码的基础上,符号位不变,其余各个位取反,最后+1。比如-3的补码表示为11111101
//原码转成补码的过程(正数不变,负数取反加1)
[+1] = [00000001]原 => [00000001]反 => [00000001]补
[-1] = [10000001]原 => [11111110]反 => [11111111]补

从以上可以看出,原码更接近人类的理解方式,那为什么不直接用原码而用补码表示数字的存储呢?
通过补码表示方式,可以让符号参与运算,统一数的加减法运算。此外,补码和原码相互转换,其运算过程是相同的,不要额外的硬件电路。

//补码方式展现3-2的运算过程
//第一步,将减法变成假发3-2转成3 + (-2)
-2的补码 [10000010]原 => [11111101]反 => [11111110]补
//第二步, 进行3 + (-2)的运算
  [00000011]3
 +[11111110]-2
 =[00000001]运算结果
//将运算转成数字
  [00000001] => +1  

2.2字符的存储

字符是指计算机中使用的文字和符号,比如1,2,3,a,b,c,空格,换行,标点符号,中文,日文,图片等。
可以把字符的存储理解成一个“翻译”的过程,因为计算机只能存储一个个的字节数据,不能识别字符,所以我们需要将字符翻译成计算机可以理解的字节数据,这个将字符翻译成字节的过程我们称为编码
举例来说ASCII码:

这里写图片描述
这是单字节的ASCII码表,可以表示0~127个字符数据,其中0~31是控制字符如回车、换行、删除等;32~126是打印字符,可以通过键盘输入并且能够显示出来。
现在,通过字节来存储不同字符的方法解决了,但人类有各种不同的语言,如英语、中文、拉丁文等等,需要用不同的编码方式来表示,不同的语言还要在计算机上同时显示,这就需要统一的编码格式规范了。

2.3常见的编码格式

ISO-8859-1

128 个字符显然是不够用的,于是 ISO 组织在 ASCII 码基础上又制定了一些列标准用来扩展 ASCII 编码,它们是 ISO-8859-1~ISO-8859-15,其中 ISO-8859-1 涵盖了大多数西欧语言字符,在所有编码中应用的最广泛。ISO-8859-1 仍然是单字节编码,它总共能表示 256 个字符。

GB2312

它的全称是《信息交换用汉字编码字符集 基本集》,它是双字节编码,总的编码范围是 A1-F7,其中从 A1-A9 是符号区,总共包含 682 个符号,从 B0-F7 是汉字区,包含 6763 个汉字。

GBK

全称叫《汉字内码扩展规范》,是国家技术监督局为 windows95 所制定的新的汉字内码规范,它的出现是为了扩展 GB2312,加入更多的汉字,它的编码范围是 8140~FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。

GB18030

全称是《信息交换用汉字编码字符集》,是我国的强制标准,它可能是单字节、双字节或者四字节编码,它的编码与 GB2312 编码兼容,这个虽然是国家标准,但是实际应用系统中使用的并不广泛。

UTF-16

说到 UTF 必须要提到 Unicode(Universal Code 统一码),ISO 试图想创建一个全新的超语言字典,世界上所有的语言都可以通过这本字典来相互翻译。可想而知这个字典是多么的复杂,关于 Unicode 的详细规范可以参考相应文档。Unicode 是 Java 和 XML 的基础,下面详细介绍 Unicode 在计算机中的存储形式。
UTF-16 具体定义了 Unicode 字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式,这个是定长的表示方法,不论什么字符都可以用两个字节表示,两个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。

UTF-8

UTF-16 统一采用两个字节表示一个字符,虽然在表示上非常简单方便,但是也有其缺点,有很大一部分字符用一个字节就可以表示的现在要两个字节表示,存储空间放大了一倍,在现在的网络带宽还非常有限的今天,这样会增大网络传输的流量,而且也没必要。而 UTF-8 采用了一种变长技术,每个编码区域有不同的字码长度。不同类型的字符可以是由 1~6 个字节组成。
UTF-8 有以下编码规则:
如果一个字节,最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 - 7F)。可见,所有 ASCII 编码已经是 UTF-8 了。
如果一个字节,以 11 开头,连续的 1 的个数暗示这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。
如果一个字节,以 10 开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节。

3. ISO8583报文中的编解码

前面我们介绍常用的几种编码方式,那在ISO8583报文中会使用哪种编码方式呢?为什么要使用这种编码方式?
我的理解是报文是用于终端和后台端到端的交互,是通过网络进行传输的,网络中最重要的当然是带宽,所以报文编码的关注点主要是尽量减小报文所占的带宽,也就是说通过编码来尽量减小报文的字节数
举个例子:
报文中的域2,存储主账号,表示为N..19(LLVAR),2个字节长度值+最大19个字节的主账号,压缩(也就是编码)时用BCD码(一种编码方式,后面会介绍)表示的1个字节的长度值+用左靠BCD码表示的最大10个字节的主账号。

//主账号(16位)
6225-8879-0261-0332  
--编码后-->
//占9个字节 
0x16 + 0x62 0x25 - 0x88 0x79 - 0x02 0x61 - 0x03 0x32

因主账号是数字(0~9)组成的,而一个字节可以表示最多256个字符,如果用1个字节来存储明显是浪费空间,这里用BCD编码,一个字节可以存储2位账号,相比节省了一半的空间。

理解了选用编码方式的原则,接下来我们来看一下8583报文中使用到的编码方式以及编解码转换方法。

3.1 BCD编码

BCD码是一种二进制的数字编码形式,用4位二进制来表示1位十进制数中的0~9这10个数码。这种编码形式利用了四个位来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的运行。
BCD编码在8583报文中使用最为广泛,像银联标准的域2,3,4,11,12,13,14等,都是使用这种编码方式。

/**
* 将str字符串转换成bcd编码的字节数组,比如字符串"123456"转成byte[] {0x12, 0x34, 0x56}
* @param asc
* @return
*/
private static byte[] str2Bcd(String asc) {
    int len = asc.length();
    len /= 2;

    byte[] bbt = new byte[len];
    byte[] abt = asc.getBytes(Charset.forName("utf-8"));

    for (int p = 0; p < len; ++p) {
        int j; //字节高4位
        int k; //字节低4位

        if ((abt[(2 * p)] >= 97) && (abt[(2 * p)] <= 122)) {
            //字符a-z
            j = abt[(2 * p)] - 97 + 10;
        }
        else if ((abt[(2 * p)] >= 65) && (abt[(2 * p)] <= 90)) {
            //字符A-Z
            j = abt[(2 * p)] - 65 + 10;
        }
        else {
            //数字0-9
            j = abt[(2 * p)] - 48;
        }

        if ((abt[(2 * p + 1)] >= 97) && (abt[(2 * p + 1)] <= 122)) {
            k = abt[(2 * p + 1)] - 97 + 10;
        }
        else if ((abt[(2 * p + 1)] >= 65) && (abt[(2 * p + 1)] <= 90)) {
            k = abt[(2 * p + 1)] - 65 + 10;
        }
        else {
            k = abt[(2 * p + 1)] - 48;
        }

        int a = (j << 4) + k;
        byte b = (byte) a;
        bbt[p] = b;
    }
    return bbt;
}


/**
* 将bcd编码的字节数组转换成str字符串,比如byte[] {0x12, 0x34, 0x56}转成字符串"123456"
* @param bytes
* @return
*/
private static String bcd2Str(byte[] bytes) {
    //str字符串的长度为原来的2倍
    StringBuffer temp = new StringBuffer(bytes.length * 2);
    for (int i = 0; i < bytes.length; ++i) {
        //得到高4位二进制转换后的十进制值
        byte left = (byte) ((bytes[i] & 0xF0) >>> 4);
        //得到低4位二进制转换后的十进制值
        byte right = (byte) (bytes[i] & 0x0F);
        //根据ASCII码表转成str表示的数字
        temp.append(String.format("%c",
                new Object[]{Integer.valueOf(left + 48)}));
        temp.append(String.format("%c",
                new Object[]{Integer.valueOf(right + 48)}));
    }
    return temp.toString();
}

3.2 ASC编码

这个就是前面介绍过的ASCII编码,主要看一下它的编解码转换,需要注意的是如果字符中包含中文或者其他语言,则需要使用支持的编码方式去编码,然后再用相同方式去解码,否则会产生乱码。比如说用ISO-8859-1对中文进行编码,再解码会产生乱码,因为ISO-8859-1本身就不支持中文。
8583报文ASC编码主要应用于一些域中除了数字外,还有英文字母或者特殊符号,如域41,42,44等

//str转asc
byte[] asc = "123456".getBytes("utf-8");

//asc转str
String str = new String(asc, "utf-8");

3.3 其他

8583报文中除了以上这两种编码方式外,还存在以下两种情况:

- 一些域如域64报文鉴别码,它是一个固定的8字节的数据,通过前面的各个域计算而来,用于鉴别报文是否被篡改。
- 一些自定义域中需要上传图片信息,有特定的自己的编码方式。

这两种情况,一般的处理方法是将域数据直接转换成字节数组,不需要编码(没办法再进一步压缩),直接将数值原值上送就可以了。

4. 组解包自动化思路

在做收单交易中,每一笔交易都需要有多个的交易请求过程,每个过程都包含组解包即编解码的过程,那通过代码将编解码的方式自动化是很有必要的,下面提供一个组解包自动化的思路。
定义一个全局的配置文件,用于配置8583报文各个域的组解包方法,包括长度编码类型、数值编码类型、最大长度、是否是变长、BCD压缩时是左靠还是右靠等,尽量将配置文件弄得简洁一些。

<?xml version="1.0" encoding="utf-8"?>
<!--
  This is the template for CUP ISO8583, it defines the necessary attributes for packing/unpacking.
With this, you can define the attributes with a friendly interface, instead of setting them one by one
in the code. Of course, you can also set all these attributes in the code when necessary.
  The attributes are listed as follows:
  1. global settings
      1) secondary_bitmap(opt.)
        indicating if secondary bitmap(i.e. filed 1) exists or not, "YES" for true, "NO" otherwise, default to "NO".
      2) var_len_format(opt.)
        the format of the varible length(i.e. L/LL/LLL), can be "BCD"/"ASC"/"BIN", default to "BCD"
        i)  BCD: BCD
        * for LVAR, 1 byte, range 0~9;
        * for LLVAR, 1 byte, range 0~99;
        * for LLLVAR, 2 bytes, range 0~999;
        ii)  ASC: ASCII
        * for LVAR, 1 byte, range 0~9;
        * for LLVAR, 2 byte, range 0~99;
        * for LLLVAR, 3 bytes, range 0~999;
        iii) BIN: BINARY
        * for LVAR, 1 byte, range 0~0xF;
        * for LLVAR, 1 byte, range 0~0xFF;
        * for LLLVAR, 2 bytes, range 0~0xFFF;

  2. field settings
      1) tag name(mandatory)
        h: header, including TPDU and some other proprietary fields
        m: msg id
        fx: field x
      2) format string (mandatory)
        currently supports "A"/"N"/"S"/"AN"/"AS"/"NS"/"ANS"/"B"/"Z"
          for variable length format, use ".x/..xx/...xxx"
          e.g. Alpha 10 bytes: "A10";  Binary 64 bits: "B64";  Alphanumeric LLVAR with max length 80: "AN..80"
      3) description (opt.)
        this is optional, it's mainly for debug purpose.

NOTE:
  If you need to define fields above 64, 'secondary_bitmap' MUST be set to "YES" first;
  Field 65 is specially for tertiary bitmap, setting format or value to this field is ignored internally;
  For Android, you MUST place this file into assets.
-->

<iso8583 secondary_bitmap="NO"  var_len_format="BCD">
  <h    format="N22"      description="header"/>
  <m    format="N4"          description="msg_id"/>
  ...
</iso8583>
银联 ISO8583 文档: 前 言 VI 1 范围 1 2 规范性引用文件 1 3 术语和定义 1 3.1 受理方 (ACQUIRER) 1 3.2 发卡方 (ISSUER) 1 3.3 转入方 (TRANSFER-IN) 2 3.4 转出方 (TRANSFER-OUT) 2 3.5 交换系统 (BANK CARD SWITCHING SYSTEM) 2 3.6 请求 (REQUEST) 2 3.7 响应码 (RESPONSE CODE) 2 3.8 冲正 (REVERSAL) 2 3.9 清算 (SETTLEMENT) 2 3.10 交易 (TRANSACTION) 2 3.11 通知 (ADVICE) 2 3.12 报文 (MESSAGE) 2 3.13 数据包 (DATAGRAM) 2 4 公共支付交易处理说明 3 4.1 公共支付业务联机交易处理 3 4.1.1 委托关系建立/委托关系撤销(0100/0110) 3 4.1.2 订购(类似预授权0100/0110) 3 4.1.3 金融类交易(0200/0210) 5 4.1.4 金融类撤销交易(0200/0210) 8 4.1.5 查询类交易(0200/0210) 9 4.1.6 转账类交易(0200/0210) 10 4.1.7 冲正通知类交易(0420/0430) 10 4.1.8 金融通知类交易(0220/0230) 12 4.1.9 与服务提供商无关的交易 12 4.2 增值业务文件方式处理 13 4.2.1 非实时查询交易 13 4.2.2 非实时缴费/充值交易 14 4.2.3 批量代收/批量代付文件方式 14 4.2.4 委托关系建立/委托关系撤销文件方式 15 4.3 超时限定 16 4.4 公共支付平台二级清算处理 17 4.4.1 截账日切通知(0820/0830) 17 4.4.2 批结对账交易(0522/0532) 17 4.4.3 公共支付平台二级清算产生的交易处理流程 18 4.4.4 公共支付平台清分清算的时序 19 4.5 管理及安全控制交易处理 19 4.5.1 网络管理交易(0820/0830) 19 4.5.2 重置密钥(0800/0810) 21 4.6 交易的异常处理流程 21 4.6.1 概述 21 4.6.2 异常处理原则 21 4.6.3 通信异常 22 5 报文域定义 31 5.1 说明 31 5.2 数据类型定义 31 5.3 域名称及定义 31 5.3.1 报文头 31 5.3.2 MTI 报文类型 36 5.3.3 第一位图 37 5.3.4 第二位图 37 5.3.5 域2 主账号PAN 37 5.3.6 域3 交易处理码 38 5.3.7 域4 交易金额 40 5.3.8 域7交易传输时间 40 5.3.9 域11系统跟踪号 41 5.3.10 域12受卡方所在地时间 41 5.3.11 域13受卡方所在地日期 42 5.3.12 域14卡有效期 42 5.3.13 域15清算日期 42 5.3.14 域18商户类型 43 5.3.15 域22服务点输入方式码 43 5.3.16 域25服务点条件码 44 5.3.17 域26服务点PIN获取码 44 5.3.18 域32代理机构标识码 45 5.3.19 域33发送机构标识码 45 5.3.20 域35第二磁道数据 45 5.3.21 域36第三磁道数据 46 5.3.22 域37检索参考号 46 5.3.23 域39应答码 47 5.3.24 域41受卡机终端标识码 47 5.3.25 域42受卡方标识码 47 5.3.26 域43受卡方名称地址 47 5.3.27 域44附加响应数据 48 5.3.28 域48附加自定义数据 48 5.3.29 域49交易货币代码 54 5.3.30 域50清算货币代码 54 5.3.31 域52个人标识码数据 54 5.3.32 域53安全控制信息 55 5.3.33 域54实际余额 56 5.3.34 域59明细查询数据 57 5.3.35 域60自定义域 61 5.3.36 域61证件号 63 5.3.37 域70网络管理信息码 66 5.3.38 域74 贷记交易笔数 67 5.3.39 域75 冲正贷记笔数 67 5.3.40 域76 借记交易笔数 67 5.3.41 域77 冲正借记笔数 67 5.3.42 域78 转账笔数 68 5.3.43 域79 冲正转账笔数 68 5.3.44 域80 查询笔数 68 5.3.45 域81 授权笔数 68 5.3.46 域82 贷记服务费金额 69 5.3.47 域84 借记服务费金额 69 5.3.48 域86 贷记交易金额 69 5.3.49 域87 冲正贷记金额 70 5.3.50 域88 借记交易金额 70 5.3.51 域89 冲正借记金额 70 5.3.52 域90原始数据元 70 5.3.53 域96报文安全码 71 5.3.54 域99清算机构代码 71 5.3.55 域100接收机构标识码 72 5.3.56 域102账户标识1 72 5.3.57 域103账户标识2 72 5.3.58 域121 交换系统保留 72 5.3.59 域122受理方保留 75 5.3.60 域123发卡方保留 75 5.3.61 域128报文鉴别码MAC 75 6 公共支付平台交易接口报文 77 6.1 说明 77 6.1.1 符号约定 77 6.1.2 报文格式说明示意 77 6.1.3 报文域条件数据元说明 78 6.2 公共支付平台联机交易报文 78 6.2.1 欠费查询/资金户余额查询报文 78 6.2.2 账单明细查询报文 79 6.2.3 银行卡余额查询 81 6.2.4 订购(预授权)报文 82 6.2.5 订购撤销(预授权撤销)报文 84 6.2.6 订购完成(预授权完成)报文 85 6.2.7 订购完成撤销(预授权完成撤销) 86 6.2.8 缴费/充值报文 87 6.2.9 缴费撤销报文 89 6.2.10 冲正通知报文 90 6.2.11 建立/撤销委托关系报文 93 6.2.12 查询委托关系报文 95 6.2.13 转账类交易报文 96 6.2.14 与服务提供商无关的交易报文 99 6.3 清分清算和日终批处理的报文接口 错误!未定义书签。 6.3.1 批结对账交易报文 错误!未定义书签。 6.3.2 截账日切通知报文 错误!未定义书签。 6.4 网络管理及安全控制报文 107 6.4.1 网络管理报文 107 6.4.2 安全控制报文 109 7 缴费终端接口报文 111 7.1 说明 111 7.1.1 标准接口报文及流程图 111 7.1.2 消息格式 111 7.1.3 消息格式的表示方法 111 7.2 委托关系建立/委托关系撤销终端报文 111 7.3 待缴费用/资金户余额查询终端报文 111 7.4 缴费账单明细查询终端报文 111 7.5 缴费/缴费撤销终端报文 111 7.6 银行卡转出/银行卡转入终端报文 111 7.7 终端签到 111 7.8 终端签退 错误!未定义书签。 7.9 终端批结对账交易、批上送完成通知(可选) 错误!未定义书签。 7.10 终端批上送记录(可选) 错误!未定义书签。 8 文件接口规范 111 8.1 概述 111 8.1.1 目的 111 8.1.2 适用范围 111 8.1.3 相关文档 111 8.2 文件存取方式说明 111 8.2.1 FTP方式 112 8.2.2 WEB方式 113 8.3 文件使用说明 115 8.3.1 基本的命名约定 115 8.3.2 记录格式基本约定 116 8.3.3 流水文件说明 120 8.3.4 批量代收/代付文件说明 121 8.4 文件格式说明 123 8.4.1 符号定义 123 8.4.2 流水文件格式 123 8.4.3 批量代收/代付文件格式 125 8.4.4 非实时待缴费用托管文件格式 129 8.4.5 委托关系文件格式 130 9 通信接口规范 131 9.1 目的 131 9.2 网络架构 132 9.3 网络接口 132 9.3.1 接入设备基本要求 132 9.3.2 通信软件接口 132 10 数据安全传输控制 134 10.1 个人标识(PIN)的加密和解密 134 10.1.1 PIN的长度 135 10.1.2 PIN的字符集 136 10.1.3 PIN格式 136 10.1.4 PIN异常的处理 137 10.2 报文来源正确性鉴别MAC 137 10.2.1 MAC报文域的选择 138 10.2.2 MAC域的构成规则 140 10.2.3 MAC的计算 140 10.2.4 MAC错误异常处理 141 附 录 A 142 参考文献 154
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值