无效的ISO 8583标头

时间:2018-12-12 09:56:14

标签: java android iso8583

我正在尝试解析ISO 8583消息并获取单个数据元素。 下面是我到目前为止尝试过的代码

ISOResponse.java

public class ISOResponse {
private static final String TAG = "ISOResponse";
private static final String ISOResponseMessage = "60010203040210303800000E8002000000000000000031000046741306511212383334363133303034363734313330363534303036323730353532340012910A59218CDAFBBCD2520014";

public void parseISO8583(final Context context) throws ParseException, IOException {

    MessageFactory<IsoMessage> messageFactory = new MessageFactory<IsoMessage>();

    if (1 == 0) {
        ConfigParser.configureFromDefault(messageFactory);
    } else {

        PrintLog.log(TAG, "Messagefactory is done");

        InputStream inputData = context.getResources().openRawResource(R.raw.j8583_config);

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputData));

        ConfigParser.configureFromReader(messageFactory, bufferedReader);

    }

    messageFactory.setIgnoreLastMissingField(true);
    IsoMessage isoMessage = messageFactory.parseMessage(ISOResponseMessage.getBytes(),10);
    if (isoMessage != null) {
        PrintLog.log(TAG, "Message type: %04x%n" + isoMessage.getType());
        PrintLog.log(TAG, "FIELD TYPE VALUE");
        for (int i = 2; i <= 64; i++) {
            IsoValue<?> f = isoMessage.getField(i);
            if (f != null) {
                PrintLog.log(TAG, "%5d %-6s [" + i + f.getType());
                PrintLog.log(TAG, f.toString());
                PrintLog.log(TAG, "" + ']');
            }
        }
    }
}
}

j8583_config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE j8583-config PUBLIC "-//J8583//DTD CONFIG 1.0//EN"
"http://j8583.sourceforge.net/j8583.dtd">
<j8583-config>
<!-- This is a test config file -->

<!-- These are the ISO headers to be prepended to the message types specified -->
<header type="0800"/>

<template type="0280">
    <field num="3" type="NUMERIC" length="2">99</field>
</template>

<!-- The server example uses this to read the requests -->
<parse type="0200">
    <field num="3" type="NUMERIC" length="6" />
    <field num="4" type="AMOUNT" />
    <field num="7" type="DATE10" />
    <field num="11" type="NUMERIC" length="6" />
    <field num="12" type="TIME" />
    <field num="13" type="DATE4" />
    <field num="15" type="DATE4" />
    <field num="17" type="DATE_EXP" />
    <field num="32" type="LLVAR" />
    <field num="35" type="LLVAR" />
    <field num="37" type="NUMERIC" length="12" />
    <field num="41" type="ALPHA" length="16" />
    <field num="43" type="ALPHA" length="40" />
    <field num="48" type="LLLVAR" />
    <field num="49" type="ALPHA" length="3" />
    <field num="60" type="LLLVAR" />
    <field num="61" type="LLLVAR" />
    <field num="100" type="LLVAR" />
    <field num="102" type="LLVAR" />
</parse>


<!-- The client example uses this to read the responses -->
<parse type="0210">
    <field num="3" type="NUMERIC" length="6" />
    <field num="4" type="AMOUNT" length="12" />
    <field num="11" type="NUMERIC" length="6" />
    <field num="12" type="TIME" length="6" />
    <field num="13" type="DATE4" length="4" />
    <field num="37" type="NUMERIC" length="12" />
    <field num="38" type="NUMERIC" length="6" />
    <field num="39" type="NUMERIC" length="2" />
    <field num="41" type="ALPHA" length="8" />
    <field num="55" type="LLLVAR" length="255" />
</parse>

<!-- this is for binary tests (message encoding AND fields) -->
<parse type="0600">
    <field num="4" type="AMOUNT" />
    <field num="7" type="DATE10" />
    <field num="11" type="NUMERIC" length="6" />
    <field num="41" type="BINARY" length="8" />
    <field num="42" type="BINARY" length="4" />
    <field num="43" type="ALPHA" length="40" />
    <field num="62" type="LLBIN" />
    <field num="63" type="LLBIN" />
    <field num="64" type="LLLBIN" />
    <field num="65" type="LLLBIN" />
    <field num="102" type="LLLVAR" />
</parse>

<parse type="0800">
    <field num="3" type="ALPHA" length="6"/>
    <field num="12" type="DATE4" length="14"/>
    <field num="17" type="DATE4" length="8"/>
    <field num="11" type="NUMERIC" length="6"/>
    <field num="41" type="LLVAR" length="16"/>
</parse>

<parse type="0810" extends="0800">
    <field num="17" type="exclude"/>
    <field num="39" type="ALPHA" length="2"/>
</parse>

<parse type="0201">
    <field num="3" type="NUMERIC" length="19" />
</parse>
<parse type="0202">
    <field num="3" type="NUMERIC" length="22" />
</parse>
<parse type="0280">
    <field num="3" type="NUMERIC" length="2" />
</parse>

此后,我的代码将引发

  

无效的ISO 8583标头

例外。我尝试删除标头数据并在isoMessage中使标头长度为0,但仍然给出相同的异常。

任何人都可以帮助我找到代码错误。 预先感谢。

3 个答案:

答案 0 :(得分:0)

我尝试解析您的消息,我知道了:

False

看来您的邮件标题长度为14,其中包括 MTI (或10,不含 MTI

答案 1 :(得分:0)

我建议使用另一种方法来打包和拆包邮件。 iso-8583-packer允许您将邮件解压缩到以下字段

<f>
    <f name="Header" val="6001020304" valHex="6001020304"/>
    <f name="MTI" val="0210" valHex="0210"/>
    <f name="Bitmap" bitmapHex="303800000E800200" bitSet="{3, 4, 11, 12, 13, 37, 38, 39, 41, 55}">
        <f name="ProcessingCode" fieldNum="3" val="000000" valHex="000000"/>
        <f name="Amount" fieldNum="4" val="000000003100" valHex="000000003100"/>
        <f name="SystemTraceAuditNumber" fieldNum="11" val="004674" valHex="004674"/>
        <f name="LocalTransactionTimeHHMMSS" fieldNum="12" val="130651" valHex="130651"/>
        <f name="LocalTransactionDateMMDD" fieldNum="13" val="1212" valHex="1212"/>
        <f name="PosNumber" fieldNum="37" val="8346130046741" valHex="38333436...36373431"/>
        <f name="ApprovalCode" fieldNum="38" val="306540" valHex="333036353430"/>
        <f name="ActionCode" fieldNum="39" val="06" valHex="3036"/>
        <f name="TerminalId" fieldNum="41" val="2705524" valHex="32373035353234"/>
        <f name="EMV" fieldNum="55" val="910A59218CDAFBBCD2520014" lenHex="0012" valHex="910A5921...D2520014"/>
    </f>
</f>

消息具有以下定义

<f type="MSG">
    <f type="VAL" name="Header" bodyPacker="LiteralBodyPacker" len="5"/>
    <f type="VAL" name="MTI" bodyPacker="BcdBodyPacker" len="2"/>
    <f type="BIT_SET" name="Bitmap" bitMapPacker="IfbBitmapPacker">
        <f type="VAL" fieldNum="3" name="ProcessingCode" bodyPacker="HexBodyPacker" len="3"/>
        <f type="VAL" fieldNum="4" name="Amount" bodyPacker="BcdBodyPacker" len="6"/>
        <f type="VAL" fieldNum="11" name="SystemTraceAuditNumber" bodyPacker="BcdBodyPacker" len="3"/>
        <f type="VAL" fieldNum="12" name="LocalTransactionTimeHHMMSS" bodyPacker="BcdBodyPacker" len="3"/>
        <f type="VAL" fieldNum="13" name="LocalTransactionDateMMDD" bodyPacker="BcdBodyPacker" len="2"/>
        <f type="VAL" fieldNum="37" name="PosNumber" bodyPacker="AsciiBodyPacker" len="13"/>
        <f type="VAL" fieldNum="38" name="ApprovalCode" bodyPacker="AsciiBodyPacker" len="6"/>
        <f type="VAL" fieldNum="39" name="ActionCode" bodyPacker="AsciiBodyPacker" len="2"/>
        <f type="VAL" fieldNum="41" name="TerminalId" bodyPacker="AsciiBodyPacker" len="7"/>
        <f type="LEN_VAL" fieldNum="55" name="EMV" lengthPacker="BcdLengthPacker" bodyPacker="HexBodyPacker"/>
    </f>
</f>

整个示例位于GitHub上。 注意:我是iso-8583-packer Java库的作者。

答案 2 :(得分:0)

我知道这是一个老问题,但我最近在使用这个库时遇到了类似的问题,只是想分享这个解决方案,以便它可以帮助其他人。 j8583 config.xml 由两部分组成,用于构建 iso 消息的标记和用于从字符串中解压消息的标记。其中每一个都有子元素字段、类型和子元素 num、类型和长度,用于定义 iso 8583 字段中的每一个。根据经验,使用j8583解析iso消息的最佳方式是使用位图并生成配置文件,然后设置消息工厂。配置 XML 在 j8583.dtd 中导入一组定义的值并用作父标记,此文件存储在服务器中,因此您需要互联网在运行时下载它或自己下载并作为系统导入,如果您是使用 android 或应用程序在与互联网通信时遇到问题,最好将这些定义添加到 [] 中,而不是使用 PUBLIC -path 在这里查看更多信息 https://www.w3schools.com/xml/xml_dtd.asp。同样重要的是,在解析响应时,不要在响应字符串消息中包含其总长度(前 4 个字符)或 tdpu 标头(之后的下 10 个字符)。

构建响应消息配置文件

private void setResponseFactory(String responseMessage) throws IOException {

    Log.i(TAG, "in setResponseFactory");

    StringBuilder xmlParser = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
            "<!DOCTYPE j8583-config [\n<!ELEMENT j8583-config ( header*, template*, parse* ) >\n" +
            "\n" +
            "<!ELEMENT header ( #PCDATA ) >\n" +
            "<!ATTLIST header type NMTOKEN #REQUIRED >\n" +
            "<!ATTLIST header ref NMTOKEN #IMPLIED >\n" +
            "<!ATTLIST header binary ( true | false ) #IMPLIED >\n" +
            "\n" +
            "<!ELEMENT template ( field* ) >\n" +
            "<!ATTLIST template type NMTOKEN #REQUIRED >\n" +
            "<!ATTLIST template extends NMTOKEN #IMPLIED >\n" +
            "\n" +
            "<!ELEMENT parse ( field* ) >\n" +
            "<!ATTLIST parse type NMTOKEN #REQUIRED >\n" +
            "<!ATTLIST parse extends NMTOKEN #IMPLIED >\n" +
            "\n" +
            "<!ELEMENT field ( #PCDATA|field )* >\n" +
            "<!ATTLIST field num NMTOKEN #REQUIRED >\n" +
            "<!ATTLIST field length NMTOKEN #IMPLIED >\n" +
            "<!ATTLIST field tz NMTOKEN #IMPLIED >\n" +
            "<!ATTLIST field type ( ALPHA | NUMERIC | AMOUNT | DATE4 | DATE6 | DATE10 | DATE12 | DATE14 | DATE_EXP | TIME | LLVAR | LLLVAR | LLLLVAR | BINARY | LLBIN | LLLBIN | LLLLBIN | LLBCDBIN | LLLBCDBIN | LLLLBCDBIN | exclude) #REQUIRED >\n]>\n\n\t\t<!-- This file is generated at runtime, for iso message parsing (unpacking), response message types are request type + 10 -->\n\n");

    String messageType = responseMessage.substring(0, 4); // response message type 0210 - sale, 0230 - advice ect...

    Log.i(TAG, "response message type " + messageType);
    Log.i(TAG, "hex bitmap " + responseMessage.substring(4, 20));
    String bitmap =   new BigInteger(responseMessage.substring(4, 20), 16).toString(2);

    int length = 64 - bitmap.length();
    char[] padArray = new char[length];
    Arrays.fill(padArray, '0');
    String padString = new String(padArray);
    bitmap = padString + bitmap; // padd bitmap with zeros to the left

    Log.i(TAG, "response bitmap " + bitmap);

    HashMap<Integer, Pair<IsoType, Integer>> config = new HashMap<>(); // iso response field dictionary

    config.put(Field_Indexes.PRIMARY_ACCOUNT_NUMBER, new Pair<>(IsoType.LLBIN, 0));
    config.put(Field_Indexes.PROCESS_CODE, new Pair<>(IsoType.NUMERIC, 6));
    config.put(Field_Indexes.TRANSACTION_AMOUNT, new Pair<>(IsoType.NUMERIC, 12));
    config.put(Field_Indexes.TRACE_AUDIT_NUMBER, new Pair<>(IsoType.NUMERIC, 6));
    config.put(Field_Indexes.LOCAL_TRANSMISSION_TIME, new Pair<>(IsoType.NUMERIC, 6));
    config.put(Field_Indexes.LOCAL_TRANSMISSION_DATE, new Pair<>(IsoType.NUMERIC, 4));
    config.put(Field_Indexes.POS_ENTRY_MODE, new Pair<>(IsoType.NUMERIC, 4));
    config.put(Field_Indexes.NETWORK_INTERNATIONAL_IDENTIFIER, new Pair<>(IsoType.NUMERIC, 4));
    config.put(Field_Indexes.POS_CONDITION_CODE, new Pair<>(IsoType.NUMERIC, 2));
    config.put(Field_Indexes.RETRIEVAL_REFERENCE_NUMBER, new Pair<>(IsoType.BINARY, 12));
    config.put(Field_Indexes.AUTHORIZATION_IDENTIFICATION_RESPONSE, new Pair<>(IsoType.BINARY, 6));
    config.put(Field_Indexes.RESPONSE_CODE, new Pair<>(IsoType.BINARY, 2));
    config.put(Field_Indexes.CARD_ACCEPTOR_TERMINAL_IDENTIFICATION, new Pair<>(IsoType.BINARY, 8));
    config.put(Field_Indexes.ICC_DATA, new Pair<>(IsoType.LLLLBCDBIN, 0));
    config.put(Field_Indexes.RN_FIELD_60, new Pair<>(IsoType.LLLLBIN, 0));
    config.put(Field_Indexes.RP_FIELD_63, new Pair<>(IsoType.LLLLBCDBIN, 0));
    config.put(Field_Indexes.MESSAGE_AUTHENTICATION_CODE_64, new Pair(IsoType.BINARY, 16));

    xmlParser.append("<j8583-config>\n\t\t<parse type=\"" + messageType + "\">");

    for(int i = 1; i<= 64; i++) // first bitmap if you are using secondary bitmap change to 128 instead of 64
        if(bitmap.charAt(i - 1) == '1')
            xmlParser.append("\n\t\t\t<field num=\"" + i + "\" type=\"" + config.get(i).first.toString() + "\""
                    + ((config.get(i).second > 0) ? " length=\"" + config.get(i).second + "\" ": "")  + "/>");


    xmlParser.append("\n\t\t</parse>\n</j8583-config>");
    wrtieFileOnInternalStorage(xmlParser.toString());

    File root = new File(StateMachine.mContext.get().getFilesDir(),"response");
    File file = new File(root, "isoresponse.xml");

   responseFactory = ConfigParser.createFromClasspathConfig(file.getCanonicalPath());
}

调用消息解析器

    public static void main (String[] args){
        setResponseFactory(responseMessage);
        responseFactory.setUseBinaryMessages(false);

        Log.i(TAG, "in analize response");

        HashMap<Integer, String> isoResponseData = SimpleParser.unpackIsoMessage(responseFactory, responseMessage); // remove tag, tdpu header and trailing 0
}

使用简单解析器https://github.com/SergeyZyazyulkin/j8583/blob/master/src/main/java/com/solab/iso8583/util/SimpleParser.java的实际解包

    public static HashMap<Integer, String> unpackIsoMessage(MessageFactory mf, String message) throws UnsupportedEncodingException, ParseException {

        HashMap<Integer, String> messageValues = new HashMap<>();
        Log.i(TAG, "message: " + message);

        if (message != null && message.length() > 0) {
            IsoMessage m = mf.parseMessage(message.getBytes(), 0);
            if (m != null) {
                for (int i = 2; i <= 128; i++) {
                    IsoValue<?> f = m.getField(i);
                    if (f != null) {

                        Log.i(TAG, "f value class name " + f.getValue().getClass().getSimpleName());

                        if(f.getValue().getClass() == byte[].class)
                            messageValues.put(i, HexCodec.hexEncode((byte[])f.getValue(), 0, ((byte[]) f.getValue()).length));

                        else if(f.getValue().getClass().getSimpleName().equals("Long")){
                            messageValues.put(i, f.getValue() + "");
                        }

                        else
                            messageValues.put(i, (String) f.getValue());

                        Log.i(TAG, "iso value index " + i + " value " + messageValues.get(i));
                    }
                }
            }
        }

        return messageValues;
    }
}

其他资源 http://j8583.sourceforge.net/xmlconf.html