IC卡(银行卡)APDU数据格式TLV解析

前言

隔离上篇文章IC卡(智能卡)APDU通讯总结太久了,这次整理一下TLV数据解析的教程,供大家参考。有时候发送指令读取到IC卡数据,直接转 ASCII码就可以拿到自己想要的数据,和业务交互。但是银行卡读取到的报文数据了,直接转是行不通的。本文重点是数据解析,不是讲解与卡怎么发送指令通讯,发送什么指令(这种都是大同小异,遵循中国金融集成电路(IC)卡规范)。

TLV

PBOC(The People’s Bank of China 中国人民银行)的银行IC卡大部分数据都是 TLV(tag-length-value) 格式的(或者叫IC卡55域数据)。 TLV(BER(Basic Encoding Rules)是 ASN.1 中最早定义的编码规则,BER 传输语法的格式一直是 TLV 三元组) 是 tag, length 和 value 的缩写,tag是这个数据元的标示,length是这个数据元值的部分的长度,value则是该数据元的值。

Tag(标签)

注:字节排序方向为从左往右数,第一个字节即为最左边的字节。bit排序规则同理。

可以用下面一张图表示:

xBAnAO.png

tag在pboc中最多占两个字节,第一个字节的编码规则 。
b7 和 b6 两位标识 tag 所属类别 。00表示TLV描述的是基本数据类型(Primitive Frame, int,string,long…),01表示用户自定义类型(Private Frame,常用于描述协议中的消息
b5 决定当前的 TLV 数据是一个单一的数据(Primitive Data 编码)和复合结构的数据(Constructed Data编码) 。 复合的 TLV 是指 value 域里也包含一个或多个 TLV, 类似嵌套的编码格式 。

b4~b0 如果全为 1 ,则说明这个 tag下面还有一个子字节,占两个字节,否则tag占一个字节 。如果tag占用两个字节,第二个字节的编码格式, b7决定tag是否还有后绪的字节存在,bit7为1时存在后续字节,为0时不存在后续字节。bit6~bit0:Tag正文

举例说明:

  • 9F33(‭9F:1001 1111‬):为一个占用两个字节的tag标签。
  • 95(‭1001 0101‬):为一个占用一个字节的tag标签。

Length(长度)

length占1~3个字节长度,描述Value部分所占字节的个数,编码格式分两类:定长方式(DefiniteForm)和不定长方式(IndefiniteForm),其中定长方式又包括短形式与长形式。

定长方式

短形式: 字节第7位为0(最左边字节的最左bit位(即bit7为0)),表示Length使用1个字节即可满足Value类型长度的描述,它的后续7个bit位(即bit6~bit0)表示Value取值长度的范围在0~127之间的,把后续7bit转成十进制值即可表示Value的字节长度。

举例说明:

03(0000 0011):表示Value占用三个字节,所以,若Value的长度在1~127字节之间,那么该L字段本身仅占一个字节

长形式: 字节第7位为1(最左边字节的最左bit位(即bit7为1)),表示Length使用多个字节描述Value类型长度,Value类型的长度大于127时,bit6~bit0用来描述Length值占用的字节数,把bit6~bit0转成十进制值即可表示Value的字节长度。

举例说明:

81FF(1000 0001 1111 1111):1000 0001表示Value为长形式,占用一个字节,其Value的字节数为1111 1111即255个字节

所以,若Value的长度在128~255字节之间,那么该L字段本身**仅占两个字节 **

不定长方式

Length所在八位组固定编码为0x80,但在Value编码结束后以两个0x00结尾。这种方式使得可以在编码没有完全结束的情况下,可以先发送部分数据给对方。

举例说明:
1000 000 … 00:1000 000表示Value长度,value最后的两位是00

Value(数值)

由一个或多个值组成 ,值可以是一个原始数据类型(Primitive Data),也可以是一个TLV结构(Constructed Data)

单一结构(原始数据类型):T L V
复合结构(复合TLV结构):T L V(嵌套一个以上TLV)

示例解析说明

上面解释了TLV的组成原理,下面举例进行分析,最后附上解析代码。上面说了TLV数据格式有可能TLV嵌套TLV,编码解析使用递归解析。

下面是一个完整的TLV数据格式(复合结构,单一结构比较简单,不做举例说明),APDU正常通讯成功后,取返回数据Data和SW1 SW2,不记得APDU通讯数据格式请看IC卡(智能卡)APDU通讯总结

704D5A0A6221871000001018326F8E0C000000000000000002031F009F0D05D86004A8009F0E0500109800009F0F05D86804F8005F24032608315F280201569F0702FF005F25031608239F080200309000

9000: 正常 成功执行
704D5A0A6221871000001018326F8E0C000000000000000002031F009F0D05D86004A8009F0E0500109800009F0F05D86804F8005F24032608315F280201569F0702FF005F25031608239F08020030:要解析的数据

为方便观察,整理成表格,请点击查看,完整解析如下图:

xBlq9x.png

代码实现TLV解析

基于上面TLV组成原理编码实现如下:

核心解码类MyTlvDecode

public class MyTlvDecode {/*** 递归解析TLV格式数据** @param tlvHexStr* @param tlvs*/
public void decodeTLV(String tlvHexStr, List<TLV> tlvs) {if (tlvHexStr == null || tlvHexStr.length() == 0) {throw new NullPointerException("tlvHexStr 为null.");}if (tlvHexStr.length() % 2 != 0) {throw new IllegalArgumentException("tlvHexStr 参数非法.");}byte[] bytes = ByteUtils.hexStringToByteArr(tlvHexStr);decodeTLV(bytes, bytes.length, tlvs);
}/*** 递归解析TLV格式数据** @param tlvBytes* @param len* @param tlvs*/
public void decodeTLV(byte[] tlvBytes, int len, List<TLV> tlvs) {if (tlvBytes == null || tlvBytes.length == 0) {throw new NullPointerException("tlvBytes 为null.");}System.out.println(ByteUtils.byteArrToHexString(tlvBytes));byte[] tag;int vLength;int lLength;boolean complexTag = false;//bit与运算同为1才为1,0x20=00100000, b5=1是判断单一结构还是复合结构if ((tlvBytes[0] & 0x20) != 0x20) { // 单一结构if ((tlvBytes[0] & 0x1f) != 0x1f) { // tag占用一个字节,否则占用两个字节(b0-b5都是1)vLength = tlvBytes[1] == 0x81 ? tlvBytes[2] : tlvBytes[1];lLength = 2;//不定长方式if (vLength > 0x80) {lLength = 3;//定长方式}tag = new byte[1];} else {// tag为两个字节vLength = tlvBytes[2] == 0x81 ? tlvBytes[3] : tlvBytes[2];lLength = 3;if (vLength > 0x80) {lLength = 4;}tag = new byte[2];}if (vLength < 0) {throw new RuntimeException("TLV解码异常, vLength:" + vLength);}} else { // 复合结构complexTag = true;if ((tlvBytes[0] & 0x1f) != 0x1f) { // tag为一个字节vLength = tlvBytes[1] == 0x81 ? tlvBytes[2] : tlvBytes[1];lLength = 2;if (vLength > 0x80) {lLength = 3;}tag = new byte[1];} else {// tag为两个字节vLength = tlvBytes[2] == 0x81 ? tlvBytes[3] : tlvBytes[2];lLength = 3;if (vLength > 0x80) {lLength = 4;}tag = new byte[2];}if (vLength < 0) {throw new RuntimeException("TLV解码异常,tag:" + tag + ",vLength:" + vLength);}}//分别解析出T、L、VSystem.arraycopy(tlvBytes, 0, tag, 0, tag.length);byte[] value = new byte[vLength];System.arraycopy(tlvBytes, lLength, value, 0, value.length);String tagStr = ByteUtils.byteArrToHexString(tag);String tagValue = ByteUtils.byteArrToHexString(value);int tagLength = value.length;tlvs.add(new TLV(tagStr, tagLength, tagValue));if (complexTag){decodeTLV(value, tagLength, tlvs);}if (len > vLength + lLength) {byte[] nextTlv = new byte[len - (vLength + lLength)];System.arraycopy(tlvBytes, vLength + lLength, nextTlv, 0, nextTlv.length);decodeTLV(nextTlv, nextTlv.length, tlvs);}
}/*** @param args 测试程序*/public static void main(String[] args) {MyTlvDecode t = new MyTlvDecode();List<String> tlvArr = new ArrayList<>();tlvArr.add("704D5A0A6221871000001018326F8E0C000000000000000002031F009F0D05D86004A8009F0E0500109800009F0F05D86804F8005F24032608315F280201569F0702FF005F25031608239F080200309000");for (int i = 0; i < tlvArr.size(); i++) {List<TLV> tlvs = new LinkedList<>();long start = System.currentTimeMillis();byte[] bytes = ByteUtils.hexStringToByteArr(tlvArr.get(i));t.decodeTLV(bytes, bytes.length, tlvs);//        t.decodeTLV(tlvStr, tlvs);long end = System.currentTimeMillis();System.out.println("解析耗时:" + (end - start) + "ms");for (TLV tlv : tlvs) {System.out.println("tag:" + tlv.tag + ",length:" + tlv.length + ",value:" + tlv.value);}System.out.println("\n");}}}

实体TLV:

public class TLV {/** 标签 */public String tag;/** 长度 */public int length;/** 值 */public String value;public TLV(){}public TLV(String tag, int length, String value) {this.length = length;this.tag = tag;this.value = value;}//...}

运行结果如下:

解析耗时:1ms
tag:70,length:77,value:5A0A6221871000001018326F8E0C000000000000000002031F009F0D05D86004A8009F0E0500109800009F0F05D86804F8005F24032608315F280201569F0702FF005F25031608239F08020030
tag:5A,length:10,value:6221871000001018326F
tag:8E,length:12,value:000000000000000002031F00
tag:9F0D,length:5,value:D86004A800
tag:9F0E,length:5,value:0010980000
tag:9F0F,length:5,value:D86804F800
tag:5F24,length:3,value:260831
tag:5F28,length:2,value:0156
tag:9F07,length:2,value:FF00
tag:5F25,length:3,value:160823
tag:9F08,length:2,value:0030

然后对比文档就知道上面tag的含义了,上图表格中已经标标出

小结

本文主要介绍TLV的组成原理和解析方法,解析不保证100%通用,但适合大部分业务需求。TLV数据解析这种不难,多读几遍和实践几次,就可以熟能生巧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/33222.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用VISA编程入门教程

概述 下图示出对具有VISA的仪器进行控制的流程。当用可视Basic语言&#xff08;Visual Basic languagee&#xff09;开发VISA程序时&#xff0c;必须回顾一个特殊的编程注意事项&#xff08;在下面列出的自述文本文件中&#xff09;。 有关VISA程序库的利用以及利用带有E5071…

Zebec联合Visa推出实体借记卡持续利好生态,$ZBC表现强劲

Zebec联合Visa推出实体借记卡持续利好生态&#xff0c;$ZBC表现强劲 Zebec生态从今年年初开始&#xff0c;持续的释放利好提振市场信心。此前&#xff0c;Zebec曾以 10 亿美元的完全稀释估值筹集了 850 万美元&#xff0c;该轮融资投资者包括 Circle Ventures、Shima 和 Resolu…

visa虚拟卡生成器_虚拟银行卡汇总

为后续做跨境支付,提前储备虚拟银行卡渠道 1. 全球付http://www.globalcash.hk/​ 在线申请,可充值,微信支付,开卡简单。2. 爱汇旅之卡http://www.ihui.com/​此卡是目前最方便容易获得,并大量获得的实体mastercard实体卡,可以直接联系客服大量拿卡,一次上百张甚至是数…

VISA编程实例(C实现)

今天写这个文章&#xff0c;是因为自己工作中用到了ROHDE&SCHWARZ&#xff08;即罗德-施瓦茨公司&#xff09;的仪表设备&#xff0c;需要通过编程的方式来读取仪表上功率测试结果&#xff0c;本来仪表上显示了测试结果&#xff0c;不知道硬件部门为什么需要通过程序来获取…

visa虚拟卡生成器_英国虚拟卡 获取多张VISA和Mastercard

这是一家英国的虚拟卡平台,主要提供虚拟信用卡。 官方网址: https://www.swiftpaycard.com/cards.php 进入之后,点上角的sign up进行注册。不懂得可以网页翻译注册。 输入你的个人信息。类似姓名,邮箱,密码,用户名之类的。自己填好就行。然后就会提示你注册成功。并提示…

【编程实践】24个实用代码优化技巧实例讲解

写代码的同学都有一些明显的共性,整体来说都比较符合代码特性中的可读性、严谨性、扩展性的要求。本文将举例一些自己看到的代码以及感受建议,从以上三个角度进行总结,希望能够对大家日常编码有一些帮助。 ChatGLM: 优秀的程序员通常具备以下特质: 1. 良好的逻辑思维能力:…

OpenAI-ChatGPT最新官方接口《从0到1生产最佳实例》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(十一)(附源码)

Production Best Practices 生产最佳实例 前言Introduction 导言Setting up your organization 设置您的组织Managing billing limits 管理计费限额API keys API密钥Staging accounts 演示账户 Building your prototype 构建您的原型Additional tips 其它技巧 Techniques for i…

chatgpt赋能python:Python数据搜索指南

Python数据搜索指南 对于很多Python程序员来说&#xff0c;从互联网上查找数据是非常常见的需求。本文将介绍一些使用Python高效地搜索数据的技巧和工具。 Google Custom Search API Google Custom Search API是一个用于在Google搜索引擎中搜索内容的接口。使用该接口&#…

【Python】用python高效查询gptkey的额度(封装pytqt5版本)

文章目录 前言一、源码二、运行效果展示总结 前言 昨天发了python查询gpt-key剩余额度和近10天使用额度查询情况的源码&#xff0c;有伙伴反馈很实用&#xff0c;但是如果能封装UI版就更好了 那徐浪老师今天就给大家做一个封装吧&#xff01; 一、源码 话不多说&#xff0c;…

无需订阅的GPT-4?

上周末&#xff0c;MegaEase 创始人兼 CTO 陈皓老师&#xff08;左耳朵耗子&#xff09;在推特推荐了一款 ChatGPT 套壳网站 Forefront Chat&#xff0c;称其可以“免费使用 GPT-3.5 和 GPT-4”。溯源了一番&#xff0c;其官方 Forefront AI 公司在前一天进行了官宣&#xff1a…

异常检测专栏(一)异常检测概述

前言 异常检测一直是机器学习中一个活跃的研究领域&#xff0c;由于风险管理、合规、安全、将抗和医疗风险以及人工智能安全等广泛领域的需求和应用不断增加&#xff0c;异常检测发挥和越来越重要的总用。近年来&#xff0c;随着深度学习和计算机视觉技术的不断发展&#xff0c…

GPG密钥生成与使用教程

以下命令只需Ubuntu用户执行 sudo yum install gnupg 生成密钥 gpg --gen-key 密钥种类选择&#xff1a;键入1 RSA密钥长度&#xff1a;键入1024&#xff08;此操作仅为提高RSA生成的速度 密钥的有效期&#xff08;默认为0选项&#xff09;&#xff1a;回车 真实姓名&…

腾讯AI开放平台使用尝试:通过文本翻译API进行汉译英

这篇文章继续尝试使用腾讯AI开放平台提供的文本翻译API进行汉译英的示例说明。 目录 事前准备请求参数返回格式示例代码使用示例常见问题总结参考内容 事前准备 实现需要申请申请账号&#xff0c;获得如下接入凭证&#xff1a; AppID&#xff1a;应用IDAppKey&#xff1a;应…

GitHub英译中设置方法

GitHub 英译中设置方法 相信有很多小伙伴初次打算使用GitHub然后去浏览器搜索之后&#xff0c;发现打开官网内容全部是英文&#xff0c;这可难倒了很多英文不好的小伙伴。但凡事都有解决之道&#xff0c;我们只需要将GitHub官网的英文转换为中文就能够很好很快学习运用GitHub&…

现在各行各业的人们越来越多地依靠计算机来解决各种难题.翻译英语,公共英语PETS三级阅读与翻译试题训练 四...

三级英语汉译英 1、他这次考试失败使他意识到定期复习功课是多么重要。 He failed in the exam, which has made him aware of the importance of reviewing his lessons regularly. 2、请一定不要忘记离家前你父母对你说过的话。 Be sure not to forget what your parents sai…

论文中文翻译成英文有什么好办法?

不知道大家是否想过这个问题&#xff1a;到大学为止&#xff0c;我们可以说已经学了十年英语了&#xff0c;但为什么英语水平高的人却没有那么多&#xff1f;尤其是涉及英语口语或写作这种需要输出的内容&#xff0c;对我们来说更是难上加难。原因主要在于&#xff0c;我们的思…

Abaqus取消汉化(汉译英,英译汉)

1、创建abaqus 桌面快捷方式 拖拽到桌面上即可 2、打开文件所在位置 3、点击win_b64 4、然后依次打开 win_b64--->SMA---->Configuration--->locale 5、加 和 改 汉化&#xff1a;在1处添加 Chinese (Simplified)_China.936zh_CN 在2处把 0 改成 1 汉化取消&…

AndroidStudio翻译辅助工具(中译英与英译中)

1.设置 File -> Settings 2.Browse repositories File -> Settings->Plugins->Browse repositories… 3.下载Translation 4.Restore点击一下 5.重启一下 6.申请ID和密匙 自己随便注册一下即可 7 创建有道智云实例 名字随便写 翻译实例-》创建实例 8 创建应…

微信小程序 通过百度API接口实现汉译英翻译

目录 先看一下做出来的效果&#xff1a; 一、微信开发平台的网址&#xff08;微信开发者工具的官方使用说明&#xff09; 二、百度API&#xff08;文本翻译的API&#xff09; 三、进入正文&#xff0c;微信小程序的代码部分 先看一下做出来的效果&#xff1a; 一、微信开发…

Python实现汉译英

引言 你是否还在用老套的方式网页打开数据&#xff1f;你是否想要打造一个属于自己的翻译程序&#xff1f; 看完这篇博客实现你的梦想&#xff0c;打造一个属于自己的翻译器。 代码解析 首先我们要导入两个库爬虫库&#xff08;requests&#xff09;和json库。Requests库就不多…