Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Smartcard Framework for .NET Compact Framework

0.00/5 (No votes)
30 Jan 2007 1  
This article describes a framework to use the PCSC smartcard API with .NET on a PocketPC

Introduction

In a couple of previous articles I presented a .NET API and a simple XML framework to write smart card application for the .NET environment. When I first developed this framework I also made a version for the Compact Framework and specially for the PocketPC. As I had some request from readers regarding the CE version I have decided to write this short article about it. I recommend that you first read my to other articles, A .NET API for PC/SC and An XML framework for Smart card application, because I describe only the main differences of the CF version compared to a full .NET 2.0 version.

A simple Smart card Framework

The CF version of the smart card classes is very similar to the one I intorduced previously. You can find below the interface and the base classes that are used to manage the card communication and the command format.

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

The classes APDUCommand and APDUResponse are used to send the command and get the response from the card. SHARE, <code>PROTOCOL and DISCONNECT are enumerations of 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();
}

The PocketPC version doesn't provide any event management and unlike the PC version there is no implementation using the a COM version of PC/SC, because it doesn't exist on CE and also because there is no COM interop support with the Compact Framework.

So the only implementation of the ICard interface is a NativeCard class that use the native interop of .NET.

CardNative: A native interoperability implementation class using P/Invoke

The Platform Invoke mechanism (P/Invoke) is a very powerful mechanism that gives a 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 input or output parameter. When you have to deal with more complex parameters like strings, structure or pointers to structure, .NET provides a set of marshaling classes that can be used as attributes or object in you 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 CardNative.cs. When you want to use a Win32 API C function you need to declare the function in your class using the interoperabilty 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.

The main differences between the PC version and the PocketPC version is that the PC/SC functions are not located in the same DLL and that parameters passed using a pointer, except for the byte array are not automatically marshaled. There are also some memory allocation functions that are not provided by the Compact Framework and you need to use the C native functions.

Memory functions that you need to import.

[DllImport("coredll.dll", SetLastError=true)]
internal static extern IntPtr    LocalAlloc(UInt32 uFlags, UInt32 uBytes);

[DllImport("coredll.dll", SetLastError=true)]
internal static extern IntPtr LocalFree(IntPtr hMem);

Declaration of the PC/SC native functions

[DllImport("scardce.dll", SetLastError=true, CharSet=CharSet.Auto )]
internal static extern int SGCardListReaders(UInt32 hContext, 
                          IntPtr mszReaders, out UInt32 pcchReaders);

[DllImport("scardce.dll", SetLastError=true)]
 internal static extern int SGCardEstablishContext(UInt32 dwScope, 
                                                   IntPtr phContext);

[DllImport("scardce.dll", SetLastError=true)]
internal static extern int SGCardReleaseContext(UInt32 hContext);

[DllImport("scardce.dll", SetLastError=true, CharSet=CharSet.Auto)]
internal static extern int SGCardConnect(UInt32 hContext, 
    byte[] szReader, 
    UInt32 dwShareMode, 
    UInt32 dwPreferredProtocols,
    IntPtr phCard, 
    IntPtr pdwActiveProtocol);

[DllImport("scardce.dll", SetLastError=true)]
internal static extern int SGCardDisconnect(UInt32 hCard, 
                                            UInt32 dwDisposition);

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

If you have a look to the declaration of the PC/SC functions you will notice some differences with the PC declaration. For example there is no automatic marshalling of the strings and you need to handle them as an array of bytes. For the rest the declaration is the same.

The following code shows how to pass a string to the PC/SC function SCardConnect.

public void Connect(string Reader, SHARE ShareMode, 
                    PROTOCOL PreferredProtocols)
{
    IntPtr    hCard = IntPtr.Zero;
    IntPtr    pProtocol = IntPtr.Zero;

    try
    {
        if (m_hContext == 0)
            EstablishContext(SCOPE.User);

        // Allocate the memory to receive the pointer's data
        hCard = LocalAlloc(0, (UInt32) Marshal.SizeOf(m_hCard));
        pProtocol = LocalAlloc(0, (UInt32) Marshal.SizeOf(m_nProtocol));

        // Get a byte array version of the string 
        byte[] baReader = Encoding.Unicode.GetBytes(Reader);
        m_nLastError = SGCardConnect(m_hContext, 
            baReader, 
            (uint) ShareMode, 
            (uint) PreferredProtocols, 
            hCard,
            pProtocol);

        if (m_nLastError != 0)
        {
            string msg = "SCardConnect error: " + m_nLastError;

            throw new Exception(msg);
        }

        m_hCard = (uint) Marshal.ReadInt32(hCard);
        m_nProtocol = (uint) Marshal.ReadInt32(pProtocol);
    }
    catch
    {
        throw;
    }
    finally
    {
        LocalFree(hCard);
        LocalFree(pProtocol);
    }
}

This code is very interesting because it shows all the differences that there are between the PC and the PocketPC version. In addition to the string management you can see that to get the card handle (m_hCard) and the protocol (pProtocol) you first need to allocate the memory to get them using the native allocation functions. On the exit of the function, if it worked you then need to get the data from the memory the same way you would do with the PC version.

Demo application: An Exchange APDU application for the PocketPC

When it comes to use the ICard interface in an application there is strictly no difference with the PC except with the limitation that exist with the .NET Compact Framework.

I designed a simple exchange APDU application that uses an older version of my APDUList.xml (there are few differences in the declaration of the APDU). The only problem that you may have is that there are not a lot of smart card readers available in the market. I developed this application using a smart card embedded in a SD card and a small smart card reader that you plug on a SD card slot. I know that there is also an extension for iPaq where you can plug a PCI smart card reader.

This is a screen shot done with the Visual Studio emulator which unfortunately cannot connect the smart card reader of the PC.

Points of Interest

This short article demonstrates the differences that there can be when you develop the same kind of application on a PC or a PocketPC. Even if the differences are less than when using a language like C++, as the CF is a subset of the .NET framework and that support for interoperability is not totally implemented it can be quite difficult to achieve the same level of functionalities.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here