c# - 如何使用 C# 通过串口使用 APDU 命令与智能卡通信
问题描述
我一直在尝试使用 APDU 命令通过串行端口与 MCR200 读/写器硬件上的 EMV 智能卡进行通信,但仍然没有成功。我没有得到和回应。这是我到目前为止所尝试的。至少我想在继续读取和写入智能卡记录之前先获取卡的 ATR。
namespace JappaSmartCard
{
public partial class BankWrite : Form
{
public SerialPort port = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
public long bytesRead;
public byte[] buffer;
List<byte> bBuffer = new List<byte>();
string sBuffer = String.Empty;
private long SendLen, RecvLen;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 262)]
private byte[] SendBuff;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 262)]
private byte[] RecvBuff;
private const int INVALID_SW1SW2 = -450;
public BankWrite()
{
InitializeComponent();
port.Handshake = Handshake.None;
port.Encoding = Encoding.ASCII;
port.ReceivedBytesThreshold = 1;
//port.ReadTimeout = 5000;
//port.WriteTimeout = 5000;
initMenu();
// Attach a method to be called when there
// is data waiting in the port's buffer
port.DataReceived += new SerialDataReceivedEventHandler(verifyChv);
}
private void BankWrite_Load(object sender, EventArgs e)
{
pbProgress.Visible = false;
}
private void initMenu()
{
pbProgress.Visible = false;
btnWrite.Enabled = false;
btnConnect.Enabled = false;
btnRead.Enabled = false;
btnSave.Enabled = false;
btnUSB.Enabled = false;
btnFormat.Enabled = false;
btnError.Enabled = false;
btnDuplicate.Enabled = false;
gbSelectHardware.Enabled = false;
gbDetails.Enabled = false;
gbTrack1.Enabled = false;
gbTrack2.Enabled = false;
gbTrack3.Enabled = false;
txtAccountNo.Text = "";
txtFirstName.Text = "";
txtLastName.Text = "";
txtPin.Text = "";
rtbInfo.Text = "";
rtbTrack1.Text = "";
rtbTrack2.Text = "";
rtbTrack3.Text = "";
ckbARC.Checked = false;
ckbARQC.Checked = false;
ckbDDA.Checked = false;
}
private void EnableConnectButton()
{
btnInitialize.Enabled = false;
gbSelectHardware.Enabled = true;
btnConnect.Enabled = true;
}
private void ClearBuffers()
{
}
private void DisplayOut(int mType, long msgCode, string PrintText)
{
switch (mType)
{
case 0: // Notifications only
{
rtbInfo.SelectionColor = Color.Blue;
break;
}
case 1: // PC/SC Error Messages
{
rtbInfo.SelectionColor = Color.Red;
PrintText = Card.GetScardErrMsg(bytesRead);
break;
}
case 2: // Input APDU command
{
rtbInfo.SelectionColor = Color.Black;
PrintText = "< " + PrintText;
break;
}
case 3: // Output data
{
rtbInfo.SelectionColor = Color.Green;
PrintText = "> " + PrintText;
break;
}
case 4: // Notifications on red font
{
rtbInfo.SelectionColor = Color.Maroon;
break;
}
}
rtbInfo.SelectedText = PrintText + "\r\n";
rtbInfo.SelectionStart = rtbInfo.TextLength;
rtbInfo.SelectionColor = Color.Black;
}
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Show all the incoming data in the port's buffer
rtbInfo.Invoke(new EventHandler(delegate { rtbInfo.Text += port.ReadExisting(); }));
// Use either the binary OR the string technique (but not both)
// Buffer and process binary data
while (port.BytesToRead > 0)
bBuffer.Add((byte)port.ReadByte());
ProcessBuffer(bBuffer);
// Buffer string data
sBuffer += port.ReadExisting();
ProcessBuffer(sBuffer);
}
private void ProcessBuffer(string sBuffer)
{
}
private void ProcessBuffer(List<byte> bBuffer)
{
}
private void btnQuit_Click(object sender, EventArgs e)
{
//Application.ExitThread();
port.Close();
this.Hide();
}
private void btnInitialize_Click(object sender, EventArgs e)
{
//Get all the ports attached
pbProgress.Visible = true;
pbProgress.Maximum = SerialPort.GetPortNames().Length;
pbProgress.Step = 1;
foreach (string s in SerialPort.GetPortNames())
{
cboReaders.Items.Add(s);
pbProgress.PerformStep();
Console.WriteLine(s);
}
cboReaders.Text = "COM1";
port = new SerialPort(cboReaders.Text,9600, Parity.None, 8, StopBits.One);
port.Handshake = Handshake.None;
port.Encoding = Encoding.ASCII;
port.ReceivedBytesThreshold = 1;
EnableConnectButton();
}
[STAThread]
private void btnConnect_Click(object sender, EventArgs e)
{
if (!port.IsOpen)
port.Open();
bytesRead = 0;
//close All open thread
//Application.ExitThread();
// Enter an application loop to keep this thread alive
//Application.Run();
pbProgress.Visible = false;
btnWrite.Enabled = true;
btnConnect.Enabled = false;
btnRead.Enabled = true;
btnSave.Enabled = false;
btnUSB.Enabled = false;
btnFormat.Enabled = true;
// Check if PIN is correct
port.Write(new byte[] { 0x03, 0x20, 0x00, 0x02, 0x08, 0x31, 0x30, 0x35, 0x34, 0xFF, 0xFF, 0xFF, 0xEE }, 0, 13);
Console.WriteLine(port.BytesToWrite);
}
public void verifyChv(object s, SerialDataReceivedEventArgs e)
{
byte[] buffer = new byte[port.ReadBufferSize];
int bytesRead = port.Read(buffer, 0, buffer.Length);
foreach (int bf in buffer)
{
rtbInfo.Text += bf.ToString("X");
}
}
private string InterpretarHex(object buffer, bool conEspacios = false)
{
string sol="";
object byteAux;
if (buffer.ToString().Length > 0)
{
byteAux = ((int)(Card.Asc((char)((Card.Mid(buffer.ToString(), 1, 1)[0]))))).ToString("X");
sol = byteAux.ToString();
for (var i = 2; i <= (buffer.ToString()).Length; i++)
{
byteAux = ((int)(Card.Asc((char)((Card.Mid(buffer.ToString(), i, 1)[0]))))).ToString("X");
if ((byteAux.ToString()).Length == 1)
byteAux = "0" + byteAux;
if ((conEspacios))
sol = sol + " " + byteAux;
else
sol = sol + byteAux;
}
}
return sol;
}
private void btnFormat_Click(object sender, EventArgs e)
{
}
private long SendAPDUandDisplay(int SendType, string ApduIn)
{
long SendAPDUandDisplay = 0;
return SendAPDUandDisplay;
}
private long SubmitIC()
{
long SubmitIC = 0;
return SubmitIC;
}
private long SelectFile(byte HiAddr, byte LoAddr)
{
long SelectFile = 0;
return SelectFile;
}
private long readRecord(byte RecNo, byte dataLen)
{
long readRecord = 0;
return readRecord;
}
private long writeRecord(int caseType, byte RecNo, byte maxLen, byte dataLen, ref byte[] ApduIn)
{
//sample code
byte[] data = System.Text.ASCIIEncoding.Default.GetBytes("Hello World\n");
port.Write(data, 0, data.Length);
return port.BytesToWrite;
}
private void cboReaders_SelectedIndexChanged(object sender, EventArgs e)
{
if(cboReaders.Items.Count>0)
{
if (cboReaders.SelectedIndex >= 0)
{
Console.WriteLine(cboReaders.Text);
}
else
{
cboReaders.Text = "COM1";
}
port = new SerialPort(cboReaders.Text, 9600, Parity.None, 8, StopBits.One);
port.Handshake = Handshake.None;
port.Encoding = Encoding.ASCII;
port.ReceivedBytesThreshold = 1;
initMenu();
EnableConnectButton();
}
else
{
rtbInfo.Text = "NO SERIAL/COM PORT DEVICE SEEN";
}
}
}
}
解决方案
我已经实现了一个开源 EMV 支付框架(https://github.com/vicente-da-silva/dcemv)。这实现了 EMV 非接触式和接触式内核。有各种 NFC 驱动程序。您可以使用它与卡进行通信。它是用 C# 编写的。
推荐阅读
- html - 使用引导程序在 vue js 中的 json 中恢复它们
- java - CAS apereo 5.3:创建定制的 MFA
- apache-camel - JsonPath 语言中的骆驼简单表达式?
- python - Flask Deploy to Heroku Error 2019-04-16T09:17:52.610857+00:00 heroku[router]: at:error code:H10 desc:App crashed
- sql - 选择不同的(col a) max(colb)
- mysql - Where 子句在(插入前)触发器中不起作用,该触发器将值设置为来自不同表的列
- ios - 如何在不验证收据的情况下访问 iOS 收据字段/属性?
- python - 在精神病实验中操纵呈现的计时器
- python - 无法将 Deeplab 模型导出到冻结图
- python - 如何在没有 AWS Vault 的情况下使用 boto3?