How to access SmartCards simply and effectively

本文提供两个演示项目,展示如何简单有效地在Windows中访问智能卡。包括使用类库列出读卡器、连接/断开读卡器、获取智能卡ATR及传输APDU等基本操作。高级演示还支持更灵活的APDU输入方式,如多条APDU、APDU脚本文件等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

How to access SmartCards simply and effectively

Using a set of classes to access SmartCard readers, to test SmartCards via scripts - even to transmit APDUs one by one.

Introduction

This article has two demo projects to show you how to access SmartCards in Windows simply and effectively. If you are not familiar with this field, this is an opportunity to learn something about it.

The basic demo is very simple, it can show you how to list the readers in the system, connect/disconnect it, get the card's ATR, and transmit one APDU with a card.

Note: The basic demo only accepts one APDU without any non-number chars, such as: "0084000008" (get an 8-bytes challenge from the card).

The advanced demo demonstrates how to use SmartCards effectively over the basic layer:

  • There is an APDU processor: it can process the user input
    • One APDU with spaces separating: "0084 0000 08"
    • Multi-APDUs: "0084 0000 08; 00A4 0000 02 3F;"
    • Even an APDU's script file: "c:\myapdu.txt"
  • ATR analyzing, we demonstrate the protocol: T=0, or T=1.
  • Multi-APDU console: This consols is useful for these kinds of tests:
    • You can prompt the user for a 'Press any key to continue' if there is something wrong
    • You can select the console texts by holding the left-button and dragging a rectangle, releasing the left-button - the text is just in your clipboard - just like the Windows cmd.exe does, but this works on Win9x too ;-)

And if you want to know how they are running, you should prepare a SmartCard reader or install a virtual SmartCard reader, and at least one SmartCard.

But if not, there is also the multi-APDU console for you to run scripts in a console during certain occasions in your project, I think.

Background

I have used SmartCards in many projects since 2004, but I really could not find useful classes to access them here in CodeProject or anywhere else on the internet. So I decided to write several classes to show you the process we usually do.

For the SmartCard subsystem in Windows, we should know: the SmartCard reader should be connected to the system, the vender should present us a PC/SC driver, and there is a so called 'SmartCard Resource Manager' for Win32 programs to access all kinds of readers via a set of APIs.

For using these APIs, we should call:

  • SCardEstablishContext(): establishes the SmartCard's context;
  • SCardListReaders(): gets a reader's list from the resource manager;
  • SCardConnect(): connects a reader by giving the reader name;
  • SCardStatus(): gets the ATR from the selected card which is in the 'connected reader';
  • SCardTransmit(): transmits the APDU between the card and our program;
  • SCardDisconnect(): disconnects the connected reader;
  • SCardReleaseContext(): releases the context.

Among these, 4 is optional.

Using the code

As we can see, the basic demo has the core class CSCardmgr. And, its interface is very simple:

// Get the readers' list
BOOL SCardGetPcscList();

// open the reader using the index
BOOL SCardOpen(int nInx);

// Get ATR from the card.
BOOL SCardReset(LPCTSTR strResp);

// Transmit APDU
BOOL SCardTransmit(LPCTSTR strApdu, LPCTSTR strResp, UINT *nSW);

// Close the connected reader
BOOL SCardClose();

Here are two very useful functions to do the string <-> hex, from Mr. Yu, one of my best leaders.

///////////////////////////////////////////////////////////////////////////////
// hex to asc: 0x22 -> "22"
int Hex2Asc(char *Dest,char *Src,int SrcLen)
{
    int i;
    for ( i = 0; i < SrcLen; i ++ )
    {
        sprintf(Dest + i * 2,"%02X",(unsigned char)Src[i]);
    }
    Dest[i * 2] = 0;
    return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
// asc to hex: "22" -> 0x22
int Asc2Hex(char *Dest,char *Src,int SrcLen)
{
    int i;
    for ( i = 0; i < SrcLen / 2; i ++ )
    {
        sscanf(Src + i * 2,"%02X",(unsigned char *)&Dest[i]);
    }
    return TRUE;
}

For the advanced demo, we improve the ATR processing and the APDU processing - these are useful in the SmartCard application. First, the ATR processing: we extract the SmartCard supported protocol only, and displays its protocol at the end of the ATR string.

///////////////////////////////////////////////////////////////////////////////
// Get the ATR information of the open Reader
void CSCardDemoDlg::OnReset() 
{
    CHAR        szATR[ATR_MAX_SIZE * 2 +1] = {0};
    BYTE        byATR[ATR_MAX_SIZE] = {0};
    CHAR        szFullAtr[MAX_RESPONSE] = {0};

    UINT        np = 0;                // Prot.
    BYTE        protocol = ATR_PROTOCOL_TYPE_T0;
    
    ZeroMemory(szATR, sizeof(szATR));

    if(m_SCard.SCardReset(szATR))
    // Do Reset it
    {
        int nLenAtr = strlen(szATR);

        // Convert ATR to Hex format
        Asc2Hex((char*)byATR, szATR, nLenAtr);                

        CAtr            objATR(byATR, nLenAtr/2);

        // get prots supported.
        objATR.ATR_GetNumberOfProtocols(&np);        
        INT nType = objATR.ATR_GetProtocolType(np, &protocol);

        sprintf(szFullAtr, "%s (T=%d).", szATR, protocol);

        // Display the ATR Information
        SetDlgItemText(IDS_MSG, szFullAtr);            
    }
}

Second, we provide the CApduProcesser and CConsoleWindow to improve the APDU transmission experience: the user input is more flexible as described, and we use CApduProcesser for this. We use this code block to eat the non-number chars:

// Eat the non-numeric chars.
for(int i=0, j=0; i < strlen(szSLBuf); i++)
{
    if(szSLBuf[i] >='0' && szSLBuf[i] <= '9')
    {
        szString[j] = szSLBuf[i];
        j ++;
    }
    else if(szSLBuf[i] >='A' && szSLBuf[i] <= 'F')
    {
        szString[j] = szSLBuf[i];
        j ++;
    }
    else if(szSLBuf[i] >='a' && szSLBuf[i] <= 'f')
    {
        szString[j] = szSLBuf[i];
        j ++;
    }
    else
        continue;
}

CConsoleWindow is used for the Console output. Its highlight is 'Any key to continue', and mouse selection:

void CConsoleWindow::WaitForAnyKeyEx()
{
    ... ...

    for(;;)
    {
        /* get an input event */
        bSuccess = ReadConsoleInput(hStdIn, &inputBuffer, 1, &dwInputEvents);
        PERR(bSuccess, "ReadConsoleInput");
        switch (inputBuffer.EventType)
        {
            case KEY_EVENT:
                 ... ...
                break;
            case MOUSE_EVENT:
                 ... ...
                break;
        }
    }

    ... ...
}

The 'KEY_EVENT' is for 'any key to continue', and 'MOUSE_EVENT', yes, for the mouse selection.

Points of Interest

What's a SmartCard? I have no idea, but what I'm sure is my iPhone has a SIM card and it is just a SmartCard. ^_^

If I had a SmartCard reader, I can read the contacts-list from my SIM card by using this demo.

Furthermore, the SmartCard is not just used in reading the SIM card, the PKI also needs it: the CSP and PKCS#11 all need it - (but not must ^_^ ). As I know, many vendors have combined the reader and card, that's the USB token; and the token has a finger scanner or OTP embedded. So, this field is very wonderful.

BTW, SmartCard is a contact card (restricted by ISO7816). There are the so called contactless card (restricted by ISO14443), such as Mifare S50/S70/DES/UL etc. Some venders also provide the so called two-module cards - these cards have two interfaces, and supports both ISO7816 and ISO14443.

History

  • 2008-01-19: First version.
  • 2008-04-12: Virtual PC/SC driver (virtual-pcsc_drv.zip) added for using/testing these demos.

For the driver's license, please refer to the readme.txt. :: It is recommend using this driver in a Virtual Machine. ::


上面的:


  • SCardDemo-Basic 和SCardDemo-Adv 都带源码,vc6的mfc工程,csdn下载频道 也有

转载自:

https://www.codeproject.com/Articles/23018/How-to-access-SmartCards-simply-and-effectively?msg=5445821#xx5445821xx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值