【问题标题】:Issue in parsing TLV data in java, how to get value,lengthjava中解析TLV数据的问题,如何获取值,长度
【发布时间】:2018-12-27 11:30:57
【问题描述】:

我尝试了许多示例代码来将 APDU 响应解析为 TLV 格式。 如果响应长度较短,我能够正确解析它,但如果长度较长则面临问题(如何在没有任何库的情况下计算标签的长度)

注意:我在常量中使用预定义的标签

代码:

private HashMap<String, String> parseTLV(String apduResponse) {

    HashMap<String, String> tagValue = new HashMap<>();
    String remainingApdu = apduResponse.replaceAll(" ", "");
    if (remainingApdu.endsWith(ResponseTags._SUCCESS_STATUSWORDS)) {
        remainingApdu = remainingApdu.substring(0, remainingApdu.length() - 4);
    }
    while (remainingApdu != null && remainingApdu.length() > 2) {
        remainingApdu = addTagValue(tagValue, remainingApdu);
    }
    return tagValue;
}

addTagValue 方法

   private String addTagValue(HashMap<String, String> tagValue, String apduResponse) {
        String tag = "";
        String length = "";
        String value = "";
        int tagLen = 0;

        if (tagUtils.isValidTag(apduResponse.substring(0, 2))) {
            tagLen = readTagLength(apduResponse.substring(3));
            // tagLen = 2;
            tag = apduResponse.substring(0, 2);
        } else if (tagUtils.isValidTag(apduResponse.substring(0, 4))) {
            tagLen = 4;
            tag = apduResponse.substring(0, 4);
        } else {
            return "";
        }
        Log.e("TAG_LEN","tag: "+tag+"taglen: "+tagLen);
        if (tagUtils.shouldCheckValueFor(tag)) {
            length = apduResponse.substring(tagLen, tagLen + 2);
            int len = tagUtils.hexToDecimal(length);
            value = apduResponse.substring(tagLen + 2, (len * 2) + tagLen + 2);
            tagValue.put(tag, value);
            if (ResponseTags.getRespTagsmap().containsKey(tag)) {
                //logData = logData + "\nKEY:" + tag + " TAG:" + ResponseTags.getRespTagsmap().get(tag)/* + " VALUE:" + value + "\n "*/;
            }
            if (tagUtils.isTemplateTag(tag)) {
              //  logData = logData + "\n\t-->";
                return addTagValue(tagValue, value) + apduResponse.substring(tag.length() + value.length() + length.length());
            } else {
                return apduResponse.substring(tag.length() + value.length() + length.length());
            }
        } else {
            value = apduResponse.substring(2, 4);
            tagValue.put(tag, value);
//            logData = logData + "\n\t\tKEY:" + tag + " TAG:" + ResponseTags.getRespTagsmap().get(tag) /*+ " VALUE:" + value + "\n "*/;
            return apduResponse.substring(tag.length() + value.length() + length.length());
        }
    }

readTagLength :

private int readTagLength(String apduResponse) {
    int len_bytes = 0;
    if (apduResponse.length() > 2) {
        len_bytes = (apduResponse.length()) / 2;
    }
    Log.e("tlv length:", "bytes:" + len_bytes);
    if (len_bytes < 128) {
        return 2;
    } else if (len_bytes > 127 && len_bytes < 255) {
        return 4;
    } else {
        return 6;
    }
}

我无法正确获取几张卡片的长度(如果 apdu 响应很长) 请帮忙

【问题讨论】:

标签: java parsing emv tlv


【解决方案1】:

在进入代码之前,首先确保输入数据是正确的。获取完整数据并在 https://www.emvlab.org/tlvutils/ 上试用。

一旦确认数据正确,请在 EMV 4.3 Book 3 中完成, BER-TLV 数据对象的附录 B 规则 B1、B2、B3 部分 - 高度重视。

如果您准确地遵循这一点,那么您就不需要存储静态的标签列表;将来会节省时间。

【讨论】:

  • 请阅读问题,特别提到“无法正确获取少数卡片的长度”。
  • 请分享在您的应用程序中无法很好解析的 APDU。可以分享一下日志吗?
  • 这个问题与 apdu 无关。它关于在不使用任何库的情况下获取 tlv 中的数据长度。请阅读问题
  • 我已经在没有任何第三方库的情况下端到端地实现了它,只需遵循我共享的文档参考中的标签长度​​和值规范。再见。
  • @UmaAchanta 您需要正确实现多字节标签标识符(最多仅支持两个字节)和多字节标签长度(看起来根本不像解析长度)。它在 BER 的文档中进行了描述,您可以尝试将 en.wikipedia.org/wiki/X.690 作为一个不错的来源。长度在超过一个字节上编码时设置最高有效位。
【解决方案2】:

以下示例假设 TLV 数组以特殊的 0x00 标记结尾,但您可以肯定地忽略它。

Pojo 类:

public class Tlv {

    private short tag;

    private byte[] value;

    public Tlv(short tag) {
        this.tag = tag;
    }
    public short getTag() {
        return tag;
    }
    public byte[] getValue() {
        return value;
    }
    public void setValue(byte[] valueBytes) {
        this.value = valueBytes;
    }
}

实用方法:

public static Map<Byte, Tlv> parse(ByteBuffer bb) throws TlvException {

    Map<Byte, Tlv> tlvs = null;
    tlvs = new HashMap<Byte, Tlv>();
    try {
        while (bb.remaining() > 0) {
            byte tag = bb.get();
            if(tag == 0x00)
                continue;
            int length = bb.get();
            byte[] value = new byte[length];
            bb.get(value, 0, length);
            Tlv tlv = new Tlv(tag);
            tlv.setValue(value);
            tlvs.put(tag, tlv);
        }
    } catch (IndexOutOfBoundsException e) {
        throw new TlvException("Malformed TLV part: " + bb.toString() + ".", e);
    }
    return tlvs;
}   

【讨论】:

  • 您的解析方法不包括对多字节标记标识符的覆盖(在第一个字节上设置了 5 个最低有效位的那些,以及可能在第二个和更高字节的最高有效位上指示的那些) .您的长度也不包括对多字节长度的支持(那些设置了最高有效位并指示长度字节数的字节)。
猜你喜欢
  • 1970-01-01
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-02
  • 1970-01-01
相关资源
最近更新 更多