Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

A Smart Card Framework for .NET

4.88/5 (102 votes)
15 May 2015CPOL8 min read 44   145.9K  
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)