Click here to Skip to main content
15,860,972 members
Articles / Web Development / HTML

A Smart Card Framework for .NET

Rate me:
Please Sign up or sign in to vote.
4.88/5 (102 votes)
15 May 2015CPOL8 min read 2.1M   144.9K   342   328
Describes a framework to use the PCSC Smart Card API with .NET.

Introduction  

 On the 18th of February 2013 this article passed the 500000 views mark. Thanks to all the visitors! That's a small figure for the internet but I'm amazed that this small library that was written almost 10 years ago with the beta  of .Net 1.0 is so popular. Another thing that puzzled me is that after 10 years there is still no support for Smart card in the .NET Framework (Except the Crypto service provider of course). Anyway I'll do some re-factoring to improve it because the current architecture is a bit rusty and no so object oriented! 

The .NET Framework has been introduced in 2002, and the version 3.0 has just been released in November. So far, Microsoft hasn't included Smart Card classes in .NET, and if you want to develop a Smart Card aware application, you have to develop your own classes. Fortunately, it is much easier to reuse existing code in .NET than with Java. In Windows, if you need to use Smart Card, you just need to use the PC/SC API in your program. This API comes in C functions or COM objects that wrap the PC/SC functions. The .NET Framework offers two types of interoperabilities with the legacy code: the COM interoperability, and the P/Invoke feature for native code interoperability. I strongly advise to use the Native code that allows more interaction, in particular a better event support. 

Background  

This article demonstrates how to use the interoperability features of .NET and use them to write a simple framework to use a Smart Card in your applications. A Smart Card is a small embedded device that receives commands through a card reader using the PC/SC Win32 API. If you want to use this API, you will need a Smart Card reader to use a Smart Card such as a SIM card.

A Simple Smart Card Framework

The SC framework I'm going to describe is composed of an interface to communicate with the Smart Card, a few classes to wrap the different parameters of a Smart Card command, and the implementation classes depending on the interop mode we are using.

The Smart Card interface provides a simple access to a Smart Card for .NET programs. We will see later how to implement this interface using both the interoperability techniques.

C#
spublic interface ICard
{
    string[] ListReaders();
    void Connect(string Reader, SHARE ShareMode, 
                 PROTOCOL PreferredProtocols);
    void Disconnect(DISCONNECT Disposition);
    APDUResponse Transmit(APDUCommand ApduCmd);
    void BeginTransaction();
    void EndTransaction(DISCONNECT Disposition);
}

The classes APDUCommand and APDUResponse are used to send the command and get the response from the card. SHARE, PROTOCOL, and DISCONNECT are constants used by PC/SC.

C#
public class APDUCommand
{
    public APDUCommand(byte bCla, byte bIns, 
           byte bP1, byte bP2, byte[] baData, byte bLe);
    public void Update(APDUParam apduParam);
    public override string ToString();
    public byte    Class;
    public byte    Ins;
    public byte    P1;
    public byte    P2;
    public byte[]  Data;
    public byte    Le;
}

public class APDUResponse
{
    public APDUResponse(byte[] baData);
    public byte[]    Data;
    public byte    SW1;
    public byte    SW2;
    public ushort    Status;
    public override string ToString();
}

Adding Card Events Support

When a card is inserted in the reader or removed, PC/SC allows you to handle those events. So I added a card event support to this framework based on the event model of .NET. The class CardBase, which inherits from the interface ICard, implements support for two events, CardInserted and CardRemoved. The mechanism of detection is implemented in the derived class that implements ICard. So far I only implemented this support in CardNative. If you want to support the event in your application program, you just need to implement the CardInsertedEventHandler and the CardRemovedEventHandler.

C#
abstract public class CardBase : ICard
{
    public event CardInsertedEventHandler OnCardInserted = null;
    public event CardRemovedEventHandler OnCardRemoved = null;
          
    abstract public string[] ListReaders();
    abstract public void Connect(string Reader, 
             SHARE ShareMode, PROTOCOL PreferredProtocols);
    abstract public void Disconnect(DISCONNECT Disposition);
    abstract public APDUResponse Transmit(APDUCommand ApduCmd);
    abstract public void BeginTransaction();
    abstract public void EndTransaction(DISCONNECT Disposition);
          
    public void StartCardEvents(string Reader);
    public void StopCardEvents();
          
    abstract protected void RunCardDetection();
          
    protected void CardInserted();
    protected void CardRemoved();
}

I developed two implementations of the interface ICard. One is using COM interoperability, and the other using native interoperability with P/Invoke. Both implementations behave the same way. In addition, I ported the P/Invoke implementation for the Compact Framework so it is possible to develop Smart Card applications for the Pocket PC.

CardCOM: A COM Interoperability Implementation Class

COM interoperability is the simplest way to reuse legacy code in .NET framework. All versions of Visual Studio .NET provide very good support for COM. You just need to add a reference to the COM object you need to import, and it generates a wrapper DLL and all the necessary classes to use your COM interfaces. Basically, you don't have to write any code. However, your COM components must respect a few rules, specially regarding the parameters used in the methods. The different interfaces of the PC/SC COM components were written long before .NET existed, and some of the interfaces are not totally compliant with COM interoperability. This is why I had to develop my own COM interface to get the list of readers. For the most important interface, ISCard and the interfaces it uses the import went fine.

C#
interface ISCardDatabaseEx : IDispatch{
    [id(1), helpstring("method ListReaders")] 
       HRESULT ListReaders([out,retval] VARIANT* ppReaders);
};

The COM component I developed replaces the ISCardDatabase interface, and only implements one of its methods: ListReaders. In the Microsoft implementation, the return parameter is a SAFEARRAY of BSTR, which unfortunately .NET is unable to import properly. The right way to do it is to use a VARIANT* that contains the SAFEARRAY of BSTR. Then, .NET will generate a wrapper method that returns an object that you just have to cast into a string[]. Using a COM object in .NET is as simple as adding a reference to this object in your code. Visual Studio will then generate a wrapper class that you directly use in your code. The following extract illustrates this.

C#
using SCARDSSPLib;    // use the SCard COM object

/// <summary>
/// Default constructor
/// </summary>
public CardCOM()
{
    // Create the SCard object
    m_itfCard = new CSCardClass();
}

public override void Connect(string Reader, 
       SHARE ShareMode, PROTOCOL PreferredProtocols)
{
    // Calls AttachReader to connect to the card
    m_itfCard.AttachByReader(Reader, 
        (SCARD_SHARE_MODES) ShareMode, 
        (SCARD_PROTOCOLS) PreferredProtocols);
}

The ISCardDatabase interface is provided in a DLL that must be registered with Regsvr32.

CardNative: A Native Interoperability Implementation Class using P/Invoke

The Platform Invoke mechanism (P/Invoke) is a very powerful mechanism that gives total access to the Win32 platform API. The .NET framework provides a complete set of classes that you can use to achieve every marshaling operation necessary to call Win32 functions from .NET. Those classes are defined in the System.Runtime.InteropServices assembly that you just need to import in your program. The P/Invoke mechanism, even if it is a bit complex, is far more convenient than the JNI mechanism of Java. All the atomic types like int, byte, long, etc... are automatically marshaled by the compiler itself. The byte[] is also automatically marshaled as an input or output parameter. When you have to deal with more complex parameters like strings, structures, or a pointer to a structure, .NET provides a set of marshaling classes that can be used as attributes or objects in your program when marshaling parameters. To develop the CardNative class, I didn't have to develop any extra code to use the PC/SC API, all the code is in the source file CardNative.cs. When you want to use a Win32 API C function, you need to declare the function in your class using the interoperability attributes provided by the System.Runtime.InteropServices assembly. Once you have declared the function, you can just use it as any C# method in your class. The following code sample illustrates this mechanism.

C#
[DllImport("winscard.dll", SetLastError=true)]
internal static extern    int    SCardTransmit(UInt32 hCard,
    [In] ref SCard_IO_Request pioSendPci,
    byte[] pbSendBuffer,
    UInt32 cbSendLength,
    IntPtr pioRecvPci,
    [Out] byte[] pbRecvBuffer,
    out UInt32 pcbRecvLength
);

public override APDUResponse Transmit(APDUCommand ApduCmd)
{
    uint    RecvLength = (uint) (ApduCmd.Le + APDUResponse.SW_LENGTH);
    byte[]    ApduBuffer = null;
    byte[]    ApduResponse = new byte[ApduCmd.Le + APDUResponse.SW_LENGTH];
    SCard_IO_Request    ioRequest = new SCard_IO_Request();
    ioRequest.m_dwProtocol = m_nProtocol;
    ioRequest.m_cbPciLength = 8;

    // Build the command APDU

    if (ApduCmd.Data == null)
    {
        ApduBuffer = new byte[APDUCommand.APDU_MIN_LENGTH + 
                    ((ApduCmd.Le != 0) ? 1 : 0)];

        if (ApduCmd.Le != 0)
            ApduBuffer[4] = (byte) ApduCmd.Le;
    }
    else
    {
        ApduBuffer = new byte[APDUCommand.APDU_MIN_LENGTH + 1 + 
                              ApduCmd.Data.Length];
        for (int nI = 0; nI < ApduCmd.Data.Length; nI++)
            ApduBuffer[APDUCommand.APDU_MIN_LENGTH + 1 + nI] = 
                                              ApduCmd.Data[nI];
        ApduBuffer[APDUCommand.APDU_MIN_LENGTH] = 
                 (byte) ApduCmd.Data.Length;
    }

    ApduBuffer[0] = ApduCmd.Class;
    ApduBuffer[1] = ApduCmd.Ins;
    ApduBuffer[2] = ApduCmd.P1;
    ApduBuffer[3] = ApduCmd.P2;

    m_nLastError = SCardTransmit(m_hCard, 
        ref ioRequest, 
        ApduBuffer, 
        (uint) ApduBuffer.Length, 
        IntPtr.Zero, ApduResponse, out RecvLength); 

    if (m_nLastError != 0)
    {
        string msg = "SCardTransmit error: " + m_nLastError;
        throw new Exception(msg);
    }

    byte[] ApduData = new byte[RecvLength];

    for (int nI = 0; nI < RecvLength; nI++)
        ApduData[nI] = ApduResponse[nI];
 
    return new APDUResponse(ApduData);
}

Demo Application

The Smart Card API is very easy to use. However, if you want to write a Smart Card application, you must know the commands to send to the card to perform operations such as selecting files, verifying PINs, or reading data. Those commands are called APDU commands, and are described in the specification of the Smart Card you want to access. The purpose of this article is not to explain how to use a Smart Card, but to give you a simple C# API to play with any Smart Card you'd want.

Most people have a GSM phone so if you have a Smart Card reader on your PC (some laptops come with an embedded Smart Card reader), you can use the little demo program to play with your SIM card. This simple program presents the PIN (if your PIN is activated), selects the phone number file, and reads the 10 first records of this file. Everything you will get is in binary format like it is stored in the card. If your PIN is activated, you must uncomment the line that verifies the PIN in my code. The PIN value is entered in binary. If your PIN is 1234, you must enter 31323334 and pad with FF bytes until the PIN length is 8.

In the second part of this article, I will present a more advanced framework to write Smart Card applications. This framework will use the classes I described in this article, and will make it easier writing Smart Card applications.

Image 1

WCS Smart card service

In a recent article I have added a WCF service to expose the ICard interface implemented by the NativeCard class. Doing that I have improved a little the exception support in the original code.

For the moment only 32 bits is supported and the card events are not yet mapped to the WCF service.  

Points of Interest 

In this first part, we have seen two methods to use legacy code with .NET. This is one of the very powerful features of .NET that makes it the ideal managed framework to develop applications on the Windows platform. This Smart Card framework can be very useful if you want to access a Smart Card application in your .NET code. Of course, VB.NET users can use this framework as well.

However, this set of class still requires that you write dedicated code to access the card using the APDU command which is not the most interesting code to write. In the second part of this article, I will give you an XML framework that allows to write Smart Card applications with minimum code, using XML declarations.

History

  • 5 Mar 2007 - Added a support for the ATR and other attributes, SCardGetAttrib function of PC/SC
  • 16 Aug 2011 - Added project updated for Visual Studio 2010
  • 26 Aug 2011 - Added 64 bit project for Visual Studio 2008, 2010
  • 29 Janv 2013 - Exception support improvement, added a WCF service that wraps ICard  
  • 20 Feb 2013 - 500000 views mark. 
  • 15 May 2015 - Corrected few issues while adding some support for Mifare Classic cards. Please get the code form Github: https://github.com/orouit/SmartcardFramework.git

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Connect In Private
Singapore Singapore
Software Architect, COM, .NET and Smartcard based security specialist.

I've been working in the software industry since I graduated in Electrical and Electronics Engineering. I chose software because I preferred digital to analog.

I started to program with 6802 machine code and evolved to the current .NET technologies... that was a long way.

For more than 20 years I have always worked in technical positions as I simply like to get my hands dirty and crack my brain when things don't go right!

After 12 years in the smart card industry I can claim a strong knowledge in security solutions based on those really small computers!
I've been back into business to design the licensing system for the enterprise solution for Consistel using a .NET smart card (yes they can run .NET CLR!)

I'm currently designing a micro-payment solution using the NXP DESFire EV1 with the ACSO6 SAM of ACS. I can then add a full proficient expertise on those systems and NFC payments.
This technology being under strict NDA by NXP I cannot publish any related article about it, however I can provide professional consulting for it.

You can contact me for professional matter by using the forum or via my LinkedIn profile.

Comments and Discussions

 
QuestionDEMOscfmwk.exe Object reference not set to an instance of an object. Pin
Ron Anders18-Jul-21 2:24
Ron Anders18-Jul-21 2:24 
QuestionNot Working With My Smart Card Reader Pin
Shohag_Ifas6-Dec-19 19:21
Shohag_Ifas6-Dec-19 19:21 
QuestionNo functionality for reading certificates Pin
Member 113541348-Mar-19 6:38
Member 113541348-Mar-19 6:38 
QuestionHow to implement this framework into my application. PinPopular
Member 1414997122-Feb-19 18:40
Member 1414997122-Feb-19 18:40 
QuestionBtnConnect Click Button Throw Exception SCardConnect error: -2146434970 Pin
PremShah129-Nov-18 21:48
PremShah129-Nov-18 21:48 
QuestionSome Questions Pin
Maximiliano Cesan29-Aug-18 9:03
Maximiliano Cesan29-Aug-18 9:03 
AnswerRe: Some Questions Pin
PremShah129-Nov-18 22:05
PremShah129-Nov-18 22:05 
QuestionSome reader oddities Pin
Marbry Hardin22-May-18 7:14
Marbry Hardin22-May-18 7:14 
BugRead binary data larger than 256 bytes Pin
jpzeeman27-Dec-17 22:19
jpzeeman27-Dec-17 22:19 
QuestionSend APDU Command with Le Recv Data Pin
Ibpet117-Dec-17 23:08
Ibpet117-Dec-17 23:08 
Questionhow to get badge number Pin
Member 1280273424-Oct-17 4:44
Member 1280273424-Oct-17 4:44 
QuestionACR1281U-C8 Contactless Smart Card Reader Pin
Cool Smith29-Aug-17 7:52
Cool Smith29-Aug-17 7:52 
QuestionHID Omnikey Smart Card Reader Pin
Member 131346468-May-17 21:08
Member 131346468-May-17 21:08 
QuestionRead From DESFire EV1 Pin
inerloop25-Dec-16 18:42
inerloop25-Dec-16 18:42 
QuestionHow to control Smart card readers without card on them? Pin
F.moghaddampoor19-Jul-16 9:38
F.moghaddampoor19-Jul-16 9:38 
QuestionNeed to send APDU commands on CardInsert Event Pin
Rahul Vaishnav26-May-16 20:48
Rahul Vaishnav26-May-16 20:48 
Question[SIM CARD] Pin
Member 1248867229-Apr-16 23:42
Member 1248867229-Apr-16 23:42 
AnswerRe: [SIM CARD] Pin
Member 124886722-May-16 10:57
Member 124886722-May-16 10:57 
QuestionStartCardEvents method is throwing an exception Pin
raisleger3-Mar-16 8:12
raisleger3-Mar-16 8:12 
AnswerRe: StartCardEvents method is throwing an exception Pin
devistanbul5-Mar-16 5:52
devistanbul5-Mar-16 5:52 
GeneralRe: StartCardEvents method is throwing an exception Pin
orouit20-Mar-16 14:28
professionalorouit20-Mar-16 14:28 
QuestionProblems reading from i²c card with smardcard framework 2010 Pin
Member 802402510-Feb-16 10:18
Member 802402510-Feb-16 10:18 
AnswerRe: Problems reading from i²c card with smardcard framework 2010 Pin
orouit20-Mar-16 14:32
professionalorouit20-Mar-16 14:32 
AnswerRe: Problems reading from i²c card with smardcard framework 2010 Pin
orouit20-Mar-16 14:35
professionalorouit20-Mar-16 14:35 
QuestionSmart Card Contactless Reader Pin
hamzeh8315-Nov-15 20:45
hamzeh8315-Nov-15 20:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.