?本篇是多年前的存篇,出处不详。旧酒换新瓶,温故知新,有了新的理解。
TLV
格式几乎所有的通信都有协议,而几乎所有的需要在卡片和终端之间传送的数据(结构)都是**TLV**
格式的.
TLV
是tag
, length
和value
的缩写.一个基本的数据元就包括上面三个域. Tag唯一标识该数据元, length
是value
域的长度. value
就是数据本身了.
举个例子, 下面是一个tlv格式的AID(应用标识符)字节串9F0607A0000000031010
, 其中9F06
是tag
, 07
是长度, A0000000031010
就是AID本身的值了.
TLV
格式编码解析对于程序编写人员来说,如果有类似上面这样的一串TLV编码的字节串从卡片传过来, 怎么样从中提取我们想要的数据. 这就牵扯出TLV解码的问题了.
解析方法:
TLV编码
就是指先对Tag
编码,再对Length
编码,最后对Value
编码。BER编码的长度确定的编码方式就是这样的。
BER-TLV
编码 : 长度确定与长度不确定的编码方式BER编码有两种方式:
Identifier octets
、Length octets
和Contents octets
(可以和TLV对应)。Identifier octets
、Length octets
、Contents octets
、End-of-contents octets
。其中Length octets
为0x80,End-of-contents octets为0x00 00。每种类型都能够编码成长度确定的编码方式,但是有的类型不能够编码成长度不确定的编码方式。 DER-TLV
编码 : 只能使用长度确定的编码方式Identifier octets
由3部分组成Class
、P/C
和Tag number
。Identifier octets
的第一个字节的高2位为Class
,接下来一位为P/C
,其他位表示Tag number
。Class
有4中类型Universal(00)
、Application(01)
、Context-specific(10)
和Private(11)
。P/C
位如果为1
则表示是Constructed
的,为0
表示是Primitive
。0<=Tag number<=30
,则整个Identifieroctets
只有一个字节,否则第一个字节的后5位前为1,接下来找第一个最高位为0
的字节,该字节就是Identifier octets
的最后一个字节。从第二个字节到最后一个字节去掉最高位的值拼起来就是Tagnumber
的值。长度确定的编码方式的Length octets
有两种方法编码长度:
Length octets
(这种方式在我们讲解的secs协议中就有用到 《半导体:Gem/Secs基本协议库的开发(1)》)。后面的那些字节组成的就是长度值。长度值表示的是Contents octets
所占的字节数。DER
要求如果长度为0-127则要使用第一种方式,如果大于127则使用后一种方式。**其中BER-TLV
编码是ISO
定义一种规范,然后到了PBOC/EMV
里被简化了, 哪里被简化了呢?
举一个例子, tag
域在ISO
里可以有多个字节, 而PBOC/EMV
里规定只用前两个字节.
下面要讲的TLV解码就是基于PBOC/EMV
的简化版本.
首先看一下tag
域是怎样编码的. Tag
域占最多占两个字节. 编码规则如下面两幅图:
??
这两幅图. 第一个图是第一个字节的编码规则.
b8
和b7
两位标识tag
所属类别. 这个可以暂时不用理.b6
决定当前的TLV
数据是一个单一的数据和复合结构的数据. 复合的TLV
是指value
域里也包含一个或多个TLV
, 类似嵌套的编码格式.(嵌套编码也是很常见的格式,譬如在SIM中的klarf
协议格式,就是典型的嵌套格式)b5~b1
如果全为1,则说明这个tag
下面还有一个子字节.占两个字节, 否则tag
占一个字节.第二幅图:
tag
占用两个字节, 第二个字节的编码格式. B8决定tag是否还有后绪的字节存在,因为前面说过,PBOC/EMV
里的tag
最多占两个字节,所以该位保持为0.清楚了上面tag编码格式,可很容易写出tag域解码的代码了. 假设,终端接收到一人字节串,这个字节串保存在tlvData的字节数组里, 伪代码如下:
if ((tlvData[i]&0x20) != 0x20)//单一结构
{
if ((tlvData[i]&0x1f) == 0x1f)//tag两字节
{
tagIndex++;
//解析length域
//解析value域
}
else//tag单字节
{
//解析length域
//解析value域
}
}
else//复合结构
{
//复合结构可以考虑用递归的方法来实现.
}
length域
的解析Length域
的编码比较简单,最多有四个字节, 如果第一个字节的最高位b8为0, b7~b1的值就是value域的长度. 如果b8为1, b7~b1的值指示了下面有几个子字节. 下面子字节的值就是value域的长度.
value域
的解析已知·value域
的长度,那么解析自然也手到擒来的事情了,不详细赘述~