I currently only have access to, and interest in, DESFire cards, so what follows may only be relevant to them. I have written a small sample program, mainly based on the examples provided by the pcsc-sharp package, which demonstrates how to retrieve the application identifiers from the card, and its unique identifier (UID). Paste the code into a new C# Console Application, and if you have a USB card reader attached and a DESFire card, it should work straight away.
Note that all commands are sent and retrieved as hexadecimal bytes. You could define these in C# as bytes directly, such as
byte[] cmdGetApplicationIds = new byte[]{0xFF, 0xCA, 0x00, 0x00, 0x00};
but I found it more readable to define them as strings and convert when required. See functions StringToByte() and ShowBytes() for how this is done.
using PCSC;
using System;
using System.Linq;
namespace DESFire.Communications
{
class Program
{
static void Main(string[] args)
{
var cmdGetApplicationIds = StringToByte("6A");
var cmdGetUID = StringToByte("FF CA 00 00 00");
try
{
SCardContext hContext;
SCardReader reader;
SCardError err;
IntPtr pioSendPci;
SetUpReader(out reader, out err, out pioSendPci, out hContext);
var response = SendCommand(reader, ref err, pioSendPci,
cmdGetApplicationIds, "Get application IDs");
response = SendCommand(reader, ref err, pioSendPci,
cmdGetUID, "Get UID");
hContext.Release();
}
catch (PCSCException ex)
{
Console.WriteLine("Ouch: "
+ ex.Message
+ " (" + ex.SCardError.ToString() + ")");
}
// Keep console window open if running from Visual Studio
Console.ReadKey();
}
private static void SetUpReader(out SCardReader reader, out SCardError err,
out IntPtr pioSendPci, out SCardContext hContext)
{
// Establish SCard context
hContext = new SCardContext();
hContext.Establish(SCardScope.System);
// Retrieve the list of Smartcard readers
string[] szReaders = hContext.GetReaders();
if (szReaders.Length <= 0)
throw new PCSCException(SCardError.NoReadersAvailable,
"Could not find any Smartcard reader.");
Console.WriteLine("reader name: " + szReaders[0]);
// Create a reader object using the existing context
reader = new SCardReader(hContext);
// Connect to the card
err = reader.Connect(szReaders[0],
SCardShareMode.Shared,
SCardProtocol.T0 | SCardProtocol.T1);
CheckErr(err);
switch (reader.ActiveProtocol)
{
case SCardProtocol.T0:
pioSendPci = SCardPCI.T0;
break;
case SCardProtocol.T1:
pioSendPci = SCardPCI.T1;
break;
default:
throw new PCSCException(SCardError.ProtocolMismatch,
"Protocol not supported: "
+ reader.ActiveProtocol.ToString());
}
}
/// <summary>
/// Send command to smart card, displaying request and response to console
/// </summary>
/// <param name="message">optional message to display</param>
/// <returns></returns>
private static byte[] SendCommand(SCardReader reader, ref SCardError err,
IntPtr pioSendPci, byte[] command, string message = "")
{
byte[] buffer = new byte[256];
Console.WriteLine();
Console.WriteLine(message);
ShowBytes(command, " request");
err = reader.Transmit(pioSendPci, command, ref buffer);
CheckErr(err);
ShowBytes(buffer, "response");
return buffer;
}
static void CheckErr(SCardError err)
{
if (err != SCardError.Success)
throw new PCSCException(err,
SCardHelper.StringifyError(err));
}
/// <summary>
/// Convert string of hexadecimal text into array of bytes
/// </summary>
/// <param name="hexWithSpaces">string of hex bytes with optional spaces</param>
/// <returns>array of bytes</returns>
public static byte[] StringToByte(string hexWithSpaces)
{
var hex = hexWithSpaces.Replace(" ", "");
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
/// <summary>
/// Display array of bytes on console
/// </summary>
/// <param name="resultArray">bytes to show</param>
/// <param name="message">optional message to display</param>
private static void ShowBytes(byte[] resultArray, string message = "")
{
Console.Write((message + ": ").PadLeft(20, ' '));
for (int i = 0; i < resultArray.Length; i++)
Console.Write("{0:X2} ", resultArray[i]);
Console.WriteLine();
}
}
}
Now that you can communicate with your DESFire card you probably want to authenticate.