全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:5615
推到 Plurk!
推到 Facebook!

如何取得Smart Card裝置 第二代金融卡的卡片序號

尚未結案
hank73317
一般會員


發表:20
回覆:47
積分:13
註冊:2008-12-12

發送簡訊給我
#1 引用回覆 回覆 發表時間:2009-04-07 15:56:36 IP:122.146.xxx.xxx 訂閱
我看了一下前輩的作法,自己改依點~~~~寫的code~~

可以取得Smart Card裝置名稱了,步過沒法得到金融卡的序號(我用合作金庫的金融卡去try的,麻煩有寫過Smart Card的高手,幫我看一下吧~~~~謝謝

會部會有可能是SCardTransmit( ),這個API的下的參數步隊,~~~~~~

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace AAAA
{
public partial class Form1 : Form
{

public struct SCARD_IO_REQUEST
{

public int dwProtocol;
public int cbPciLength;
}

public Form1()
{
InitializeComponent();
}
[DllImport("WinScard.dll")]
public static extern int SCardEstablishContext(int dwScope, int nNotUsed1,
int nNotUsed2, ref int phContext);
[DllImport("WinScard.dll")]
public static extern int SCardListReaders(int hContext, string cGroups,
ref string cReaderLists, ref int nReaderCount);
[DllImport("WinScard.dll")]
public static extern int SCardListReaderGroups(int hContext, ref string cGroups, ref int nStringSize);

[DllImport("WinScard.dll")]
public static extern int SCardConnect(int hContext, string cReaderName,
uint dwShareMode, uint dwPrefProtocol, ref int phCard, ref int ActiveProtocol);
[DllImport("WinScard.dll")]
public static extern int SCardTransmit(int hCard,ref SCARD_IO_REQUEST pioSendPci, byte[] pbSendBuffer, int cbSendLength,
ref SCARD_IO_REQUEST pioRecvPci, ref byte pbRecvBuffer, ref int pcbRecvLength);

private void button1_Click(object sender, EventArgs e)
{
//First step in using smart cards is CSardEstablishContext()
int nContext = 0; //system
int nNotUsed1 = 0;
int nNotUsed2 = 0;
//handle to context for future calls to use
int nRetVal1 = SCardEstablishContext(nContext, nNotUsed1, nNotUsed2, ref nContext);
string mszReaders;
string cReaderList = "" Convert.ToChar(0);
int nReaderCount = -1;
//used to split null delimited strings into string arrays
char[] delimiter = new char[1];

textBox2.Text = delimiter[0].ToString();
//Second step in using smart cards is SCardListReaderGroups() to determin reader to use
string cGroupList = "" ;
int nStringSize = -1; //SCARD_AUTOALLOCATE
int nRetVal2 = SCardListReaderGroups(nContext, ref cGroupList, ref nStringSize);
if (nRetVal2 != 0)
{
DisplaySCError(nRetVal2, "SCardListReaderGroups()");
return;
}
string[] cGroups = cGroupList.Split(delimiter);

/*foreach (string cName in cGroups)
{
MessageBox.Show("Reader Group: " cName);
}*/
/*int nRetVal3 = SCardFreeMemory(this.nContext, ref cGroupList);
if (nRetVal3 != 0)
{
DisplaySCError(nRetVal3,"SCardFreeMemory()");
return;
}*/
int nRetVal4 = SCardListReaders(nContext, cGroups[0], ref cReaderList, ref nReaderCount);
if (nRetVal4 != 0)
{
DisplaySCError(nRetVal4, "SCardListReaders()");
return;
}
textBox1.Text = cReaderList;//將smart Card 的裝置名稱秀出
//=================================================
string[] cReaders = cReaderList.Split(delimiter);
/*foreach (string cName in cReaders)
{
MessageBox.Show("Reader: " cName);
}*/
/*int nRetVal5 = SCardFreeMemory(this.nContext, ref cReaderList);
if (nRetVal5 != 0)
{
DisplaySCError(nRetVal5,"SCardFreeMemory()");
return;
}*/
uint nShareMode = 1; //exclusive
uint nPrefProtocol = 0x80000000; //default PTS
int nCard = 0;
int nActiveProtocol = 0;
int nRetVal6 = SCardConnect(nContext, cReaders[0], nShareMode, nPrefProtocol, ref nCard, ref nActiveProtocol);
if (nRetVal6 != 0)
DisplaySCError(nRetVal6, "SCardConnect()");

//===================================
SCARD_IO_REQUEST SendPci, RecvPci;
byte[] SelEFAPDU = { 0xA0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 }; //Select Elementary File 的 APDU
byte[] ReadSNAPDU = { 0x00, 0xB0, 0x00, 0x04, 0x08 }; //由offset 0 讀取 0x10位 Binary 資料的 APDU
byte[] SelEFRecvBytes = new byte[2]; //應回 90 00
int SelEFRecvLength = 2;
byte[] SNRecvBytes = new byte[18]; //接收卡號的 Byte Array
int SnRecvLength = 18;
//下達 Select FE14 檔的 APDU
SendPci.dwProtocol = RecvPci.dwProtocol = nActiveProtocol;
SendPci.cbPciLength = RecvPci.cbPciLength = 8;

if (SCardTransmit(nCard, ref SendPci, SelEFAPDU, SelEFAPDU.Length,
ref RecvPci, ref SelEFRecvBytes[0], ref SelEFRecvLength) == 0)
{
if (SCardTransmit(nCard, ref SendPci, ReadSNAPDU, ReadSNAPDU.Length,
ref RecvPci, ref SNRecvBytes[0], ref SnRecvLength) == 0)
{
Console.WriteLine("卡號為{0}",
Encoding.Default.GetString(SNRecvBytes, 0, 16));
}
}
}
//============================
private void DisplaySCError(int nErrCode, string cText)
{
string cErrString = "";
string ErrCode = String.Format("0x{0:X}", nErrCode);
//例外的Error code處理
switch (ErrCode)
{
case "0x80100001":
cErrString = "Internal Error";
break;
case "0x80100002":
cErrString = "Cancelled";
break;
case "0x80100003":
cErrString = "Invalid Handle";
break;
case "0x80100004":
cErrString = "Invalid Parameter";
break;
case "0x80100005":
cErrString = "Invalid Target";
break;
case "0x80100006":
cErrString = "No Memory";
break;
case "0x80100007":
cErrString = "Waited Too Long";
break;
case "0x80100008":
cErrString = "Insufficient Buffer";
break;
case "0x80100009":
cErrString = "Unknown Reader";
break;
case "0x8010000A":
cErrString = "Timeout";
break;
case "0x8010000B":
cErrString = "Sharing Violation";
break;
case "0x8010000C":
cErrString = "No Smart Card";
break;
case "0x8010000D":
cErrString = "Unknown Card";
break;
case "0x8010000E":
cErrString = "Can't Dispose";
break;
case "0x8010000F":
cErrString = "Proto Mismatch";
break;
case "0x80100010":
cErrString = "Not Ready";
break;
case "0x80100011":
cErrString = "Invalid Value";
break;
case "0x80100012":
cErrString = "System Cancelled";
break;
case "0x80100013":
cErrString = "Comm Error";
break;
case "0x80100014":
cErrString = "Unknown Error";
break;
case "0x80100015":
cErrString = "Invalid ATR";
break;
case "0x80100016":
cErrString = "Not Transacted";
break;
case "0x80100017":
cErrString = "Reader Unavailable";
break;
case "0x80100018":
cErrString = "Shutdown";
break;
case "0x80100019":
cErrString = "PCI Too Small";
break;
case "0x8010001A":
cErrString = "Reader Unsupported";
break;
case "0x8010001B":
cErrString = "Duplicate Reader";
break;
case "0x8010001C":
cErrString = "Card Unsupported";
break;
case "0x8010001D":
cErrString = "No Service";
break;
case "0x8010001E":
cErrString = "Service Stopped";
break;
case "0x80100065":
cErrString = "Unsupported Card";
break;
case "0x80100066":
cErrString = "Unresponsive Card";
break;
case "0x80100067":
cErrString = "Unpowered Card";
break;
case "0x80100068":
cErrString = "Reset Card";
break;
case "0x80100069":
cErrString = "Removed Card";
break;
default:
cErrString = "Unknown PC/SC Error Code - No Further Information Is Available";
break;
}
MessageBox.Show(String.Format("Error Code: 0x{0:X}\n\n" cErrString "\n\n" cText, nErrCode),
"Smart Card PC/SC Error");
}


}
}



取得卡片序號的段code


SCARD_IO_REQUEST SendPci, RecvPci;
byte[] SelEFAPDU = { 0xA0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 }; //Select Elementary File 的 APDU
byte[] ReadSNAPDU = { 0x00, 0xB0, 0x00, 0x04, 0x08 }; //由offset 0 讀取 0x10位 Binary 資料的 APDU
byte[] SelEFRecvBytes = new byte[2]; //應回 90 00
int SelEFRecvLength = 2;
byte[] SNRecvBytes = new byte[18]; //接收卡號的 Byte Array
int SnRecvLength = 18;
//下達 Select FE14 檔的 APDU
SendPci.dwProtocol = RecvPci.dwProtocol = nActiveProtocol;
SendPci.cbPciLength = RecvPci.cbPciLength = 8;

if (SCardTransmit(nCard, ref SendPci, SelEFAPDU, SelEFAPDU.Length,
ref RecvPci, ref SelEFRecvBytes[0], ref SelEFRecvLength) == 0)
{
if (SCardTransmit(nCard, ref SendPci, ReadSNAPDU, ReadSNAPDU.Length,
ref RecvPci, ref SNRecvBytes[0], ref SnRecvLength) == 0)
{
Console.WriteLine("卡號為{0}",
Encoding.Default.GetString(SNRecvBytes, 0, 16));
}
}



會部會是有可能byte[] SelEFAPDU = { 0xA0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 }; //Select Elementary File 的 APDU
byte[] ReadSNAPDU = { 0x00, 0xB0, 0x00, 0x04, 0x08 }; //由offset 0 讀取 0x10位 Binary 資料的 APDU

下錯了,步是第二代金融卡的APDU~~~~~~

編輯記錄
hank73317 重新編輯於 2009-04-07 15:58:38, 註解 無‧
hank73317 重新編輯於 2009-04-07 15:59:49, 註解 無‧
hank73317 重新編輯於 2009-04-07 16:01:32, 註解 無‧
hank73317
一般會員


發表:20
回覆:47
積分:13
註冊:2008-12-12

發送簡訊給我
#2 引用回覆 回覆 發表時間:2009-04-07 18:20:28 IP:122.146.xxx.xxx 訂閱
我在補充一下,我要取得的是ATR~~~~~~~

hank73317
一般會員


發表:20
回覆:47
積分:13
註冊:2008-12-12

發送簡訊給我
#3 引用回覆 回覆 發表時間:2009-04-08 13:36:58 IP:122.146.xxx.xxx 訂閱
 各位大大,我的問題搞定了~~~~

Code給各位參考~~~~~

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace poi
{
public partial class Form1 : Form
{
public struct SCARD_IO_REQUEST
{
public int dwProtocol;
public int cbPciLength;
}
//==========================================================
public enum SCARD_STATE
{
// The application is unaware of the current state, and would like to know. The use
// of this value results in an immediate return from state transition monitoring
// services. This is represented by all bits set to zero.
UNAWARE = 0x00000000,
// The application requested that this reader be ignored. No other bits will be set.
IGNORE = 0x00000001,
// This implies that there is a difference between the state believed by the
// application, and the state known by the Service Manager. When this bit is set,
// the application may assume a significant state change has occurred on this reader.
CHANGED = 0x00000002,
// This implies that the given reader name is not recognized by the Service Manager.
// If this bit is set, then CHANGED and IGNORE will also be set.
UNKNOWN = 0x00000004,
// This implies that the actual state of this reader is not available. If this bit
// is set, then all the following bits are clear.
UNAVAILABLE = 0x00000008,
// This implies that there is not card in the reader. If this bit is set, all the
// following bits will be clear.
EMPTY = 0x00000010,
// This implies that there is a card in the reader.
PRESENT = 0x00000020,
// This implies that there is a card in the reader with an ATR matching one of the
// target cards. If this bit is set, PRESENT will also be set. This bit is only
// returned on the SCardLocateCard() service.
ATRMATCH = 0x00000040,
// This implies that the card in the reader is allocated for exclusive use by
// another application. If this bit is set, PRESENT will also be set.
EXCLUSIVE = 0x00000080,
// This implies that the card in the reader is in use by one or more other
// applications, but may be connected to in shared mode. If this bit is set,
// PRESENT will also be set.
INUSE = 0x00000100,
// This implies that the card in the reader is unresponsive or not supported by the
// reader or software.
MUTE = 0x00000200,
// This implies that the card in the reader has not been powered up.
UNPOWERED = 0x00000400
}

public enum SCARD_SCOPE
{
// The context is a user context, and any database operations are performed within the
// domain of the user.
USER = 0x0000,
// The context is that of the current terminal, and any database operations are performed
// within the domain of that terminal. (The calling application must have appropriate
// access permissions for any database actions.)
TERMINAL = 0x0001,
// The context is the system context, and any database operations are performed within the
// domain of the system. (The calling application must have appropriate access permissions
// for any database actions.)
SYSTEM = 0x0002,
GLOBAL = 0x0003
}
public struct SCARD_READERSTATE
{
/// Reader
public string szReader;
/// User Data
public IntPtr pvUserData;
/// Current State
public SCARD_STATE dwCurrentState;
/// Event State/New State
public SCARD_STATE dwEventState;
/// ATR Length
public UInt32 cbAtr;
/// Card ATR
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]
public byte[] rgbAtr;
}

public static string[] ListReaders()
{
int ReaderSize = -1; //SCARD_AUTOALLOCATE
ErrorCode = SCardListReaders(ContextHandle, null, null, ref ReaderSize);
byte[] ReaderBytes = new byte[ReaderSize];
ErrorCode = SCardListReaders(ContextHandle, null, ReaderBytes, ref ReaderSize);
string[] ReaderList = Encoding.ASCII.GetString(ReaderBytes).Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
return ReaderList;
}
private static void AppendOutput(string format, params object[] items)
{
Console.WriteLine(format, items);
}
private static void AppendOutput()
{
Console.WriteLine();
}
public static string BytesToHex(byte[] ba, int length)
{
return BytesToHex(ba, 0, length);
}
public static byte[] MakeArray(byte[] by, int start, int length)
{
if (start < 0) start = 0;
if (length < 0) length = 0;
byte[] bb = new byte[length];
if (by != null)
if (length > 0 && start < by.Length)
Array.Copy(by, start, bb, 0, length);
return bb;
}
public static string BytesToHex(byte[] ba, int start, int length)
{
byte[] tempb = MakeArray(ba, start, length);
int len = 0;
string separator = "";
string[] hexstrs = Array.ConvertAll(tempb, delegate(byte b)
{
switch ( len)
{
case 16: separator = "\n"; len = 0; break;
case 8: //separator = " "; break;
case 4:
case 12: separator = " "; break;
default: separator = ""; break;
}
return b.ToString("X2") separator;
});
return string.Join("", hexstrs).TrimEnd(separator.ToCharArray());
}
//=================================================================
public Form1()
{
InitializeComponent();
}

[DllImport("winscard.dll")]
public static extern int SCardGetStatusChange(int hContext, uint dwTimeout, ref SCARD_READERSTATE rgReaderStates, int cReaders);
[DllImport("winscard.dll")]
public static extern int SCardEstablishContext(SCARD_SCOPE dwScope, int nNotUsed1, int nNotUsed2, out int hContext);
[DllImport("winscard.dll")]
public static extern int SCardListReaders(int hContext, byte[] cGroups, byte[] cReaders, ref int nReaderCount);
[DllImport("WinScard.dll")]
public static extern int SCardListReaderGroups(int hContext, ref string cGroups, ref int nStringSize);

[DllImport("WinScard.dll")]
public static extern int SCardListReaders(int hContext, string cGroups,
ref string cReaderLists, ref int nReaderCount);

public static int ContextHandle = 0;
public static int ErrorCode = 0;
public static SCARD_READERSTATE[] readerState = null;
public static string[] ReaderList = null;
public static int nReaders = 1, iReader = -1;
private void button1_Click(object sender, EventArgs e)
{

//建立 Smart Card API
ErrorCode = SCardEstablishContext(SCARD_SCOPE.USER, 0, 0, out ContextHandle);
//string[] CardList = ListCards();
//AppendOutput(string.Join("\n", CardList));
ReaderList = ListReaders();
nReaders = ReaderList.Length;
readerState = new SCARD_READERSTATE[nReaders];
SCARD_STATE eventState = SCARD_STATE.UNAWARE;
iReader = -1;
String SmartCardATR="";
for (int i = 0; i < nReaders && iReader < 0; i )
{
readerState[i].szReader = ReaderList[i];
readerState[i].dwCurrentState = SCARD_STATE.UNAWARE;
ErrorCode = SCardGetStatusChange(ContextHandle, 250, ref readerState[i], 1);
if (ErrorCode != 0) continue;
eventState = readerState[i].dwEventState;
readerState[i].dwCurrentState = eventState;
SmartCardATR = SmartCardATR BytesToHex(readerState[i].rgbAtr, (int)readerState[i].cbAtr).ToString();
if (iReader < 0 && 0 != (SCARD_STATE.PRESENT & eventState))
iReader = i;
}
textBox1.Text = SmartCardATR;
//==============================================
char[] delimiter = new char[1];
//Second step in using smart cards is SCardListReaderGroups() to determin reader to use
string cGroupList = "";
int nStringSize = -1; //SCARD_AUTOALLOCATE
int nRetVal2 = SCardListReaderGroups(ContextHandle, ref cGroupList, ref nStringSize);
if (nRetVal2 != 0)
return;

string[] cGroups = cGroupList.Split(delimiter);
string cReaderList = "" Convert.ToChar(0);
int nReaderCount = -1;
/*foreach (string cName in cGroups)
{
MessageBox.Show("Reader Group: " cName);
}*/
/*int nRetVal3 = SCardFreeMemory(this.nContext, ref cGroupList);
if (nRetVal3 != 0)
{
DisplaySCError(nRetVal3,"SCardFreeMemory()");
return;
}*/
int nRetVal4 = SCardListReaders(ContextHandle, cGroups[0], ref cReaderList, ref nReaderCount);

if (nRetVal4 != 0)
return;
textBox2.Text = cReaderList;
//===========================================
}
}
}
系統時間:2024-04-25 2:19:47
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!