十幾年前傳統磁條卡片側錄盜刷事件層出不窮,當時高安全交易保護的晶片問世,ISO8583也依循著制定晶片規格的組織EMV增加了數十個晶片交易資訊欄位,按照ISO8583標準,晶片資訊在DE55,並以BER-TLV的規格(ISO8825)組成資料區塊,由於計算驗證ARQC/ARPC需要晶片交易欄位,我們要先Parse DE55。
ISO8583 晶片交易欄位是按照BER-TLV的標準制定,BER全名為Basic Encoding Rules,TLV全名則為Tag Length Value,簡單用下圖表示:
9F36代表EMV Tag: ATC 交易次數,02表示Value長度,0001則是Value,這邊要注意長度是實際長度而非16進位字串長度。
這邊我們注意到TLV Tag 第1個Byte 8bit內幾個特別的地方:
- 前2個bit用來表示Tag class type:通用、應用、規範還是私用。
- 第3個bit 表示資料屬於基本還是結構。
- 後5個bit 若為11111,表示Tag name有2個Byte,例如我們剛剛舉的9F36 ATC的例子。
1. Parse EMV Tag程式碼:
public class EMVTag
{
//Mask for Tag name 00011111
public static byte DoubleByteMask = 0x1F;
public byte[] Tag { get; set; }
public string TagName
{
get
{
return Tag.BToHex();
}
}
public int ValueLength { get; set; }
public byte[] Value { get; set; }
public int Parse(byte[] bData, ref int offset)
{
//(1)Tag Name
Tag = GetTagName(bData, ref offset);
//(2)Length
ValueLength = GetValueLength(bData, ref offset);
//(3)Value Data
Value = new byte[ValueLength];
Array.Copy(bData, offset, Value, 0, ValueLength);
offset += ValueLength;
//Loop End
if (offset >= bData.Length)
{
offset = -1;
}
return offset;
}
public static byte[] GetTagName(byte[] bdata, ref int offset)
{
List<byte> TagName = new List<byte>();
//Tag Name Byte(1)
TagName.Add(bdata[offset]);
//是否為兩個Byte的Tag name (與Mask進行&運算),且假設最多2個byte
bool isNext = ((bdata[offset] & DoubleByteMask) == DoubleByteMask);
offset++;
while (isNext && offset < bdata.Length)
{
isNext = false;
//Tag Name Byte(2)
TagName.Add(bdata[offset]);
offset++;
}
return TagName.ToArray();
}
public static int GetValueLength(byte[] data, ref int offset)
{
int len = (int)(data[offset]);
offset++;
return len;
}
public static List<EMVTag> ParseTags(byte[] data)
{
List<EMVTag> EMVTags = new List<EMVTag>();
int offset = 0;
while (offset >= 0)
{
EMVTag tag = new EMVTag();
tag.Parse(data, ref offset);
EMVTags.Add(tag);
}
return EMVTags;
}
測試程式及晶片交易資料:
string sampleDE55 = @"
5F2A0201245F34010182021C008407A0000000031010
950580000000009A031102249B0268009C0100
9F02060000000000009F03060000000000009F0607A0000000031010
9F0802008C9F0902008C9F100706010A039000009F1A020124
9F2608423158936ED6C38F9F2701809F3303E0B0C8
9F34034103029F3501229F360200019F3704ACAC66E8
9F5800DF0100DF0200DF0400
";
//GetTLV(sampleDE55);
List<EMVTag> EmvTags = EMVTag.ParseTags(sampleDE55.Replace("\r\n", "").HexToByte());
foreach (var item in EmvTags)
{
Console.WriteLine("{0}: {1}", item.TagName, item.Value.BToHex());
}
測試結果:
小結:
- 國內區域主要清算中心為使國內銀行降低晶片化修改幅度,部分清算中心是將晶片交易資料藏於其他DE欄位中,與標準ISO8583作法不同。
- 會不會遇到超過2個Byte的EMV Tag name?
- Tag 說明可參考Emvlab
參考:
金融系統中BER-TLV的解析,更改、增加、刪除TAG的實現