zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    nginx -s reload 时报错 [error] open() "/run/nginx.pid" failed (2: No such file or directory)
    系统调用(四):SSDT
    系统调用(三): 分析KiFastCallEntry(二)
    系统调用(二): 分析KiFastCallEntry(一)
    系统调用(一): 重写WriteProcessMemory
    CVE-2009-0927分析
    CVE-2008-0015分析
    CVE-2006-4868分析
    在linux上使用impdp命令时提示ORA-12154: TNS:could not resolve the connect identifier specified的问题
    破解myeclipse10失败的一个奇葩原因
  • 原文地址:https://www.cnblogs.com/xinwang/p/5733198.html
Copyright © 2011-2022 走看看