EMV/PBOC解析(三) TLV格式解析(C#)
1.什么是TLV格式?
TLV即Tag-Length-Value,常在IC卡与POS终端设备中通过这样的一个应用通信协议进行数据交换。 金融系统中的TLV是BER-TLV编码的一个特例编码规范,而BER-TLV是ISO定义中的规范。在TLV的定义中,可以知道它包括三个域,分别为:标签域(Tag),长度域(Length),内容域(Value)。这里的长度域的值实际上就是内容域的长度。 其实,在BER编码的方式有两种情况,一种是确定长度的方式,一种是不确定长度的方式,而金融TLV选择了确定长度的方式,这样在设备之间的数据传输量上就可以减少。
2.Tag域
3.Length域
当b8为0时,该字节的b7-b1作为value域的长度;当b8为1时,b7-b1作为后续字节的长度。例:10000011,代表后续还有3个字节作为value域的长度(本字节不算,本字节变为作为一个Length的索引)。3个字节代表value的长度,意味着什么呢,意味着内容的长度当需要很大的时候,字节的位数就会跟着越高,3个字节就代表最大可以有256*256*256的长度。
4.Value域
分成两种情况考虑,就是前面说到的Tag分成两个数据元结构,一种是简单数据元结构,一种是复合数据元架构:
先来看看简单数据元结构:
复合数据元结构:
5.TLV格式数据实例
数据: 5F2D027A68
Tag域
5F → 01011111 → 5F 2D → 00101101 → 5F2D
Length域
02 → 00000010 → 02(2字节)
Value域
7A68
6.算法实现 C#
首先根据定义创建一个实体类
1 /// <summary> 2 /// TLV格式报文实体类 3 /// </summary> 4 public class TLVEntity 5 { 6 /// <summary> 7 /// 标记 8 /// </summary> 9 public byte[] Tag { get; set; } 10 11 /// <summary> 12 /// 数据长度 13 /// </summary> 14 public byte[] Length { get; set; } 15 16 /// <summary> 17 /// 数据 18 /// </summary> 19 public byte[] Value { get; set; } 20 21 /// <summary> 22 /// 标记占用字节数 23 /// </summary> 24 public int TagSize { get { return this.Tag.Length; } } 25 26 /// <summary> 27 /// 数据长度占用字节数 28 /// </summary> 29 public int LengthSize { get { return this.Length.Length; } } 30 31 /// <summary> 32 /// 子嵌套TLV实体列表 33 /// </summary> 34 public List<TLVEntity> SubTLVEntity { get; set; } 35 }
下面是tlv格式报文打包解析
1 /// <summary> 2 /// TLV格式报文打包解析 3 /// </summary> 4 public class TLVPackage 5 { 6 #region TLV 打包 7 8 /// <summary> 9 /// TLV报文打包 10 /// </summary> 11 /// <param name="buffer">字节数据</param> 12 /// <returns></returns> 13 public static List<TLVEntity> Construct(byte[] buffer) 14 { 15 List<TLVEntity> resultList = new List<TLVEntity>(); 16 int currentIndex = 0; 17 while (currentIndex < buffer.Length) 18 { 19 TLVEntity entity = new TLVEntity(); 20 //1. 根据Tag判断数据是否是嵌套的TLV 21 bool hasSubEntity = HasSubEntity(buffer, currentIndex); 22 23 #region Tag解析 24 entity.Tag = GetTag(buffer, currentIndex); 25 currentIndex += entity.Tag.Length; 26 #endregion 27 28 #region Length解析 29 entity.Length = GetLength(buffer, currentIndex); 30 currentIndex += entity.Length.Length; 31 #endregion 32 33 #region Value解析 34 int valueLength = GetValueLengthByLengthByteValue(entity.Length); 35 entity.Value = buffer.Take(currentIndex + valueLength).Skip(currentIndex).ToArray(); 36 if (hasSubEntity)//判断是否是嵌套结构 37 entity.SubTLVEntity = Construct(entity.Value);//嵌套结构递归解析 38 currentIndex += entity.Value.Length; 39 #endregion 40 41 resultList.Add(entity); 42 } 43 return resultList; 44 } 45 46 /// <summary> 47 /// 是否存在嵌套实体 48 /// </summary> 49 /// <returns></returns> 50 private static bool HasSubEntity(byte[] bytes, int index) 51 { 52 if (bytes.Length < index + 1) 53 throw new ArgumentException("无效的索引值"); 54 return (bytes[index] & 0x20) == 0x20; 55 } 56 57 /// <summary> 58 /// 获取Tag字节数据 59 /// </summary> 60 /// <param name="bytes">长度</param> 61 /// <param name="index">索引位置</param> 62 /// <returns></returns> 63 private static byte[] GetTag(byte[] bytes, int index) 64 { 65 if (bytes.Length < index + 1) 66 throw new ArgumentException("无效的索引值"); 67 //判断Tag所占字节长度 68 if ((bytes[index] & 0x1f) == 0x1f) 69 {//占2字节 70 return new byte[] { bytes[index], bytes[index + 1] }; 71 } 72 else 73 {//占1字节 74 return new byte[] { bytes[index] }; 75 } 76 } 77 78 /// <summary> 79 /// 获取长度 80 /// </summary> 81 /// <param name="bytes">长度</param> 82 /// <param name="index">索引位置</param> 83 /// <returns></returns> 84 private static byte[] GetLength(byte[] bytes, int index) 85 { 86 if (bytes.Length < index + 1) 87 throw new ArgumentException("无效的索引值"); 88 //判断Length部分所占字节 是1个字节还是多个字节 89 if ((bytes[index] & 0x80) == 0x80) 90 {//占多个字节 91 int lengthSize = (bytes[index] & 0x7f) + 1;//获取Length所占字节数 92 return bytes.Take(index + lengthSize).Skip(index).ToArray(); 93 } 94 else 95 {//占单个字节 96 return new byte[] { bytes[index] }; 97 } 98 } 99 /// <summary> 100 /// 根据Length部分的值获取到value部分的值 101 /// </summary> 102 /// <param name="bytes">Length部分的值</param> 103 /// <returns></returns> 104 private static int GetValueLengthByLengthByteValue(byte[] bytes) 105 { 106 int length = 0; 107 if (bytes.Length == 1) 108 length = bytes[0]; 109 else 110 { 111 //从下一个字节开始算Length域 112 for (int index = 1; index < bytes.Length; index++) 113 { 114 length += bytes[index] << ((index-1) * 8); //计算Length域的长度 115 } 116 } 117 return length; 118 } 119 120 #endregion 121 122 #region TLV 解析 123 /// <summary> 124 /// 解析TLV 125 /// </summary> 126 /// <param name="list"> 127 /// <returns></returns> 128 public static byte[] Parse(List<TLVEntity> list) 129 { 130 byte[] buffer = new byte[4096]; 131 int currentIndex = 0; 132 int currentTLVIndex = 0; 133 int valueSize = 0; 134 135 while (currentTLVIndex < list.Count()) 136 { 137 valueSize = 0; 138 TLVEntity entity = list[currentTLVIndex]; 139 140 Array.Copy(entity.Tag, 0, buffer, currentIndex, entity.TagSize); //解析Tag 141 142 currentIndex += entity.TagSize; 143 144 for (int index = 0; index < entity.LengthSize; index++) 145 { 146 valueSize += entity.Length[index] << (index * 8); //计算Length域的长度 147 } 148 if (valueSize > 127) 149 { 150 buffer[currentIndex] = Convert.ToByte(0x80 | entity.LengthSize); 151 currentIndex += 1; 152 } 153 154 Array.Copy(entity.Length, 0, buffer, currentIndex, entity.LengthSize); //解析Length 155 156 currentIndex += entity.LengthSize; 157 //判断是否包含子嵌套TLV 158 if (entity.SubTLVEntity == null) 159 { 160 Array.Copy(entity.Value, 0, buffer, currentIndex, valueSize); //解析Value 161 currentIndex += valueSize; 162 } 163 else 164 { 165 byte[] tempBuffer = Parse(entity.SubTLVEntity); 166 Array.Copy(tempBuffer, 0, buffer, currentIndex, tempBuffer.Length); //解析子嵌套TLV 167 currentIndex += tempBuffer.Length; 168 } 169 170 currentTLVIndex++; 171 } 172 173 byte[] resultBuffer = new byte[currentIndex]; 174 Array.Copy(buffer, 0, resultBuffer, 0, currentIndex); 175 176 return resultBuffer; 177 } 178 #endregion 179 }
tlv实体操作帮助类
public class TLVHelper { /// <summary> /// 根据tag获取tlv的值 /// </summary> /// <param name="entities"></param> /// <param name="tag"></param> /// <returns></returns> public static TLVEntity GetValueByTag(List<TLVEntity> entities, string tag) { TLVEntity resultEntity = null; var query = entities.SingleOrDefault(e => CodeConvert.ToHexString(e.Tag).ToUpper() == tag); if (query == null) { foreach (var tlv in entities) { if (tlv.SubTLVEntity != null) { TLVEntity result = GetValueByTag(tlv.SubTLVEntity, tag); if (result !=null && result.Length.Length > 0) return result; } } } else resultEntity = query; return resultEntity; } /// <summary> /// 16进制数据转化为TVL实体 /// </summary> /// <param name="resultData"></param> /// <returns></returns> public static List<TLVEntity> ToTLVEntityList(string data) { byte[] dataBytes = CodeConvert.HexStringToByteArray(data); var tlvList = TLVPackage.Construct(dataBytes); return tlvList; } }
转载请注明出处:http://www.cnblogs.com/xinwang/p/5733198.html