上一篇文章取得Smart Card的APDU Command,說明如何側錄讀卡機的指令與回傳值
這篇文章將實作程式來讀取自然人憑證的卡號
程式參考於使用C#讀取自然人評證卡號
但實作後仍無法正確顯示,所以使用 WinSCard APDU View Utility 來側錄指令後,修改成下面的程式碼
Imports System Imports System.Text Imports System.Runtime.InteropServices Public Class DigitalCard Private Structure SCARD_IO_REQUEST Public dwProtocol As Integer Public cbPciLength As Integer End Structure '引用 PC/SC(Personal Computer/Smart Card) API WinScard.dll <DllImport("WinScard.dll")> _ Private Shared Function SCardEstablishContext(ByVal dwScope As UInteger, ByVal nNotUsed1 As Integer, ByVal nNotUsed2 As Integer, ByRef phContext As Integer) As Integer End Function <DllImport("WinScard.dll")> _ Private Shared Function SCardReleaseContext(ByVal phContext As Integer) As Integer End Function <DllImport("WinScard.dll")> _ Private Shared Function SCardConnect(ByVal hContext As Integer, ByVal cReaderName As String, ByVal dwShareMode As UInteger, ByVal dwPrefProtocol As UInteger, ByRef phCard As Integer, ByRef ActiveProtocol As Integer) As Integer End Function <DllImport("WinScard.dll")> _ Private Shared Function SCardDisconnect(ByVal hCard As Integer, ByVal Disposition As Integer) As Integer End Function <DllImport("WinScard.dll")> _ Private Shared Function SCardListReaders(ByVal hContext As Integer, ByVal cGroups As String, ByRef cReaderLists As String, ByRef nReaderCount As Integer) As Integer End Function <DllImport("WinScard.dll")> _ Private Shared Function SCardTransmit(ByVal hCard As Integer, ByRef pioSendPci As SCARD_IO_REQUEST, ByVal pbSendBuffer() As Byte, ByVal cbSendLength As Integer, ByRef pioRecvPci As SCARD_IO_REQUEST, ByRef pbRecvBuffer As Byte, ByRef pcbRecvLength As Integer) As Integer End Function ''' ''' 取得自然人憑證的卡號 ''' ''' ''' Public Function GetCardNumber() As String Dim ContextHandle As Integer = 0, CardHandle As Integer = 0, ActiveProtocol As Integer = 0, ReaderCount As Integer = -1 Dim ReaderList As String = String.Empty '讀卡機名稱列表 Dim SendPci, RecvPci As SCARD_IO_REQUEST Dim SelEFAPDU_1() As Byte = {&H80, &HA4, &H0, &H0, &H2, &H3F, &H0} 'Select Elementary File 的 APDU Dim SelEFAPDU_2() As Byte = {&H80, &HA4, &H0, &H0, &H2, &H9, &H0} 'Select Elementary File 的 APDU Dim SelEFAPDU_3() As Byte = {&H80, &HA4, &H0, &H0, &H2, &H9, &H3} 'Select Elementary File 的 APDU Dim ReadSNAPDU() As Byte = {&H80, &HB0, &H0, &H0, &H10} '由offset 0 讀取 0x10位 Binary 資料的 APDU Dim SelEFRecvBytes(1) As Byte '應回 90 00 Dim SelEFRecvLength As Integer = 2 Dim SNRecvBytes(17) As Byte '接收卡號的 Byte Array Dim SnRecvLength As Integer = 18 '建立 Smart Card API If SCardEstablishContext(0, 0, 0, ContextHandle) = 0 Then '列出可用的 Smart Card 讀卡機 If SCardListReaders(ContextHandle, Nothing, ReaderList, ReaderCount) = 0 Then '建立 Smart Card 連線 If SCardConnect(ContextHandle, ReaderList, 1, 2, CardHandle, ActiveProtocol) = 0 Then RecvPci.dwProtocol = ActiveProtocol SendPci.dwProtocol = RecvPci.dwProtocol RecvPci.cbPciLength = 8 SendPci.cbPciLength = RecvPci.cbPciLength '下達 Select FE14 檔的 APDU If SCardTransmit(CardHandle, SendPci, SelEFAPDU_1, SelEFAPDU_1.Length, RecvPci, SelEFRecvBytes(0), SelEFRecvLength) = 0 Then If SCardTransmit(CardHandle, SendPci, SelEFAPDU_2, SelEFAPDU_2.Length, RecvPci, SelEFRecvBytes(0), SelEFRecvLength) = 0 Then If SCardTransmit(CardHandle, SendPci, SelEFAPDU_3, SelEFAPDU_3.Length, RecvPci, SelEFRecvBytes(0), SelEFRecvLength) = 0 Then '下達讀取卡號指令 If SCardTransmit(CardHandle, SendPci, ReadSNAPDU, ReadSNAPDU.Length, RecvPci, SNRecvBytes(0), SnRecvLength) = 0 Then Return Encoding.Default.GetString(SNRecvBytes, 0, 16) End If End If End If End If End If End If End If Return "" End Function End Class
使用的話請參考下面程式
Private Sub Button1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim DGCard As New DigitalCard MsgBox(DGCard.GetCardNumber) End Sub
One thought on “使用讀卡機取得自然人憑證的卡號”