PBOC/EMV中TLV的构造和解析

转自 http://blog.csdn.net/super_mimi/article/details/49000981

BER-TLV 数据对象编码

根据 ISO/IEC 8825 的定义,一个 BER-TLV 数据对象包括 2-3 个连续数据域:
标签域( Tag)包括一个或多个连续字节。它定义一种类别、类型和一个数字。本规范规定的数据对象的标签域用一个或二个字节编码。
长度域( Length)包括一个或多个连续字节。它定义了接下来一个域的长度。本规范规定的数据对象的长度用一个、或二个字节编码。

根据 ISO/IEC 8825 的定义,一个 BER-TLV 数据对象包括 2-3 个连续数据域:
标签域( Tag)包括一个或多个连续字节。它定义一种类别、类型和一个数字。本规范规定的数据对象的标签域用一个或二个字节编码。
长度域( Length)包括一个或多个连续字节。它定义了接下来一个域的长度。本规范规定的数据对象的长度用一个、或二个字节编码。

值域( Value)定义数据对象的值。如果 L= ‘ 00’ ,则值域不存在。


先看看Tag域的编码:


表 B- 根据 ISO/IEC 8825 定义了当标签号=31(即第一字节的 b5- b1 位为‘ 11111’ )时,BER-TLV 标签跟随字节的编码规则。即Tag域扩展到下一个字节。


当b8为1时,还需要扩展。但EMV文档中说明,Tag域最多占用两个字节。



Length域的规范:

当长度域的最高字节的 b8 位为 时,长度域仅有一个字节。 b7 到 b1 位的值为值域的字节数。长度域的范围为 到 127
当长度域的最高字节的 b8 位位 时,紧接的 b7 到 b1 位的值为长度域最高字节后跟随的长度字节数。后续字节的整数值为值域的字节数。要表示 255 个字节以下的值域,至少需要个字节。


Value域的规范:

基本 BER-TLV 数据对象的值域是一个数据元。数据元是带标识(标签)的最小数据域。


复合 BER-TLV 数据对象包括一个标签、一个长度和一个值域,其值域由一个和多个BER-TLV 数据对象组成。



下面是TLV代码的例子:

TLV结构体:

[cpp]  view plain  copy
 print ?
  1. //创建TLV结构体  
  2. typedef struct TLVEntity  
  3. {  
  4.     unsigned char * Tag;        //标签  
  5.     unsigned char * Length;     //长度  
  6.     unsigned char * Value;      //数据  
  7.     unsigned int TagSize;       //标签占用字节  一般两个字节  
  8.     unsigned int LengthSize;    //数据占用的字节  
  9.     TLVEntity * subTLVEntity;   //嵌套的子TLV结构体,如果有的话,需要递归  
  10.     unsigned int subTLVnum;     //下一级的TLV数量,不包括下下级的TLV(记录subTLVEntity[]的大小)  
  11. }TLV, *PTLV;  

构造TLV的函数:

[cpp]  view plain  copy
 print ?
  1. //构造TLV  
  2. void TLVConstruct(unsigned char *buffer,            //TLV字符串      
  3.                   unsigned int bufferLength,        //TLV字符串长度  
  4.                   PTLV PTlvEntity,                  //TLV指针  
  5.                   unsigned int& entitySize          //TLV结构数量,解析时用到  
  6.                   )  
  7. {  
  8.     int currentIndex = 0;                           //用于标记buffer  
  9.     int currentTLVIndex = 0;                        //当前TLV结构标记  
  10.     int currentStatus = 'T';                        //状态字符  
  11.   
  12.     unsigned long valueSize = 0;                    //数据长度  
  13.   
  14.     while (currentIndex < bufferLength)  
  15.     {  
  16.         switch (currentStatus)  
  17.         {  
  18.         case 'T':  
  19.             valueSize = 0; //清零  
  20.             //判断TLV是否为单一结构,字节的第6位是否为1  
  21.             if ((buffer[currentIndex] & 0x20) != 0x20)  
  22.             {  
  23.                 //单一结构  
  24.                 PTlvEntity[currentTLVIndex].subTLVEntity = NULL;  
  25.                 PTlvEntity[currentTLVIndex].subTLVnum = 0;      //子TLV的数量为零  
  26.                 //判断是Tag是否为多字节,字节的1--5位是否都为1,是的话有后续字节  
  27.                 if ((buffer[currentIndex] & 0x1f) == 0x1f)  
  28.                 {  
  29.                     //Tag为多字节  
  30.                     int endTagIndex = currentIndex;  
  31.                     while (buffer[++endTagIndex] & 0x80 == 0x80); //最后一个字节的最高位为0  
  32.                     int tagSize = endTagIndex - currentIndex + 1; //计算标签所占用字节  
  33.   
  34.                     PTlvEntity[currentTLVIndex].Tag = (unsigned char *)malloc(tagSize);  
  35.                     memcpy(PTlvEntity[currentTLVIndex].Tag, buffer + currentIndex, tagSize);  
  36.                     PTlvEntity[currentTLVIndex].Tag[tagSize] = 0;//字符串末尾置0  
  37.   
  38.                     PTlvEntity[currentTLVIndex].TagSize = tagSize;  
  39.   
  40.                     currentIndex += tagSize;  
  41.                 }  
  42.                 else  
  43.                 {  
  44.                     //Tag占用1个字节  
  45.                     PTlvEntity[currentTLVIndex].Tag = (unsigned char *)malloc(1);  
  46.                     memcpy(PTlvEntity[currentTLVIndex].Tag, buffer + currentIndex, 1);  
  47.                     PTlvEntity[currentTLVIndex].Tag[1] = 0;  
  48.   
  49.                     PTlvEntity[currentTLVIndex].TagSize = 1;  
  50.   
  51.                     currentIndex += 1;  
  52.                 }  
  53.             }  
  54.             else  
  55.             {  
  56.                 //复合结构  
  57.                 //判断是否为多字节  
  58.                 if ((buffer[currentIndex] & 0x1f) == 0x1f)  
  59.                 {  
  60.                     int endTagIndex = currentIndex;  
  61.                     while (buffer[++endTagIndex] & 0x80 == 0x80);  
  62.                     int tagSize = endTagIndex - currentIndex + 1;  
  63.   
  64.                     PTlvEntity[currentTLVIndex].Tag = (unsigned char *)malloc(tagSize);  
  65.                     memcpy(PTlvEntity[currentTLVIndex].Tag, buffer + currentIndex, tagSize);  
  66.                     PTlvEntity[currentTLVIndex].Tag[tagSize] = 0;  
  67.   
  68.                     PTlvEntity[currentTLVIndex].TagSize = tagSize;  
  69.   
  70.                     currentIndex += tagSize;  
  71.                 }  
  72.                 else  
  73.                 {  
  74.                     PTlvEntity[currentTLVIndex].Tag = (unsigned char *)malloc(1);  
  75.                     memcpy(PTlvEntity[currentTLVIndex].Tag, buffer + currentIndex, 1);  
  76.                     PTlvEntity[currentTLVIndex].Tag[1] = 0;  
  77.   
  78.                     PTlvEntity[currentTLVIndex].TagSize = 1;  
  79.   
  80.                     currentIndex += 1;  
  81.                 }  
  82.   
  83.                 //分析子TLV中的Tag  
  84.                 int subTlvLength = 0;           //子TLV长度  
  85.                 unsigned char * temp;           //子TLV所包含的数据  
  86.                 //先判断length域的长度,length域字节如果最高位为1,后续字节代表长度,为0,1--7位代表数据长度  
  87.                 if ((buffer[currentIndex] & 0x80) == 0x80)  
  88.                 {  
  89.                     //最高位为1  
  90.                     unsigned int lengthSize = buffer[currentIndex] & 0x7f;  
  91.                     for (int index = 0; index < lengthSize; index++)  
  92.                     {  
  93.                         //大端显示数据  
  94.                         subTlvLength += buffer[currentIndex + 1 + index] << ((lengthSize - 1 - index) * 8);  
  95.   
  96.                         /* 如果是小端的话 
  97.                         subTlvLength += buffer[currentIndex + 1 + index] << (index * 8); 
  98.                         */  
  99.                     }  
  100.   
  101.   
  102.                     //申请一段subTlvlength大小的内存存放该TLV的内容  
  103.                     temp = (unsigned char *)malloc(subTlvLength);  
  104.                     memcpy(temp, buffer + currentIndex + 1 + lengthSize, subTlvLength);  
  105.   
  106.                 }  
  107.                 else  
  108.                 {  
  109.                     //最高位为0  
  110.                     subTlvLength = buffer[currentIndex];  
  111.                     temp = (unsigned char *)malloc(subTlvLength);  
  112.   
  113.                     memcpy(temp, buffer + currentIndex + 1, subTlvLength);  
  114.   
  115.                 }  
  116.                 temp[subTlvLength] = 0;  
  117.   
  118.                 unsigned int oSize;//输出有多少个同等级的子TLV,解析时也应该用到  
  119.                 //不清楚子TLV同等级的TLV有多少个,申请100TLV大小的内存肯定够用  
  120.                 PTlvEntity[currentTLVIndex].subTLVEntity = (PTLV)malloc(sizeof(TLV[100]));  
  121.                 TLVConstruct(temp, subTlvLength, PTlvEntity[currentTLVIndex].subTLVEntity, oSize);  
  122.   
  123.                 PTlvEntity[currentTLVIndex].subTLVnum = oSize; //填入子TLV的数量  
  124.   
  125.             }  
  126.             currentStatus = 'L';  
  127.             break;  
  128.         case 'L':  
  129.             //判断长度字节的最高位是否为1,如果为1,则该字节为长度扩展字节,由下一个字节开始决定长度  
  130.             if ((buffer[currentIndex] & 0x80) == 0x80)  
  131.             {  
  132.                 //最高位1  
  133.                 unsigned int lengthSize = buffer[currentIndex] & 0x7f;  
  134.                 currentIndex += 1; //从下一个字节开始算Length域  
  135.                 for (int index = 0; index < lengthSize; index++)  
  136.                 {  
  137.                     valueSize += buffer[currentIndex + index] << ((lengthSize - 1 - index) * 8); //计算Length域的长度  
  138.                 }  
  139.                 PTlvEntity[currentTLVIndex].Length = (unsigned char *)malloc(lengthSize);  
  140.                 memcpy(PTlvEntity[currentTLVIndex].Length, buffer + currentIndex, lengthSize);  
  141.                 PTlvEntity[currentTLVIndex].Length[lengthSize] = 0;  
  142.                 PTlvEntity[currentTLVIndex].LengthSize = lengthSize;  
  143.   
  144.                 currentIndex += lengthSize;  
  145.             }  
  146.             else  
  147.             {  
  148.                 //最高位0  
  149.                 PTlvEntity[currentTLVIndex].Length = (unsigned char *)malloc(1);  
  150.                 memcpy(PTlvEntity[currentTLVIndex].Length, buffer + currentIndex, 1);  
  151.                 PTlvEntity[currentTLVIndex].Length[1] = 0;  
  152.                 PTlvEntity[currentTLVIndex].LengthSize = 1;  
  153.   
  154.                 valueSize = PTlvEntity[currentTLVIndex].Length[0];  
  155.   
  156.                 currentIndex += 1;  
  157.             }  
  158.             currentStatus = 'V';  
  159.             break;  
  160.         case 'V':  
  161.             PTlvEntity[currentTLVIndex].Value = (unsigned char *)malloc(valueSize);  
  162.             memcpy(PTlvEntity[currentTLVIndex].Value, buffer + currentIndex, valueSize);  
  163.             PTlvEntity[currentTLVIndex].Value[valueSize] = 0;  
  164.   
  165.             currentIndex += valueSize;  
  166.   
  167.             //进入下一个TLV构造循环  
  168.             currentTLVIndex += 1;  
  169.   
  170.             currentStatus = 'T';  
  171.             break;  
  172.         }  
  173.     }  
  174.     entitySize = currentTLVIndex;  
  175. }  


解析TLV的函数:

[cpp]  view plain  copy
 print ?
  1. // 解析TLV  
  2. BOOL TLVParseAndFindError(  
  3.     PTLV PTlvEntity,                    //输入的TLV结构体  
  4.     unsigned int entitySize,            //TLV结构体的数量  
  5.     unsigned char* buffer,              //输出的字符串  
  6.     unsigned int& bufferLength          //字符串的长度  
  7.     )  
  8. {  
  9.     int currentIndex = 0;  
  10.     int currentTLVIndex = 0;  
  11.     unsigned long valueSize = 0;  
  12.    
  13.     while(currentTLVIndex < entitySize)  
  14.     {  
  15.         valueSize = 0;  
  16.         TLVEntity entity = PTlvEntity[currentTLVIndex];  
  17.            
  18.         memcpy(buffer + currentIndex, entity.Tag, entity.TagSize);  //解析Tag  
  19.         currentIndex += entity.TagSize;  
  20.    
  21.         for (int index = 0; index < entity.LengthSize; index++)  
  22.         {  
  23.             //大端显示数据  
  24.             valueSize += entity.Length[index] << ((entity.LengthSize - 1 - index) * 8); //计算Length域的长度  
  25.         }  
  26.         if(valueSize > 127)                                  //还原length  当最高位为1的情况  
  27.         {  
  28.             buffer[currentIndex] = 0x80 | entity.LengthSize;                  
  29.             currentIndex += 1;/******************************************/  
  30.         }  
  31.            
  32.         memcpy(buffer + currentIndex, entity.Length, entity.LengthSize);    //解析Length  
  33.         currentIndex += entity.LengthSize;  
  34.         //判断是否包含子嵌套TLV  
  35.         if(entity.subTLVEntity == NULL)  
  36.         {  
  37.             //不包含  
  38.             memcpy(buffer + currentIndex, entity.Value, valueSize); //解析Value  
  39.             currentIndex += valueSize;  
  40.         }  
  41.         else  
  42.         {  
  43.             unsigned int oLength;  
  44.             TLVParseAndFindError(entity.subTLVEntity, entity.subTLVnum, buffer + currentIndex, oLength); //解析子嵌套TLV  
  45.             currentIndex += oLength;  
  46.         }  
  47.    
  48.         currentTLVIndex++;  
  49.     }  
  50.     buffer[currentIndex] = 0;  
  51.     bufferLength = currentIndex;  
  52.     return TRUE;  
  53. }  

测试的函数:

[cpp]  view plain  copy
 print ?
  1. unsigned char requestBuf[] = {  
  2.         0x30,0x82,0x02,0x5C,0x02,0x01,0x00,0x02,0x81,0x81,0x00,0xC2,0xA9,0x64,0x0E,0x11,  
  3.         0x3A,0x29,0x83,0x31,0x21,0x92,0x72,0x79,0xE0,0xEF,0x1C,0xDB,0xF5,0xE4,0x98,0xA3,  
  4.         0x0A,0x98,0x58,0x05,0x54,0xDF,0xE6,0x55,0xFD,0xB5,0x0D,0x5B,0x62,0x93,0x2C,0x0B,  
  5.         0x4E,0x6C,0xE3,0xF7,0xCE,0x2A,0x76,0x18,0x72,0x15,0x90,0x34,0xCA,0x00,0xE2,0x79,  
  6.         0x86,0x09,0x74,0xC6,0x50,0x85,0xF9,0x40,0xBF,0xA6,0xAE,0x3B,0xEB,0xF3,0xF1,0x70,  
  7.         0x9A,0xE8,0x47,0xAB,0xB8,0x04,0x27,0xC1,0x02,0xFE,0xD2,0x4F,0xA7,0x96,0x55,0x0D,  
  8.         0xE5,0x3B,0x8F,0xA8,0x5A,0xB4,0x50,0x2B,0x9D,0x1C,0x2C,0x16,0xD2,0xF9,0x75,0x13,  
  9.         0xF5,0x35,0x87,0x38,0xF3,0xE0,0x4B,0x7F,0xCC,0x8C,0xBC,0x81,0xB9,0xFA,0x35,0x60,  
  10.         0xD3,0x5B,0xDD,0xCA,0x50,0xD5,0x19,0xC6,0x5A,0x4B,0x05,0x02,0x03,0x01,0x00,0x01,  
  11.         0x02,0x81,0x80,0x40,0x67,0x0F,0x89,0xD1,0xEC,0x46,0xC0,0xB7,0x58,0x0E,0x9E,0x1E,  
  12.         0x31,0xAB,0x9A,0x86,0x31,0x87,0xC4,0x72,0x28,0xB6,0xB7,0x64,0x68,0x2C,0xBD,0x85,  
  13.         0x94,0xAF,0x3A,0x70,0x92,0x1F,0xF3,0xF1,0xF7,0xAB,0xF2,0x0E,0x51,0xE0,0xDD,0x7A,  
  14.         0x80,0x00,0x1F,0x5A,0x3F,0xBC,0xE4,0x30,0xE5,0x86,0x2A,0x62,0xD4,0x50,0x46,0xE3,  
  15.         0x43,0xA5,0x0E,0xAA,0xDA,0x22,0x70,0x60,0x6A,0x5C,0xD5,0xEF,0xA5,0xEB,0x06,0x6A,  
  16.         0x53,0xE9,0xFB,0x79,0xC6,0x00,0x84,0x05,0xB7,0x5E,0x12,0x53,0x4C,0xAC,0xA4,0xA1,  
  17.         0x77,0x16,0x64,0x99,0xAB,0x5F,0x1B,0xC0,0xC6,0x88,0xEB,0x96,0x73,0x84,0x61,0x17,  
  18.         0x50,0x1D,0x14,0xBC,0x90,0xC1,0x36,0xDF,0x9D,0x23,0x5A,0xB4,0xD7,0xE8,0x9F,0x2A,  
  19.         0x77,0x3D,0xAF,0x02,0x41,0x00,0xF2,0xE5,0x23,0xFF,0x1C,0x24,0xFC,0x1A,0x80,0x53,  
  20.         0x24,0x9C,0x57,0x06,0x0B,0xF7,0x7A,0x56,0x01,0xB9,0x50,0x7A,0xB4,0xAB,0xD4,0x5A,  
  21.         0xC8,0xB3,0x6F,0x87,0xF0,0x2A,0xAC,0x13,0x4E,0xD7,0x5C,0x74,0x69,0x87,0x6B,0x20,  
  22.         0x98,0x2C,0x0D,0x42,0x31,0xCA,0x5F,0xA3,0x8C,0x7E,0xE3,0x21,0x29,0x75,0xE4,0xAD,  
  23.         0xAE,0xB0,0x11,0xFB,0xD9,0x37,0x02,0x41,0x00,0xCD,0x2A,0x0D,0x51,0x67,0xD2,0x25,  
  24.         0xE8,0x6F,0xC9,0x51,0x31,0x46,0xEE,0x10,0x04,0xD0,0xA9,0x42,0x8D,0x15,0xC1,0x6D,  
  25.         0x59,0x83,0x74,0x39,0x36,0xE6,0x6F,0xD6,0x70,0x93,0xAD,0x59,0xD5,0x31,0x35,0xAC,  
  26.         0x8F,0xF2,0xC4,0x75,0xD9,0x60,0xC1,0xCE,0x93,0xBB,0x02,0x42,0x62,0xEE,0x42,0xF5,  
  27.         0xBD,0x19,0x20,0x0D,0xDC,0x20,0xF3,0x6B,0xA3,0x02,0x41,0x00,0xBC,0xE1,0x69,0x1B,  
  28.         0x91,0xB4,0x45,0x03,0x0A,0xB5,0x1C,0xEC,0x22,0x54,0x06,0x6C,0x3D,0x0A,0xB2,0xAE,  
  29.         0x7B,0xA1,0xDF,0xEB,0x1A,0xE8,0x39,0xD8,0x27,0x2B,0xCB,0x9C,0x33,0x51,0x94,0x66,  
  30.         0xAE,0x73,0xAC,0x38,0x6D,0x1A,0xDC,0x9A,0xAC,0xF8,0xC3,0xA5,0x3E,0xB7,0xFC,0xA2,  
  31.         0x13,0x57,0x8F,0x59,0x29,0x29,0xD2,0x85,0x02,0x87,0x19,0x03,0x02,0x40,0x63,0x2F,  
  32.         0xE5,0x68,0x69,0xCD,0x0B,0x4E,0xA8,0x5C,0xA7,0xC8,0x2F,0x06,0x80,0xF0,0x13,0x01,  
  33.         0x01,0x8F,0xBB,0xE8,0xDB,0xB8,0xDE,0xF8,0x9D,0x80,0x91,0x3F,0x98,0x68,0xAC,0xBC,  
  34.         0xAE,0x25,0x87,0xB8,0xEF,0x48,0x58,0x91,0xEA,0x77,0xC1,0x73,0x71,0x2F,0xB2,0xC5,  
  35.         0x90,0xDA,0xCB,0x5D,0xCB,0xF8,0x33,0xE1,0x6F,0x51,0xF1,0x0C,0x3E,0x09,0x02,0x40,  
  36.         0x7D,0x62,0x82,0x3D,0xAA,0xB6,0x2D,0x35,0x2B,0x87,0xB4,0x75,0x49,0x51,0x8A,0x77,  
  37.         0x75,0x96,0xEA,0xA2,0x1C,0x75,0x57,0xA2,0xF4,0xE9,0x70,0xAE,0x81,0x09,0x84,0xE1,  
  38.         0x4B,0x41,0x11,0x82,0xA7,0x41,0xD1,0xCC,0xD8,0xFF,0x21,0xC4,0x38,0x79,0x45,0xA5,  
  39.         0x0F,0x98,0x64,0x85,0xF5,0x2B,0xA6,0xBE,0x36,0xF3,0xDC,0x05,0xD3,0xFA,0x12,0x33  
  40. };  
  41.   
  42. int main(int argc, char* argv[])  
  43. {  
  44.        TLV PtlvEntity[1000];  
  45.        unsigned int tlv_count;  
  46.        //构造TLV  
  47.        TLVConstruct(requestBuf, sizeof(requestBuf), PtlvEntity, tlv_count);  
  48.        MessageBox(NULL,"构造完成!","test",MB_OK);  
  49.          
  50.        unsigned char parseBuf[4096];  
  51.        unsigned int buf_count;  
  52.        //解析TLV  
  53.        TLVParseAndFindError(PtlvEntity, tlv_count, parseBuf, buf_count);  
  54.        MessageBox(NULL,"解析完成!","test",MB_OK);  
  55.   
  56.         //看了下前100个数据  
  57.        for(int i=0; i<100; i++)  
  58.        {  
  59.            char buf[5];  
  60.            wsprintf(buf,"%02x",parseBuf[i]);  
  61.            cout<<buf<<endl;  
  62.        }  
  63.          
  64.        if(strncmp((char*)parseBuf, (char*)requestBuf, sizeof(requestBuf)) == 0)  
  65.        {  
  66.            MessageBox(NULL,"TRUE","test",MB_OK);  
  67.        }  
  68.        else  
  69.        {  
  70.            MessageBox(NULL,"FALSE","test",MB_OK);  
  71.        }  
  72.     printf("Hello World!\n");  
  73.     return 0;  
  74. }  

总结

TLV在数据通信方面,其实运用得很广泛,在应用层数据通信中,如HTTP协议,HTML,XML语言本身定义了一些标签(Body,Head,Script)对数据串行化,接收方再根据标签解析原始数据,通过浏览器展现出来。因此本质上也是属于TLV协议的设计模式。甚至在传输层的TCP,UDP协议,你完全可以通过TLV实现自定义的应用协议。

附上C#源代码:TLVPackageDemo.rar

总结

TLV在数据通信方面,其实运用得很广泛,在应用层数据通信中,如HTTP协议,HTML,XML语言本身定义了一些标签(Body,Head,Script)对数据串行化,接收方再根据标签解析原始数据,通过浏览器展现出来。因此本质上也是属于TLV协议的设计模式。甚至在传输层的TCP,UDP协议,你完全可以通过TLV实现自定义的应用协议。

 

附上C#源代码:TLVPackageDemo.rar

本文借鉴于:http://www.cnblogs.com/liping13599168/archive/2011/06/15/2081366.html

原文的代码有些小问题,本文修正了,另外代码注释更加得详细。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值