SIMPLE-TLV vs BER-TLV
Asked Answered
M

3

24

I have found in docs they are referring to SIMPLE-TLV and BER-TLV . I was look into most of the EMV and GP docs but they have not mentioned the different.

Could anyone help me to understand the difference of two ?

Midterm answered 17/9, 2013 at 15:23 Comment(0)
G
44

Data fields in ISO/IEC 7816-4 for smart cards

BER encoding

This is the specification of the more common BER encoding used by ISO/IEC 7816-4:

Each BER-TLV data object shall consists of 2 or 3 consecutive fields (see ISO/IEC 8825 and annex D).

The tag field T consists of one or more consecutive bytes. It encodes a class, a type and a number. The length field consists of one or more consecutive bytes. It encodes an integer L. If L is not null, then the value field V consists of L consecutive bytes. If L is null, then the data object is empty: there is no value field.

Note that ISO/IEC 7816 only allows the use of up to 5 length bytes (specifying a size up to 2^32 - 1 bytes) in the current standard. Indefinite length encoding is not supported either. These limitations are specific to smart cards. Note that 4 and 5 byte length encodings were introduced in a later version of ISO/IEC 7816-4; earlier cards / card reading applications may only support 3 length bytes (i.e. a value size up to 64KiB bytes, instead of 4GiB).

The BER TLV specification is much more expansive (which is why SIMPLE-TLV is called "simple"). I won't go into the details too much as there is plenty of information available on the internet. To name just a few differences, the tags have syntactical meaning and may consist of multiple bytes and the length encoding is rather complex.

Normally BER should only be used as an encoding of ASN.1 structures, with the ASN.1 syntax defining the structure. ISO 7816-4 however messes this up and only specifies the BER tag bytes directly.

Note that sometimes DER is specified instead of BER. In that case you should only use the minimum number of bytes for the size of the length field - e.g. a single length byte with value 05 in the samples below. The ISO/IEC specification of BER encoding is basically a copy of the US specific X.690 standard, also reflected in the international standard ISO/IEC 8825-1 (both payware).

SIMPLE-TLV encoding

The BER specification in ISO/IEC 7816-4 is followed by the SIMPLE-TLV specification. SIMPLE-TLV is specific to ISO 7816-4.

Each SIMPLE-TLV data object shall consist of 2 or 3 consecutive fields.

The tag field T consists of a single byte encoding only a number from 1 to 254 (e.g. a record identifier). It codes no class and no construction-type. The length field consists of 1 or 3 consecutive bytes. If the leading byte of the length field is in the range from '00' to 'FE', then the length field consists of a single byte encoding an integer L valued from 0 to 254. If the leading byte is equal to 'FF', then the length field continues on the two subsequent bytes which encode an integer L with a value from 0 to 65535. If L in not null, then the value field V consists of consecutive bytes. If L is null, then the data object is empty: there is no value field.

Note that the standard forgets to specify the endianness directly. You can however assume big endian encoding within ISO/IEC 7816-4.

Samples

The following samples are all used to convey the same tag number (which defines the field) and value, except one that defines tag number 31 for BER.

Sample SIMPLE-TLV

0F 05 48656C6C6F                 // tag number 15, length 5 then the value
0F FF0005 48656C6C6F             // tag number 15, length 5 (two bytes), then the value

Sample BER-TLV:

4F 05 48656C6C6F                 // *application specific*, primitive encoding of tag number 15, length 5 then the value
4F 8105 48656C6C6F               // the same, using two bytes to encode the length
4F 820005 48656C6C6F             // the same, using three bytes to encode the length
4F 83000005 48656C6C6F           // the same, using four bytes to encode the length
4F 8400000005 48656C6C6F         // the same , using five bytes to encode the length
5F0F 05 48656C6C6F               // **invalid** encoding of the same, with two bytes for the tag, specifiying a tag number 15 which is smaller than 31
5F1F 05 48656C6C6F               // application specific, primitive encoding of **tag number 31**

In the last example with the two byte tag encoding, the first byte is 40 hex, where the first 3 leftmost bits 010 specify application specific encoding, adding the magic value 1F (31) to it to indicate that another byte will follow with the actual tag number, again 1F, so value 31.

Differences

The following differences should be noted:

  • SIMPLE-TLV is a different method of encoding for tag and length (although the encoding may look similar, e.g. when using a single byte to indicate the length part)
  • SIMPLE-TLV does not contain information about the class of the field, e.g. if it is defined for ASN.1 (because it is not linked to ASN.1)
  • SIMPLE-TLV does not contain information if it is primitive or constructed (primitive directly specifies a value, constructed means nested TLV structures)
  • SIMPLE-TLV has restrictions regarding the tag number (between 1 and 254, inclusive) and length (up to 65535)
Graziano answered 21/9, 2013 at 12:34 Comment(2)
To prevent confusion. Part 4 of the standard (ISO/IEC 7816-4) Annex D describes the use of basic encoding rules ASN.1 and the encoding with BER-TLV. It dictates the use of BER-TLV for the encoding of data interchanged. It just happens to use BER-TLV, but in other ways BER-TLV has nothing to do with ISO/IEC 7816.Floruit
@Floruit I'm pretty sure paragraph 6.2 also specifies BER for Data Object encoding. This is at least present since the 98 spec, and I've checked against the 2013 version (although versions before 2005 only specified up to a 3 byte length field, if I'm not mistaken).Graziano
Q
8

Simple TLV simply consists of Tag (or Type), Length, and Value.

The BER-TLV is a special TLV which has one or more TLV inside its Value. So it has composite structure.

Tag1 Len1 Tag2-Len2-Value2 Tag3-Len3-Value3 ... TagN-LenN-ValueN
          ------------------------Value1------------------------
Quantic answered 19/9, 2013 at 8:2 Comment(1)
That is not the only difference. Simple TLV has a set length for tag and length parts of a data unit, while BER-TLV can have variable tag and length lengths. A tag can be held in 1 or 3 bytes, the data length can be held in 1 or 5 bytes... in Simple TLV its always 1 or always 2 or always 3 etc.Referee
S
1

[Example C# code for Bert-Tlv Parser][1]: [1]https://github.com/umitkoc/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();
    }
}
Satiety answered 17/9, 2013 at 15:23 Comment(1)
If you need a dotnet version then the nuget package nuget.org/packages/Great.EmvTags works well.Scriptural

© 2022 - 2024 — McMap. All rights reserved.