银行卡读卡涉及相关APDU命令发送。网上有很多相关博客进行了详细说明,这里就不在赘述。本文主要讲55域获取流程及本人联调时遇到的相关问题。在智能卡读取使用方面本人也属于初学者,其中如有疑问或表述不正确的地方还望谅解。
银联IC卡读卡流程详解--读卡器与卡交互指令 请参考:https://blog.csdn.net/kxd_ysheng/article/details/21178101/
金融tag对照表 请参考:https://blog.csdn.net/juvary/article/details/51487245
常用APDU指令错误码 请参考:https://blog.csdn.net/lonet/article/details/7541265
不多说直接上源码(55域获取部分):
55域获取:
'*************************************************************************************************
'*函数名: get55Date
'*程序功能:银行卡读卡 55域获取(TYPE A CPU类型)
'*开发人员:Anna
'*异动人员:无
'*入口参数:hexMoney 传入金额(例:¥201.05表示为:000000020105)
' merchantName 商户名称 (10字节)
'*返回参数:返回55域信息
' -1101 卡机内无卡
' -1102 暂不支持此类卡片,请使用借记卡
' -1103 操作不成功
' -1104 卡不在允许操作的位置上
' -1105 复卡位失败
' -1106 APDU执行失败
' -1107 暂不支持该卡支付
'*************************************************************************************************
Public Function get55Date(ByVal hexMoney As String, ByVal merchantName As String)
'冷复位
Dim CpuType As Byte
Dim CpuResetData(300) As Byte
Dim CpuResetDataLen As Long
'定义接受判断标识符
Dim resDateFlag As String
'定义接收执行apdu返回数据
Dim resDate As String
Dim rc As Integer
If hcom <= 0 Then
MsgBox ("请先打开串口")
Exit Function
End If
'CPU 卡复位
rc = CPU_ColdReset(hcom, 0, CpuType, CpuResetData(0), CpuResetDataLen)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "MC_ReadTrack", rc, "CPU 卡复位", "ComHandle=" & hcom & ",_CPUMode = 0x0,_CPUType = 0x0")
If (rc >= 0) Then
Select Case rc
Case 0
Dim Strtmp As String
Strtmp = ""
For i = 0 To CpuResetDataLen - 1
Strtmp = Strtmp + DoubleType(Hex(CpuResetData(i)))
Next i
'1. 应用选择
CPUAPDUCOMMAND = "00A404000E315041592E5359532E4444463031"
crt310resStr = CPUSendCmd(CPUAPDUCOMMAND, 0)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "CPUSendCmd", crt310resStr, "APDU 应用选择", "CPUAPDUCOMMAND = " & CPUAPDUCOMMAND)
'2.通过循环读记录,选择 PSE 关联文件,判断是否是借记卡
CPUAPDUCOMMAND = "00B2010C00"
crt310resStr = CPUSendCmd(CPUAPDUCOMMAND, 0)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "CPUSendCmd", crt310resStr, "APDU 通过循环读记录,选择 PSE 关联文件", "CPUAPDUCOMMAND = " & CPUAPDUCOMMAND)
'截取返回值判断是否是储蓄卡
resDateFlag = Right$(crt310resStr, 4)
'MsgBox ("resDateFlag")
'MsgBox (resDateFlag)
If (resDateFlag = "9000") Then
Dim aidStr As String
aidStr = Mid$(crt310resStr, 13, 16)
'3.选择文件
CPUAPDUCOMMAND = "00A4040008" & aidStr
crt310resStr = CPUSendCmd(CPUAPDUCOMMAND, 0)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "CPUSendCmd", crt310resStr, "APDU 选择文件", "CPUAPDUCOMMAND = " & CPUAPDUCOMMAND)
Dim resIncludeStrPosition As Integer
resIncludeStrPosition = InStr(crt310resStr, "9F38")
If (resIncludeStrPosition > 0) Then
Dim CPUAPDUCOMMAND55 As String
'获取截取长度
Dim interceptLenStr As String
interceptLenStr = Mid$(crt310resStr, resIncludeStrPosition + 4, 2)
'获取9F38数据
Dim date9F38res As String
date9F38res = Mid$(crt310resStr, resIncludeStrPosition + 6, HEXToDEC(interceptLenStr) * 2)
'定义获取信息长度
Dim date9F38resHex As String
Dim date9F38resLen As Integer
date9F38resHex = interceptLenStr
date9F38resLen = HEXToDEC(date9F38resHex)
'定义9F38获取信息返回值
Dim date9F7A As String
date9F7A = "00"
'终端交易属性
Dim date9F66 As String
date9F66 = "60000000"
'授权金额
Dim date9F02 As String
date9F02 = hexMoney
'其他金额
Dim date9F03 As String
date9F03 = "000000000000"
'终端国家代码
Dim date9F1A As String
date9F1A = "0156"
'终端验证结果
Dim date95 As String
date95 = "0000000000"
'交易货币代码
Dim date5F2A As String
date5F2A = "0156"
'交易日期
Dim date9A As String
date9A = Format(Now, "yymmdd")
'交易类型
Dim date9C As String
date9C = "00"
'不可预知数
Dim date9F37 As String
Dim RandomizeInt As Long
RandomizeInt = Rnd * 100000000
date9F37 = Trim(RandomizeInt)
'SM算法支持指示器
Dim dateDF69 As String
dateDF69 = "00"
'交易时间
Dim date9F21 As String
date9F21 = Format(Now, "HHmmss")
'商户名称
Dim date9F4E As String
date9F4E = merchantName
date9F4E = "0000000000000000000000000000000000000000"
CPUAPDUCOMMAND = ""
CPUAPDUCOMMAND55 = ""
Dim itemLen As Integer
itemLen = 0
'判断是否包含9F7A
If (InStr(date9F38res, "9F7A")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + date9F7A
itemLen = itemLen + 1
End If
'判断是否包含9F66
If (InStr(date9F38res, "9F66")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + date9F66
itemLen = itemLen + 4
End If
'判断是否包含9F02(实际金额/分)
If (InStr(date9F38res, "9F02")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + date9F02
itemLen = itemLen + 6
End If
'判断是否包含9F03
If (InStr(date9F38res, "9F03")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + date9F03
itemLen = itemLen + 6
End If
'判断是否包含9F1A
If (InStr(date9F38res, "9F1A")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + date9F1A
itemLen = itemLen + 2
End If
'判断是否包含95
If (InStr(date9F38res, "95")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + date95
itemLen = itemLen + 5
End If
'判断是否包含5F2A
If (InStr(date9F38res, "5F2A")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + date5F2A
itemLen = itemLen + 2
End If
'判断是否包含9A
If (InStr(date9F38res, "9A")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + date9A
itemLen = itemLen + 3
End If
'判断是否包含9C
If (InStr(date9F38res, "9C")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + date9C
itemLen = itemLen + 1
End If
'判断是否包含9F37
If (InStr(date9F38res, "9F37")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + date9F37
itemLen = itemLen + 4
End If
'判断是否包含DF69
If (InStr(crt310resStr, "DF69")) Then
CPUAPDUCOMMAND = CPUAPDUCOMMAND + "00"
itemLen = itemLen + 1
End If
CPUAPDUCOMMAND = "80A80000" + DecToHex(itemLen + 2) + "83" + DecToHex(itemLen) + CPUAPDUCOMMAND
'定义接受55域返回值信息
Dim date55ResInfo As String
date55ResInfo = CPUSendCmd(CPUAPDUCOMMAND, 0)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "CPUSendCmd", date55ResInfo, "APDU 根据9F38返回组合报文发送命令", "CPUAPDUCOMMAND = " & CPUAPDUCOMMAND)
If (resDateFlag = "9000") Then
'获取82值
Dim date82 As String
date82 = Mid$(date55ResInfo, 5, 4)
'根据 GPO 返回的 AFL
Dim gpoDate As String
gpoDate = Mid$(date55ResInfo, 9, Len(date55ResInfo) - 12)
Dim GPOCPUAPDUCOMMAND As String
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "截取获取gpoDate", gpoDate, "APDU 读应用数据")
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "判断Len(gpoDate) Mod 8 = 0结果:", Len(gpoDate) Mod 8 = 0, "APDU 读应用数据")
'定义存储5F34数据
Dim date5F34 As String
date5F34 = ""
'定义存储8C数据
Dim date8C As String
If (Len(gpoDate) Mod 8 = 0) Then
Dim forNum As Integer
forNum = Len(gpoDate) / 8
For i = 1 To forNum
'定义截取命令数据
Dim GPOCPUAPDUCOMMANDDate As String
GPOCPUAPDUCOMMANDDate = Mid$(gpoDate, (i - 1) * 8 + 1, 8)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "定义截取命令数据GPOCPUAPDUCOMMANDDate:", GPOCPUAPDUCOMMANDDate, "APDU 读应用数据")
'计算SFI值
Dim SFIDate As String
SFIDate = Left$(GPOCPUAPDUCOMMANDDate, 2)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "计算SFIDate:", SFIDate, "APDU 读应用数据")
Dim SFIDateRes As String
SFIDateRes = HexForSFI(SFIDate)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "计算SFI值:", SFIDateRes, "APDU 读应用数据")
'截取Record 值
Dim RecordDate As String
Dim RecordDateNum As Integer
RecordDate = Mid$(GPOCPUAPDUCOMMANDDate, 5, 2)
RecordDateNum = HEXToDEC(RecordDate)
For k = 1 To RecordDateNum
'拼接GPO命令
GPOCPUAPDUCOMMAND = "00B2" & DecToHex(k) & SFIDateRes & "00"
resDate = CPUSendCmd(GPOCPUAPDUCOMMAND, 0)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "CPUSendCmd", resDate, "APDU 读应用数据", "GPOCPUAPDUCOMMAND = " & GPOCPUAPDUCOMMAND)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "InStr(resDate, 8C):", InStr(resDate, "8C"), "APDU 截取8C数据")
If (Len(resDate) > 0 And InStr(resDate, "8C") = 5 And InStr(resDate, "8D") > InStr(resDate, "8C")) Then
'获取截取长度
Dim interceptLen8C As String
interceptLen8C = Mid$(resDate, 7, 2)
'获取9F38数据
date8C = Mid$(resDate, 9, HEXToDEC(interceptLen8C) * 2)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "截取8C数据", date8C, "APDU 截取8C数据")
End If
If (Len(resDate) > 0 And InStr(resDate, "5F34") > 0) Then
'定义获取包含5F34位置
Dim resInclude5F34Position As Integer
resInclude5F34Position = InStr(resDate, "5F34")
If (resInclude5F34Position > 0) Then
'获取截取长度
Dim interceptLen5F34 As String
interceptLen5F34 = Mid$(resDate, resInclude5F34Position + 4, 2)
'获取9F38数据
date5F34 = Mid$(resDate, resInclude5F34Position + 6, HEXToDEC(interceptLen5F34) * 2)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "截取5F34数据", date5F34, "APDU 截取5F34数据")
End If
End If
Next
Next
Else
'命令截取错误
End If
'组合报文获取55域9F10 9F26 9F27信息
'CPUAPDUCOMMAND = "80AE800034" + CPUAPDUCOMMAND55 + date82 + date9F36 组合报文发送如上报文时 部分卡不能获取返回值报错 6A80 数据域参数不正确 将所有包含数据全部发送时 都可以正常返回
If (Len(date8C) > 0) Then
'此次ATC寄存器值
Dim date9F36 As String
date9F36 = ""
CPUAPDUCOMMAND = "80CA9F3600"
resDate = CPUSendCmd(CPUAPDUCOMMAND, 0)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "CPUSendCmd", resDate, "APDU 获取9F36此次ATC寄存器值", "CPUAPDUCOMMAND = " & CPUAPDUCOMMAND)
resDateFlag = Right$(resDate, 4)
If (resDateFlag = "9000") Then
date9F36 = Mid$(resDate, 7, 4)
End If
'判断是否包含9F02(实际金额/分)
If (InStr(date8C, "9F02")) Then
CPUAPDUCOMMAND55 = CPUAPDUCOMMAND55 + date9F02
End If
'判断是否包含9F03
If (InStr(date8C, "9F03")) Then
CPUAPDUCOMMAND55 = CPUAPDUCOMMAND55 + date9F03
End If
'判断是否包含9F1A
If (InStr(date8C, "9F1A")) Then
CPUAPDUCOMMAND55 = CPUAPDUCOMMAND55 + date9F1A
End If
'判断是否包含95
If (InStr(date8C, "95")) Then
CPUAPDUCOMMAND55 = CPUAPDUCOMMAND55 + date95
End If
'判断是否包含5F2A
If (InStr(date8C, "5F2A")) Then
CPUAPDUCOMMAND55 = CPUAPDUCOMMAND55 + date5F2A
End If
'判断是否包含9A
If (InStr(date8C, "9A")) Then
CPUAPDUCOMMAND55 = CPUAPDUCOMMAND55 + date9A
End If
'判断是否包含9C
If (InStr(date8C, "9C")) Then
CPUAPDUCOMMAND55 = CPUAPDUCOMMAND55 + date9C
End If
'判断是否包含9F37
If (InStr(date8C, "9F37")) Then
CPUAPDUCOMMAND55 = CPUAPDUCOMMAND55 + date9F37
End If
End If
CPUAPDUCOMMAND = "80AE800034" + CPUAPDUCOMMAND55 + date82 + date9F36
resDate = CPUSendCmd(CPUAPDUCOMMAND, 0)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "CPUSendCmd", resDate, "APDU 发送组合报文获取55域信息", "CPUAPDUCOMMAND = " & CPUAPDUCOMMAND)
resDateFlag = Right$(resDate, 4)
If (resDateFlag = "9000") Then
Dim date9F26 As String
Dim date9F27 As String
Dim date9F10 As String
date9F27 = Mid$(resDate, 5, 2)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "截取", date9F27, "截取 date9F27")
date9F26 = Mid$(resDate, 11, 16)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "截取", date9F26, "截取 date9F26")
date9F10 = Mid$(resDate, 27, Len(resDate) - 30)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "截取", date9F10, "截取 date9F10")
'封装组合55域数据
Dim str9F33 As String
Dim resDate55 As String
resDate55 = ""
str9F33 = "6040E8"
resDate55 = resDate55 + "9F26" + DecToHex(Len(date9F26) / 2) + date9F26
resDate55 = resDate55 + "9F27" + DecToHex(Len(date9F27) / 2) + date9F27
resDate55 = resDate55 + "9F10" + DecToHex(Len(date9F10) / 2) + date9F10
resDate55 = resDate55 + "9F37" + DecToHex(Len(date9F37) / 2) + date9F37
resDate55 = resDate55 + "9F36" + DecToHex(Len(date9F36) / 2) + date9F36
resDate55 = resDate55 + "95" + DecToHex(Len(date95) / 2) + date95
resDate55 = resDate55 + "9A" + DecToHex(Len(date9A) / 2) + date9A
resDate55 = resDate55 + "9C" + DecToHex(Len(date9C) / 2) + date9C
resDate55 = resDate55 + "9F02" + DecToHex(Len(date9F02) / 2) + date9F02
resDate55 = resDate55 + "5F2A" + DecToHex(Len(date5F2A) / 2) + date5F2A
resDate55 = resDate55 + "82" + DecToHex(Len(date82) / 2) + date82
resDate55 = resDate55 + "9F1A" + DecToHex(Len(date9F1A) / 2) + date9F1A
resDate55 = resDate55 + "9F03" + DecToHex(Len(date9F03) / 2) + date9F03
resDate55 = resDate55 + "9F33" + DecToHex(Len(date9F33) / 2) + date9F33
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "55域信息", resDate55, " resDate55结果")
get55Date = resDate55 & "|" & date5F34
Else
'-1107 暂不支持该卡支付
get55Date = -1107
End If
End If
End If
End If
'下电
crt310resStr = CPUDownPower()
Case 78
'-1103 操作不成功
get55Date = -1103
Case 69
'-1101 卡机内无卡
get55Date = -1101
Case 87
get55Date = -1104
End Select
Else
'-1105 复卡位失败
get55Date = -1105
End If
End Function
55域获取使用公用函数:
Public Function HexForSFI(ByVal Dnum As String) As String
'截取第一个值
Dim numStr1 As String
numStr1 = Left$(Dnum, 1)
Dim numStr1Hex As String
numStr1Hex = ASCII_to_bin(numStr1)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "截取第一个值", numStr1Hex, "APDU 读应用数据")
'截取第二个值
Dim numStr2 As String
numStr2 = Right$(Dnum, 1)
Dim numStr2Hex As String
numStr2Hex = ASCII_to_bin(numStr2)
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "截取第二个值", numStr2Hex, "APDU 读应用数据")
'拼接SFI
Dim SFIStr As String
SFIStr = numStr1Hex & Left$(numStr2Hex, 1) & "100"
resBool = WriteErrLog("CRT_310--银行卡读卡 55域获取 (TYPE A CPU类型)--", "拼接SFI", SFIStr, "APDU 读应用数据")
HexForSFI = BIN_to_HEX(SFIStr)
End Function
Public Function BIN_to_HEX(ByVal Bin As String) As String
Dim i As Long
Dim H As String
If Len(Bin) Mod 4 <> 0 Then
Bin = String(4 - Len(Bin) Mod 4, "0") & Bin
End If
For i = 1 To Len(Bin) Step 4
Select Case Mid(Bin, i, 4)
Case "0000": H = H & "0"
Case "0001": H = H & "1"
Case "0010": H = H & "2"
Case "0011": H = H & "3"
Case "0100": H = H & "4"
Case "0101": H = H & "5"
Case "0110": H = H & "6"
Case "0111": H = H & "7"
Case "1000": H = H & "8"
Case "1001": H = H & "9"
Case "1010": H = H & "A"
Case "1011": H = H & "B"
Case "1100": H = H & "C"
Case "1101": H = H & "D"
Case "1110": H = H & "E"
Case "1111": H = H & "F"
End Select
Next i
'While Left(H, 1) = "0"
' H = Right(H, Len(H) - 1)
' Wend
BIN_to_HEX = H
End Function
'*************************************************************************************************
'*函数名: HEXToDEC
'*程序功能:16进制转10进制值
'*开发人员:Anna
'*异动人员:无
'*入口参数:Hex 16进制字符串
'*返回参数:10进制Integer值
'*************************************************************************************************
Public Function HEXToDEC(ByVal Hex As String) As Integer
Dim i As Integer
Dim B As Integer
For i = 1 To Len(Hex)
Select Case Mid(Hex, Len(Hex) - i + 1, 1)
Case "0": B = B + 16 ^ (i - 1) * 0
Case "1": B = B + 16 ^ (i - 1) * 1
Case "2": B = B + 16 ^ (i - 1) * 2
Case "3": B = B + 16 ^ (i - 1) * 3
Case "4": B = B + 16 ^ (i - 1) * 4
Case "5": B = B + 16 ^ (i - 1) * 5
Case "6": B = B + 16 ^ (i - 1) * 6
Case "7": B = B + 16 ^ (i - 1) * 7
Case "8": B = B + 16 ^ (i - 1) * 8
Case "9": B = B + 16 ^ (i - 1) * 9
Case "A": B = B + 16 ^ (i - 1) * 10
Case "B": B = B + 16 ^ (i - 1) * 11
Case "C": B = B + 16 ^ (i - 1) * 12
Case "D": B = B + 16 ^ (i - 1) * 13
Case "E": B = B + 16 ^ (i - 1) * 14
Case "F": B = B + 16 ^ (i - 1) * 15
End Select
Next i
HEXToDEC = B
End Function
'*************************************************************************************************
'*函数名: DecToHex
'*程序功能:10进制转16进制
'*开发人员:Anna
'*异动人员:无
'*入口参数:decInt 10进制Integer值
'*返回参数:16进制字符串
'*************************************************************************************************
Public Function DecToHex(ByVal decInt As Integer) As String
Dim resHex As String
If (decInt < 16) Then
resHex = "0" + Hex(decInt)
Else
resHex = Hex(decInt)
End If
DecToHex = resHex
End Function
'*************************************************************************************************
'*函数名: GetTLVData
'*程序功能:获取响应结果TLV对应值
'*开发人员:Anna
'*异动人员:无
'*入口参数:dateStr 主数据串
' tlvStr 要获取的tab
'*返回参数:tlvStr对应数据
'*************************************************************************************************
Public Function GetTLVData(ByVal dateStr As String, ByVal tlvStr As String) As String
'定义获取tvl数据
Dim tvlDate As String
tvlDate = "-1"
'定义获取包含tvl位置
Dim resIncludeStrPosition As Integer
resIncludeStrPosition = InStr(crt310resStr, tlvStr)
If (resIncludeStrPosition >= 0) Then
'获取截取长度
Dim interceptLenStr As String
interceptLenStr = Mid$(dateStr, resIncludeStrPosition + 4, 2)
'获取tvl数据
tvlDate = Mid$(dateStr, resIncludeStrPosition + 6, HEXToDEC(interceptLenStr) * 2)
End If
GetTLVData = tvlDate
End Function
Function DoubleType(ByVal Str1 As String) As String '双字符函数
If Len(Str1) = 0 Then
DoubleType = "00"
Else
If Len(Str1) = 1 Then
DoubleType = "0" + Str1
Else
If Len(Str1) = 2 Then
DoubleType = Str1
End If
End If
End If
End Function
Function ASCII_to_bin(ByRef ASCData As String) As String
Dim ASC_BinBuf As String
Dim i As Integer
ASC_BinBuf = ""
For i = 1 To Len(ASCData)
Select Case Mid$(ASCData, i, 1)
Case "0"
ASC_BinBuf = ASC_BinBuf + "0000"
Case "1"
ASC_BinBuf = ASC_BinBuf + "0001"
Case "2"
ASC_BinBuf = ASC_BinBuf + "0010"
Case "3"
ASC_BinBuf = ASC_BinBuf + "0011"
Case "4"
ASC_BinBuf = ASC_BinBuf + "0100"
Case "5"
ASC_BinBuf = ASC_BinBuf + "0101"
Case "6"
ASC_BinBuf = ASC_BinBuf + "0110"
Case "7"
ASC_BinBuf = ASC_BinBuf + "0111"
Case "8"
ASC_BinBuf = ASC_BinBuf + "1000"
Case "9"
ASC_BinBuf = ASC_BinBuf + "1001"
Case "A"
ASC_BinBuf = ASC_BinBuf + "1010"
Case "B"
ASC_BinBuf = ASC_BinBuf + "1011"
Case "C"
ASC_BinBuf = ASC_BinBuf + "1100"
Case "D"
ASC_BinBuf = ASC_BinBuf + "1101"
Case "E"
ASC_BinBuf = ASC_BinBuf + "1110"
Case "F"
ASC_BinBuf = ASC_BinBuf + "1111"
End Select
Next i
ASCII_to_bin = ASC_BinBuf
End Function
55域获取注意说明:
(1)获取55域信息有固定的流程,按照网上前辈博客中所写流程基本上没有问题都能获取到55域信息。但是需注意的是,获取55域发送apdu命令一般最为最后命令发送,获取9F36应用交易计数器(ATC)请放在发送获取55域apdu命令之前,经本人测试,若流程不对会导致获取55的信息中9F26数据不正确。
(2)对于根据GPO返回的AFL,读文件时,这里指出两点个人理解:
应用初始化
请求命令报文:80A800000B83099F02065F2A02
卡片返回:80167C0008010100100101011003060018010100200101009000
0801010010010101100306001801010020010100为AFL,AFL(应用文件定位器),每个AFL包括4个字节
字节1:bit8-bit4:SFI(短文件标识符)
bit3-bit1:000
字节2:文件中要读的第1个记录的记录号(不能为0)
字节3:文件中要读的最后一个记录的记录号(大于或等于字节2)
字节4:从字节2的记录好开始,用于静态数据记录的个数(从0开始,不大于(字节3)-(字节2)+1)
根据GPO返回的AFL,读文件。读文件号格式为:SFI左移3位,右边补100。
比如上面的08 十六进制就是 0000 1000 bit8-bit4才是SFI,所以真实的是:0000 0001 ,读取文件的时候,右补0100(表明读取指定记录) ,得到0000 1100,就是0x0c。同理,02文件就是:0x14
08 01 01 00
也就是说发送命令报文为:00B2 01 0C 00
其中,00B2 读取IC卡固定命令 0C 为08计算结果 ;00 一般固定为00即可, 01 一般为字节3 如果字节3为03 则发送命令报文可有三个
00B2010C 00 , 00B2020C00, 00B2030C00
(3)在获取55域9F26信息,即生成应用密文,
网上博客说可根据读取的“卡片风险管理数据对象列表1(CDOL1)”生成该命令。
即如果8C卡片风险管理数据对象列表1(CDOL1)返回为:
8C : 9F02069F03069F1A0295055F2A029A039C019F37049F21039F4E14
则请求命令报文:80AE40002E00000000000900000000000001560000800000015610041000B84FBA072019024C4E00000000000000000000000000000000000000
80AE4000 固定命令
2E 数据长度
000000000009 9F02
000000000000 9F03
0156 9F1A
0000800000 95
0156 5F2A
100410 9A
00 9C
B84FBA07 9F37
201902 9F21
4C4E00000000000000000000000000000000000000 9F4E
上述命令本人未做尝试,本人使用
"80AE800034" + 8C包含数据(除去9F21 和9F4E)+ date82 + date9F36,
即如果date82 82为7C00, date9F36为0001,
请求命令报文为:80AE800034 + 00000000000900000000000001560000800000015610041000B84FBA07 +7C00 + 0001,即80AE80003400000000000900000000000001560000800000015610041000B84FBA077C000001,经测试联调测试成功