什么是 TLV

TLV(Tag-Length-Value) 是一种灵活的数据编码格式,广泛应用于智能卡、金融支付、网络协议等领域。它通过”标签-长度-值”三元组的方式组织数据,使得数据结构具有良好的可扩展性和自描述性。

基本结构

1
2
3
4
5
+--------+--------+------------------+
| Tag | Length | Value |
+--------+--------+------------------+
| 标签 | 长度 | 数据 |
+--------+--------+------------------+
  • Tag(标签):标识数据的类型或用途,通常为 1-2 个字节
  • Length(长度):表示 Value 部分的字节数,可变长度
  • Value(值):实际的数据内容,长度由 Length 字段指定

TLV 的应用场景

1. 银行卡 IC 卡数据

1
2
3
4
5
示例数据:57 09 4333353138303631329000
解析结果:
Tag: 57 (卡号)
Length: 09 (9字节)
Value: 4333353138303631329000 (实际卡号数据)

2. EMV 支付终端

  • 交易授权数据
  • 持卡人信息
  • 卡片认证数据

3. 网络协议

  • ASN.1 编码
  • SNMP 协议
  • LDAP 协议

4. 物联网设备

  • 传感器数据上报
  • 设备配置信息
  • 状态监控数据

TLV 数据格式详解

Tag(标签)字段

单字节 Tag

1
2
3
4
5
6
7
8
9
10
二进制结构:
┌─────┬─────┬────────┐
│ b8 │ b7 │ b6-b1 │
├─────┼─────┼────────┤
│类别 │构造 │标签号 │
└─────┴─────┴────────┘

b8-b7: 00=Universal, 01=Application, 10=Context, 11=Private
b6: 0=基本型(Primitive), 1=构造型(Constructed)
b5-b1: 标签号(1-30)

示例:

1
2
3
4
0x57 = 01010111
├─ 01: Application类
├─ 0: 基本型
└─ 10111: 标签号23(卡号)

多字节 Tag

当标签号大于 30 时,使用多字节表示:

1
2
3
4
5
6
第一字节:b5-b1全为1(0x1F)
后续字节:最高位为1表示继续,为0表示结束

示例:0x9F61
0x9F = 10011111 (第一字节,b5-b1=11111)
0x61 = 01100001 (第二字节,最高位=0,结束)

Length(长度)字段

短格式(0-127 字节)

1
2
0x00 - 0x7F: 直接表示长度
示例:0x09 = 9字节

长格式(128 字节以上)

1
2
3
4
5
6
7
8
9
第一字节:0x81-0x84
0x81: 后续1个字节表示长度
0x82: 后续2个字节表示长度
0x83: 后续3个字节表示长度
0x84: 后续4个字节表示长度

示例:0x82 01 00
0x82: 使用2字节表示长度
0x01 0x00: 长度为256字节

Value(值)字段

基本型(Primitive)

Value 包含实际的数据内容:

1
2
Tag: 57 (卡号)
Value: 直接存储卡号数据

构造型(Constructed)

Value 包含嵌套的 TLV 结构:

1
2
3
4
5
Tag: 70 (数据模板)
Value: 包含多个子TLV结构
└─ TLV1: 57 09 43... (卡号)
└─ TLV2: 5F20 0C ... (持卡人姓名)
└─ TLV3: 9F61 12 ... (身份证号)

常见编码方式

1. 十六进制(HEX)

1
2
原始数据:57 09 4333353138303631329000
用途:调试、日志记录

2. BCD 编码(Binary Coded Decimal)

1
2
3
数值:6225123456789012
BCD: 62 25 12 34 56 78 90 12
用途:卡号、金额

3. ASCII 编码

1
2
3
文本:"VISA"
ASCII: 56 49 53 41
用途:简单字符串

4. UTF-8/GBK 编码

1
2
3
4
中文:"张三"
GBK: D5 C5 C8 FD
UTF-8: E5 BC A0 E4 B8 89
用途:持卡人姓名等

🎨 银行卡常用 Tag

卡片信息

Tag 名称 编码方式 示例
57 卡号(Track 2) BCD 62251234567890129000
5A 应用主账号(PAN) BCD 6225123456789012
5F20 持卡人姓名 GBK/UTF-8 张三
5F24 应用失效日期 BCD 251231 (2025 年 12 月 31 日)

交易相关

Tag 名称 编码方式 说明
9F02 授权金额 BCD 000000010000 (100.00 元)
9F03 其他金额 BCD 000000000000
9F1A 终端国家代码 ASCII CN (中国)
9F33 终端性能 HEX E0F8C8

持卡人信息

Tag 名称 编码方式 说明
9F61 持卡人证件号码 ASCII/BCD 身份证号
9F62 持卡人证件类型 HEX 00=身份证

解析流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
原始数据:57 09 4333353138303631329000

第1步:读取Tag
├─ 读取:0x57
├─ 判断:单字节Tag(b5-b1 ≠ 11111)
├─ 类型:基本型(b6=0)
└─ 结果:Tag = "57"

第2步:读取Length
├─ 读取:0x09
├─ 判断:短格式(< 0x80)
└─ 结果:Length = 9字节

第3步:读取Value
├─ 读取:43 33 35 31 38 30 36 31 32
├─ 后续:90 00
└─ 结果:Value = 9字节数据

第4步:解析Value
├─ Tag=57 → 卡号
├─ 编码:BCD
├─ 处理:去除D后的数据
└─ 结果:433351380631329

TLV 的优势

1. 灵活性

1
2
3
可以任意添加新的Tag,无需修改已有结构
原有数据:57 09 ... (卡号)
添加数据:57 09 ... + 5F20 0C ... (姓名)

2. 可扩展性

1
2
3
4
支持嵌套结构,可以表示复杂的数据关系
70 1A (数据模板)
57 09 ... (卡号)
5F20 0C ... (姓名)

3. 自描述性

1
2
3
4
通过Tag就能知道数据的含义,不需要额外的文档
57 = 卡号
5F20 = 持卡人姓名
9F79 = 卡片余额

4. 向后兼容

1
旧系统可以忽略不认识的Tag,继续处理已知的数据

解析注意事项

1. Tag 字节数判断

1
2
3
4
5
// 检查是否为多字节Tag
if ((firstByte & 0x1F) == 0x1F)
{
// 需要读取后续字节
}

2. Length 格式判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 判断长度格式
if (length <= 0x7F)
{
// 短格式
}
else if (length == 0x80)
{
// 不定长格式(不常用)
}
else
{
// 长格式
int lenOfLen = length & 0x7F;
}

3. 构造型递归解析

1
2
3
4
5
6
7
8
// 判断是否为构造型
bool isConstructed = (firstByte & 0x20) != 0;

if (isConstructed)
{
// 递归解析Value中的嵌套TLV
ParseTlvRecursive(value);
}

4. 编码方式选择

1
2
3
4
5
6
7
8
// 根据Tag选择合适的编码方式
switch (tag)
{
case "57": // 卡号 - BCD
case "5F20": // 姓名 - GBK
case "4F": // AID - HEX
case "9F61": // 身份证 - ASCII/BCD
}

实际应用示例

银行卡读卡数据

1
2
3
4
5
6
7
8
9
10
11
原始数据:
70 29
57 09 62 25 12 34 56 78 90 12 90 00
5F20 06 D5 C5 C8 FD
9F79 06 00 00 00 01 00 00

解析结果:
数据模板 (70)
├─ 卡号 (57): 6225123456789012
├─ 持卡人姓名 (5F20): 张三
└─ 卡片余额 (9F79): 100.00元

支付交易数据

1
2
3
4
5
6
原始数据包含:
- 交易金额
- 交易类型
- 终端信息
- 卡片信息
- 认证数据

总结

TLV 格式的核心优势:

  1. 结构清晰 - Tag-Length-Value 三部分职责明确
  2. 易于扩展 - 新增字段不影响现有结构
  3. 自我描述 - 通过 Tag 即可知道数据含义
  4. 嵌套支持 - 支持复杂的层次化数据结构

在下一篇文章中,我们将展示如何用 C#实现完整的 TLV 解析器,支持递归解析、多种编码方式和银行卡数据处理。


理解 TLV 格式是处理智能卡、金融支付等领域数据的基础。掌握其原理后,你就能轻松应对各种 IC 卡数据解析需求!