Click here to Skip to main content
15,744,193 members
Articles / Web Development / HTML
Posted 5 Dec 2006


342 bookmarked

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
Describes a framework to use the PCSC Smart Card API with .NET.


 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. 


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.

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.

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.

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.

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.

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
        (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.

[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;
        ApduBuffer = new byte[APDUCommand.APDU_MIN_LENGTH + 1 + 
        for (int nI = 0; nI < ApduCmd.Data.Length; nI++)
            ApduBuffer[APDUCommand.APDU_MIN_LENGTH + 1 + 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, 
        (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.


  • 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:


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

AnswerRe: SCARDSSPLib.dll Pin
orouit16-Jul-13 23:35
professionalorouit16-Jul-13 23:35 
GeneralMy vote of 5 Pin
H-M-Kais27-Jun-13 2:32
H-M-Kais27-Jun-13 2:32 
QuestionError SW=6118 Pin
xyankeesx920919-Jun-13 9:20
xyankeesx920919-Jun-13 9:20 
AnswerRe: Error SW=6118 Pin
orouit16-Jul-13 23:50
professionalorouit16-Jul-13 23:50 
QuestionVerifyPin function error "Value does not fall within the expected range." for admin key Pin
Subhadip Ghosh17-Jun-13 23:46
Subhadip Ghosh17-Jun-13 23:46 
AnswerRe: VerifyPin function error "Value does not fall within the expected range." for admin key Pin
orouit16-Jul-13 23:38
professionalorouit16-Jul-13 23:38 
QuestionProblem with NFC reader Pin
Piotr Błaszczyk5-Jun-13 11:23
Piotr Błaszczyk5-Jun-13 11:23 
AnswerRe: Problem with NFC reader Pin
orouit14-Jun-13 10:50
professionalorouit14-Jun-13 10:50 
I checked the specs of that reader. It has a PCSC interface so once you have installed the drivers, the readers should appear in the list of readers that you can get with my API (which is on top of PCSC) and you can use my code to send commands to the card.
Software Architect, COM, .NET and Smartcard security specialist.

QuestionAccessing Help Pin
polczym29-May-13 0:42
polczym29-May-13 0:42 
Questioncard connection error : SCardReleaseContext error: 6 -SOS Pin
Subhadip Ghosh22-May-13 2:19
Subhadip Ghosh22-May-13 2:19 
AnswerRe: card connection error : SCardReleaseContext error: 6 -SOS Pin
orouit23-May-13 17:08
professionalorouit23-May-13 17:08 
GeneralRe: card connection error : SCardReleaseContext error: 6 -SOS Pin
Subhadip Ghosh26-May-13 21:30
Subhadip Ghosh26-May-13 21:30 
AnswerRe: card connection error : SCardReleaseContext error: 6 -SOS Pin
orouit27-May-13 3:14
professionalorouit27-May-13 3:14 
QuestionRFID support Pin
GIJOGEORGE27-Mar-13 20:11
GIJOGEORGE27-Mar-13 20:11 
AnswerRe: RFID support Pin
orouit1-Apr-13 0:16
professionalorouit1-Apr-13 0:16 
QuestionHID OEM75 MiFare Pin
mrssuper7-Mar-13 10:16
mrssuper7-Mar-13 10:16 
SuggestionRe: HID OEM75 MiFare Pin
orouit8-Mar-13 14:49
professionalorouit8-Mar-13 14:49 
Questioncard is not getting connected Pin
mitesh jadia25-Mar-13 8:20
mitesh jadia25-Mar-13 8:20 
AnswerRe: card is not getting connected Pin
orouit5-Mar-13 15:02
professionalorouit5-Mar-13 15:02 
QuestionMagnetic swipe reader in Pin
Muhil4-Mar-13 17:56
Muhil4-Mar-13 17:56 
AnswerRe: Magnetic swipe reader in Pin
orouit5-Mar-13 14:55
professionalorouit5-Mar-13 14:55 
Questionread only iccid or imsi Pin
Member 825806915-Feb-13 17:32
Member 825806915-Feb-13 17:32 
SuggestionRe: read only iccid or imsi Pin
orouit19-Feb-13 2:32
professionalorouit19-Feb-13 2:32 
GeneralRe: read only iccid or imsi Pin
Member 825806915-Mar-13 0:38
Member 825806915-Mar-13 0:38 
AnswerRe: read only iccid or imsi Pin
orouit21-Mar-13 4:42
professionalorouit21-Mar-13 4:42 

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.