简体   繁体   中英

Issue in parsing TLV data in java, how to get value,length

I have tried many sample codes to parse APDU response to TLV format. I am able to parse it properly if the response length is less but facing issue if length is more(how calculate length of a tag without any libraries)

NOTE: I am using predefined tags in Constants

code:

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 method

   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;
    }
}

I cannot able to get length properly for few cards(if apdu response is long) Please help

First be sure the input data is proper before you go into the code. Take the full data and try it on https://www.emvlab.org/tlvutils/ .

Once its confirmed the data is proper, go through in EMV 4.3 Book 3, Annex B Rules for BER-TLV Data Objects sections B1, B2, B3 - with utmost attention.

If you follow this precisely, then you wouldn't need to store a static list of tags; will save time in future.

Below sample has an assumption that TLV array is ending with special 0x00 tag but for sure you can ignore it.

Pojo class :

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;
    }
}

Utility method :

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;
}   

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM