java中解析TLV数据的问题,如何获取值、长度

java中解析TLV数据的问题,如何获取值、长度,java,parsing,emv,tlv,Java,Parsing,Emv,Tlv,我已经尝试了许多示例代码来将APDU响应解析为TLV格式。 如果响应长度较小,我能够正确地解析它,但如果响应长度较大,我将面临问题(如何在没有任何库的情况下计算标记的长度) 注意:我在常量中使用预定义的标记 代码: private HashMap<String, String> parseTLV(String apduResponse) { HashMap<String, String> tagValue = new HashMap<>();

我已经尝试了许多示例代码来将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;
}
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;
    }
}
private HashMap parseTLV(字符串apduResponse){
HashMap tagValue=新的HashMap();
字符串remaingapdu=apduResponse.replaceAll(“,”);
if(保留PDU.endsWith(响应项\成功\状态词)){
remaingapdu=remaingapdu.substring(0,remaingapdu.length()-4);
}
while(remaingapdu!=null&&remaingapdu.length()>2){
remainingApdu=addTagValue(tagValue,remainingApdu);
}
返回标记值;
}
附加值方法

   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());
        }
    }
private String addTagValue(HashMap tagValue,String apduResponse){
字符串标签=”;
字符串长度=”;
字符串值=”;
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);
}否则{
返回“”;
}
Log.e(“TAG_LEN”,“TAG:+TAG+”taglen:+taglen”);
if(tagUtils.shouldCheckValueFor(tag)){
长度=apduResponse.substring(tagLen,tagLen+2);
int len=tagUtils.hexToDecimal(长度);
值=apduResponse.substring(tagLen+2,(len*2)+tagLen+2);
tagValue.put(标签,值);
if(ResponseTags.getRespTagsmap().containsKey(标记)){
//logData=logData+“\nKEY:“+tag+”标记:“+ResponseTags.getRespTagsmap().get(tag)/*+”值:“+VALUE+”\n”*/;
}
if(tagUtils.isTemplateTag(tag)){
//logData=logData+“\n\t-->”;
返回addTagValue(tagValue,value)+apduResponse.substring(tag.length()+value.length()+length.length());
}否则{
返回apduResponse.substring(tag.length()+value.length()+length.length());
}
}否则{
值=apduResponse.子字符串(2,4);
tagValue.put(标签,值);
//logData=logData+“\n\t\tKEY:“+tag+”标记:“+ResponseTags.getRespTagsmap().get(tag)/*+”值:“+VALUE+”\n*/;
返回apduResponse.substring(tag.length()+value.length()+length.length());
}
}
readTagLength:

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;
}
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;
    }
}
private int readTagLength(字符串apduResponse){
int len_字节=0;
如果(apduResponse.length()>2){
len_字节=(apduResponse.length())/2;
}
Log.e(“tlv长度:”,“字节:”+len_字节);
if(len_字节<128){
返回2;
}else if(len_字节>127&&len_字节<255){
返回4;
}否则{
返回6;
}
}
我无法正确获取少数卡片的长度(如果apdu响应很长)
请帮助

在进入代码之前,首先确保输入数据正确。获取完整的数据并试穿

一旦确认数据正确,请参阅EMV 4.3第3册, 附录B BER-TLV数据对象规则第B1、B2、B3节-特别注意


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

下面的示例假设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;
}   
publicstaticmap解析(bytebufferbb)抛出TlvException{
Map tlvs=null;
tlvs=新HashMap();
试一试{
而(bb.remaining()>0){
字节标记=bb.get();
如果(标记==0x00)
继续;
int length=bb.get();
字节[]值=新字节[长度];
bb.get(值,0,长度);
Tlv Tlv=新的Tlv(标签);
tlv.设定值(值);
tlv.put(标签、tlv);
}
}catch(IndexOutOfBoundsException e){
抛出新的TLVEException(“格式错误的TLV部分:“+bb.toString()+””,e);
}
返回TLV;
}   

可能重复的可能重复的请阅读问题,特别提到“无法正确获取少数卡片的长度”。请共享应用程序中解析不好的APDU。你能分享日志吗?问题不在于apdu。它是指在不使用任何库的情况下获取tlv中的数据长度。请阅读问题我已经在没有任何第三方库的情况下端到端地实现了它,只需遵循我共享的文档参考中的标记长度和值规范即可。再见。@UmaAchanta您需要实现多字节标记标识符(您最多只支持两个字节)和正确的多字节标记长度(看起来根本不像解析长度)。它在BER文档中有描述,您可以尝试作为一个合适的来源。长度在多个字节上编码时设置了最高有效位。您的解析方法不包括多字节标记标识符的覆盖范围(在第一个字节上设置了5个最低有效位的标识符,以及在第二个和以后的字节上可能指示最高有效位的标识符)。您的长度还不包括对多字节长度的支持(设置了最高有效位并指示长度字节数的长度)。