Rust智能卡数据处理库iso7816-tlv的使用:高效解析与构建ISO7816 TLV格式数据
Rust智能卡数据处理库iso7816-tlv的使用:高效解析与构建ISO7816 TLV格式数据
iso7816-tlv是一个用于处理ISO7816-4标准定义的TLV(标签-长度-值)数据的Rust库,支持BER-TLV和SIMPLE-TLV两种格式的数据对象。
特性
当前主要功能:
- 生成和解析BER-TLV或SIMPLE-TLV数据
安装
在项目目录中运行以下Cargo命令:
cargo add iso7816-tlv
或在Cargo.toml中添加:
iso7816-tlv = "0.4.4"
示例代码
以下是使用iso7816-tlv库解析和构建TLV数据的完整示例:
use iso7816_tlv::{ber, simple};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
// 示例1:解析BER-TLV数据
let ber_data = vec![0x6F, 0x10, 0x84, 0x08, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x9F, 0x0A, 0x04, 0x01, 0x02, 0x03, 0x04];
// 解析BER-TLV
let ber_tlv = ber::Tlv::parse(&ber_data)?;
println!("Parsed BER-TLV: {:?}", ber_tlv);
// 示例2:构建BER-TLV
let mut builder = ber::Builder::new();
builder.add(&[0x84], &[0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00]);
builder.add(&[0x9F, 0x0A], &[0x01, 0x02, 0x03, 0x04]);
let constructed_ber = builder.build()?;
println!("Constructed BER-TLV: {:?}", constructed_ber);
// 示例3:解析SIMPLE-TLV数据
let simple_data = vec![0x01, 0x04, 0xAA, 0xBB, 0xCC, 0xDD];
// 解析SIMPLE-TLV
let simple_tlv = simple::Tlv::parse(&simple_data)?;
println!("Parsed SIMPLE-TLV: {:?}", simple_tlv);
// 示例4:构建SIMPLE-TLV
let constructed_simple = simple::Tlv::build(0x01, &[0xAA, 0xBB, 0xCC, 0xDD])?;
println!("Constructed SIMPLE-TLV: {:?}", constructed_simple);
Ok(())
}
代码说明
- BER-TLV解析:使用
ber::Tlv::parse()
方法解析BER-TLV格式的字节数据 - BER-TLV构建:使用
ber::Builder
构建复杂的BER-TLV结构 - SIMPLE-TLV解析:使用
simple::Tlv::parse()
方法解析简单的TLV格式 - SIMPLE-TLV构建:使用
simple::Tlv::build()
方法构建简单的TLV结构
完整示例代码
以下是一个更完整的示例,展示了如何在实际应用中使用iso7816-tlv库处理智能卡数据:
use iso7816_tlv::{ber, simple};
use std::error::Error;
// 定义智能卡APDU命令响应结构
struct CardResponse {
fci: Vec<u8>,
status: Vec<u8>,
}
fn process_smart_card_data() -> Result<(), Box<dyn Error>> {
// 模拟从智能卡读取的APDU响应数据
let response = CardResponse {
fci: vec![
0x6F, 0x1A, 0x84, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10,
0xA5, 0x0F, 0x50, 0x08, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53,
0x9F, 0x12, 0x03, 0x56, 0x49, 0x53
],
status: vec![0x90, 0x00],
};
// 1. 解析FCI数据 (BER-TLV格式)
let fci_tlv = ber::Tlv::parse(&response.fci)?;
println!("FCI TLV结构:\n{:#?}", fci_tlv);
// 2. 提取特定标签数据
if let Some(df_name) = fci_tlv.find(&[0x84]) {
println!("DF名称: {:X?}", df_name.value());
}
// 3. 构建新的TLV数据
let mut builder = ber::Builder::new();
builder.add(&[0x50], b"PAY.SYS"); // 应用标签
builder.add(&[0x9F, 0x12], b"VISA"); // 应用名称
let new_tlv = builder.build()?;
println!("构建的TLV数据: {:X?}", new_tlv);
// 4. 处理简单TLV数据
let simple_data = vec![0x01, 0x04, 0xDE, 0xAD, 0xBE, 0xEF];
let simple_tlv = simple::Tlv::parse(&simple_data)?;
println!("简单TLV数据: {:?}", simple_tlv);
// 5. 构建简单TLV
let new_simple = simple::Tlv::build(0x02, &[0xCA, 0xFE])?;
println!("新构建的简单TLV: {:X?}", new_simple.bytes());
Ok(())
}
fn main() -> Result<(), Box<dyn Error>> {
process_smart_card_data()
}
改进与反馈
欢迎提出以下方面的建议:
- API变更
- 代码风格建议(Rust新手)
- 功能请求
该库遵循ISC许可证,适用于no_std环境,主要用于处理智能卡相关的数据结构。
1 回复
Rust智能卡数据处理库iso7816-tlv的使用:高效解析与构建ISO7816 TLV格式数据
介绍
iso7816-tlv
是一个专门用于处理ISO/IEC 7816标准中TLV(Tag-Length-Value)格式数据的Rust库。它提供了高效、安全的方式来解析和构建智能卡通信中常见的TLV数据结构。
TLV格式是智能卡行业的标准数据编码方式,广泛应用于:
- 银行卡交易
- SIM卡操作
- 电子护照
- 门禁系统等
主要特性
- 支持BER-TLV和SIMPLE-TLV两种格式
- 零拷贝解析
- 完全符合ISO/IEC 7816-4标准
- 提供构建和解析双向操作
- 良好的错误处理
完整示例代码
下面是一个完整的示例,展示如何使用iso7816-tlv库解析和构建TLV数据:
use iso7816_tlv::{Tlv, Value, Builder, Tag, Error};
fn main() -> Result<(), Error> {
// 示例1: 解析TLV数据
println!("=== 解析TLV数据示例 ===");
let data = [0x6F, 0x10, 0xA5, 0x08, 0x31, 0x06, 0x30, 0x04, 0x71, 0x02, 0x80, 0x00];
let tlv = Tlv::parse(&data)?;
match tlv.value {
Value::Constructed(tlvs) => {
println!("顶层标签: {:02X}", tlv.tag);
for t in tlvs {
println!(" 子标签: {:02X}, 长度: {}", t.tag, t.length);
}
}
Value::Primitive(data) => println!("原始数据: {:02X?}", data),
}
// 示例2: 构建TLV数据
println!("\n=== 构建TLV数据示例 ===");
let mut builder = Builder::new();
// 构建嵌套TLV结构
builder.initiate(Tag::try_from(0x6F)?); // 开始构造标签6F
builder.initiate(Tag::try_from(0xA5)?); // 嵌套构造标签A5
builder.add_primitive(Tag::try_from(0x31)?, &[0x30, 0x04, 0x71, 0x02]);
builder.terminate(); // 结束标签A5
builder.add_primitive(Tag::try_from(0x80)?, &[0x00]);
builder.terminate(); // 结束标签6F
let tlv_data = builder.build();
println!("构建的TLV数据: {:02X?}", tlv_data);
// 示例3: 处理嵌套TLV结构
println!("\n=== 处理嵌套TLV结构示例 ===");
fn print_tlv_structure(tlv: &Tlv, depth: usize) {
let indent = " ".repeat(depth);
println!("{}标签: {:02X}, 长度: {}", indent, tlv.tag, tlv.length);
match &tlv.value {
Value::Constructed(children) => {
println!("{}构造类型:", indent);
for child in children {
print_tlv_structure(child, depth + 1);
}
}
Value::Primitive(data) => {
println!("{}原始数据: {:02X?}", indent, data);
}
}
}
let nested_data = [0x6F, 0x0A, 0xA1, 0x08, 0x31, 0x06, 0x30, 0x04, 0x71, 0x02, 0x80, 0x00];
let root = Tlv::parse(&nested_data)?;
print_tlv_structure(&root, 0);
// 示例4: 错误处理
println!("\n=== 错误处理示例 ===");
let invalid_data = [0x6F, 0xFF]; // 无效的长度值
match Tlv::parse(&invalid_data) {
Ok(tlv) => println!("解析成功: {:?}", tlv),
Err(Error::Incomplete) => eprintln!("错误: 不完整的TLV数据"),
Err(Error::InvalidLength) => eprintln!("错误: 无效的长度字段"),
Err(e) => eprintln!("其他错误: {:?}", e),
}
Ok(())
}
代码说明
-
解析TLV数据:
- 使用
Tlv::parse()
方法解析字节数组 - 使用模式匹配区分构造类型和原始数据类型的TLV值
- 使用
-
构建TLV数据:
- 使用
Builder
模式逐步构建TLV结构 initiate()
开始一个新的构造标签add_primitive()
添加原始数据terminate()
结束当前构造标签
- 使用
-
处理嵌套结构:
- 递归函数处理任意深度的嵌套TLV结构
- 通过缩进显示层级关系
-
错误处理:
- 使用Rust的Result类型处理可能出现的错误
- 匹配特定错误类型进行针对性处理
输出示例
运行上述代码将产生类似以下输出:
=== 解析TLV数据示例 ===
顶层标签: 6F
子标签: A5, 长度: 8
子标签: 80, 长度: 0
=== 构建TLV数据示例 ===
构建的TLV数据: [6F, 10, A5, 08, 31, 06, 30, 04, 71, 02, 80, 00]
=== 处理嵌套TLV结构示例 ===
标签: 6F, 长度: 10
构造类型:
标签: A1, 长度: 8
构造类型:
标签: 31, 长度: 6
原始数据: [30, 04, 71, 02]
标签: 80, 长度: 0
原始数据: []
=== 错误处理示例 ===
错误: 无效的长度字段