Есть ли анализатор Java для BER-TLV?

Я новичок в Java, поэтому я хотел бы использовать стандартное решение для стандартной задачи. Длина тегов и значений неизвестна.

7 ответов

Вы можете использовать этот анализатор BER-TLV: исходный код на git или скачать jar.
Примеры:

Как разобрать

byte[] bytes = HexUtil.parseHex("50045649534157131000023100000033D44122011003400000481F");
BerTlvParser parser = new BerTlvParser(LOG);
BerTlvs tlvs = parser.parse(bytes, 0, bytes.length);

Как построить

byte[] bytes =  new BerTlvBuilder()
                .addHex(new BerTag(0x50), "56495341")
                .addHex(new BerTag(0x57), "1000023100000033D44122011003400000481F")
                .buildArray();

Maven зависимость

<!-- https://mvnrepository.com/artifact/com.payneteasy/ber-tlv -->
<dependency>
    <groupId>com.payneteasy</groupId>
    <artifactId>ber-tlv</artifactId>
    <version>1.0-8</version>
</dependency>

Учебник здесь дает советы о том, как разобрать BER-TLV. Использование JACCAL

Я сделал простой парсер на основе информации, представленной здесь: http://www.codeproject.com/Articles/669147/Simple-TLV-Parser

Я не знаю, поддерживает ли этот код все стандарты, но он работает для меня.

public static Map<String, String> parseTLV(String tlv) {
    if (tlv == null || tlv.length()%2!=0) {
        throw new RuntimeException("Invalid tlv, null or odd length");
    }
    HashMap<String, String> hashMap = new HashMap<String, String>();
    for (int i=0; i<tlv.length();) {
        try {
            String key = tlv.substring(i, i=i+2);

            if ((Integer.parseInt(key,16) & 0x1F) == 0x1F) {
                // extra byte for TAG field
                key += tlv.substring(i, i=i+2);
            }
            String len = tlv.substring(i, i=i+2);
            int length = Integer.parseInt(len,16);

            if (length > 127) {
                // more than 1 byte for lenth
                int bytesLength = length-128;
                len = tlv.substring(i, i=i+(bytesLength*2));
                length = Integer.parseInt(len,16);
            }
            length*=2;

            String value = tlv.substring(i, i=i+length);
            //System.out.println(key+" = "+value);
            hashMap.put(key, value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("Error parsing number",e);
        } catch (IndexOutOfBoundsException e) {
            throw new RuntimeException("Error processing field",e);
        }
    }

    return hashMap;
}

Пример кода C# для декодирования bertTlv

Подробности кода здесь

      public class Tlv : ITlv, IFile
{
    List<TlvModel> modelList=new();
    string parser = "";
    string length = "";
    String empty = "";
    string ascii = "";
    int decValue = 0;
    int step = 0;
    public Tlv(String data)
    {
        TlvParser(data.Replace(" ",""));
    }
    public void readTag()
    {
        String line = "";
        StreamReader sr = new StreamReader("taglist.txt");
        while ((line = sr.ReadLine()) != null)
        {
            modelList.Add(new()
            {
                tag = line.Split(",")[0].Trim(),
                description = line.Split(",")[1].Trim()
            });

        }
        sr.Close();


    }
    public void insertTag()
    {
        try
        {
            StreamWriter sw = new StreamWriter("test.txt");
            foreach (var item in modelList)
            {
                sw.WriteLine($"{item.tag},{item.description}");
            }
            sw.Close();
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception: " + e.Message);
        }

    }
    public int writeFile(String parser)
    {
        StreamWriter sw = new StreamWriter("output.txt");
        sw.WriteLine(parser);
        sw.Close();
        return 0;
    }

    private int TlvParser(String data, int i = 0, string tag = "")
    {
        if (i == 0)
        {
            readTag();
        }
        if (i < data.Length)
        {
            tag += data[i];
            TlvModel model = getTag(tag);
            if (model != null)
            {

                decValue = int.Parse(data.Substring(i + 1, 2), System.Globalization.NumberStyles.HexNumber);
                // lengthControl(data,i+3,decValue);
                if (model.description.Contains("Template"))
                {
                    parser += $"{empty}|------ tag: {model.tag}({model.description})\n";
                    step += 1;
                    empty = Empty();
                    return TlvParser(data, i + 3, "");
                }
                else
                {
                    parser += $"{empty}|------ tag: {model.tag}({model.description}){empty}|------ value -->  {ConvertHex(data.Substring(i + 3, decValue * 2))} \n";
                }
                i += 3 + decValue * 2;
                return TlvParser(data, i, "");

            }
            else
            {
                return TlvParser(data, i + 1, tag);
            }
        }
        return writeFile(parser);

    }

    public TlvModel getTag(string tag)
    {
        return modelList.Find(i => i.tag == tag);
    }

    public string ConvertHex(string hex)
    {

        ascii = "";
        for (int i = 0; i < hex.Length; i += 2)
        {
            ascii += System.Convert.ToChar(System.Convert.ToUInt32(hex.Substring(i, 2), 16));
        }
        return ascii;
    }

    private string Empty()
    {
        for (int s = 0; s < step; s++)
        {
            empty += "\t";
        }
        return empty;
    }

    public void setTag(TlvModel model)
    {
        modelList.Add(model);
        insertTag();
    }
}

Я нашел классы Javacard для BER TLV. Надеюсь, что те помогают

Может быть, эта бесплатная библиотека может быть полезна для вас. Я использовал этот для простого анализа TLV. В любом случае это лицензия MIT, и вы можете ее изменить.

https://github.com/VakhoQ/tlv-encoder
Другие вопросы по тегам