VC中PC/SC智能卡接口的编程(2)

3.4 向智能卡发送指令
函数ScardTransmit()向智能卡发送指令,并接受返回的数据。
函数原型:LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_I0_REQUEST pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength);
各个参数的含义:(1)hCard:输入类型;与智能卡连接的句柄。(2)pioSendPci:输入类型;指令的协议头结构的指针,由SCARD_IO_REQUEST结构定义。后面是使用的协议的协议控制信息。一般使用系统定义的结构,SCARD_PCI_T0(T=0协议)、 SCARD_PCI_T1(T=1协议)、SCARD_PCI_RAW(原始协议)。(3)pbSendBuffer:输入类型;要发送到智能卡的数据的指针。(4)cbSendLength:输入类型;pbSendBuffer的字节数目。(5)pioRecvPci:输入输出类型;指令协议头结构的指针,后面是使用的协议的协议控制信息,如果不返回协议控制信息,可以为NULL。(6)pbRecvBuffer:输入输出类型;从智能卡返回的数据的指针。(7)pcbRecvLength:输入输出类型;pbRecvBuffer的大小和实际大小。

对于T=0协议,收发缓冲的用法如下:
(a)向智能卡发送数据:要向智能卡发送n>0字节数据时,pbSendBuffer 前4字节分别为T=0的CLA、INS、P1、P2,第5字节是n,随后是n字节的数据;cbSendLength值为n+5(4字节头+1字节Lc+n字节数据)。PbRecvBuffer将接收SW1、SW2状态码;pcbRecvLength值在调用时至少为2,返回后为2。
BYTE        recvBuffer[260];
int         sendSize, recvSize;
BTYE        sw1, sw2;
BYTE    select_mf[]={0xC0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00};
sendSize=7;
recvSize=sizeof(recvBuffer);
lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, select_mf, sendSize,
NULL, recvBuffer, &recvSize);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardTransmit/n");
exit(1);
}
//返回的数据,recvSize=2
sw1=recvBuffer[recvSize-2];
sw2=recvBuffer[recvSize-1];

(b)从智能卡接收数据:为从智能卡接收n>0字节数据,pbSendBuffer 前4字节分别为T=0的CLA、INS、P1、P2,第5字节是n(即Le),如果从智能卡接收256字节,则第5字节为0;cbSendLength值为5(4字节头+1字节Le)。PbRecvBuffer将接收智能卡返回的n字节,随后是SW1、SW2状态码;pcbRecvLength的值在调用时至少为 n+2,返回后为n+2。
BYTE        get_challenge[]={0x00, 0x84, 0x00, 0x00, 0x08};
sendSize=5;
recvSize=sizeof(recvBuffer);
lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, get_challenge,
sendSize, NULL, recvBuffer, &recvSize);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardTransmit/n");
exit(1);
}
//返回的数据, recvSize=10
sw1=recvBuffer[recvSize-2];
sw2=recvBuffer[recvSize-1];
//data=recvBuffer[0]----recvBuffer[7]

(c)向智能卡发送没有数据交换的命令:应用程序既不向智能卡发送数据,也不从智能卡接收数据,pbSendBuffer 前4字节分别为T=0的CLA、INS、P1、P2,不发送P3;cbSendLength 值必须为4。PbRecvBuffer从智能卡接收SW1、SW2状态码;pcbRecvLength值在调用时至少为2,返回后为2。
BYTE    set_flag[]={0x80, 0xFE, 0x00, 0x00};
sendSize=4;
recvSize=sizeof(recvBuffer);
lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, set_flag, sendSize,
NULL, recvBuffer, &recvSize);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardTransmit/n");
exit(1);
}
//返回的数据,recvSize=2
sw1=recvBuffer[recvSize-2];
sw2=recvBuffer[recvSize-1];

(d)向智能卡发送具有双向数据交换的命令:T=0协议中,应用程序不能同时向智能卡发送数据,并从智能卡接收数据,即发送到智能卡的指令中,不能同时有Lc和Le。这只能分两步实现:向智能卡发送数据,接收智能卡返回的状态码,其中,SW2是智能卡将要返回的数据字节数目;从智能卡接收数据(指令为0x00、0xC0、0x00、0x00、Le)。
BYTE    get_response={0x00, 0xc0, 0x00, 0x00, 0x00};
BYTE    internal_auth[]={0x00, 0x88, 0x00, 0x00, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
sendSize=13;
recvSize=sizeof(recvBuffer);
lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, internal_auth,
sendSize, NULL, recvBuffer, &recvSize);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardTransmit/n");
exit(1);
}
//返回的数据,recvSize=2
sw1=recvBuffer[recvSize-2];
sw2=recvBuffer[recvSize-1];
    if ( sw1!=0x61 )
{
printf("Failed Command/n");
exit(1);
}
get_response[4]=sw2;
sendSize=5;
recvSize=sizeof(recvBuffer);
lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, get_response,
sendSize, NULL, recvBuffer, &recvSize);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardTransmit/n");
exit(1);
}
//返回的数据,recvSize=10
sw1=recvBuffer[recvSize-2];
sw2=recvBuffer[recvSize-1];
//data=recvBuffer[0]----recvBuffer[7]

3.5 断开与读卡器(智能卡)的连接
在与智能卡的数据交换完成后,可以使用函数ScardDisconnect()终止应用与智能卡之间的连接。
函数原型:LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition);
各个参数的含义:(1)hCard:输入类型;与智能卡连接的句柄。(2)dwDisposition:输入类型;断开连接时,对智能卡的操作,SCARD_LEAVE_CARD(不做任何操作)、SCARD_RESET_CARD(复位智能卡)、SCARD_UNPOWER_CARD(给智能卡掉电)、SCARD_EJECT_CARD(弹出智能卡)。
下面是断开与智能卡连接的代码:
lReturn = SCardDisconnect(hCardHandle[0], SCARD_LEAVE_CARD);
if ( lReturn != SCARD_S_SUCCESS )
{
printf("Failed SCardDisconnect/n");
exit(1);
}

3.6 释放资源管理上下文
    在应用程序终止前时,应该调用函数ScardReleaseContext()释放资源管理器的上下文。
函数原型:LONG SCardReleaseContext(SCARDCONTEXT hContext);
各个参数含义:(1)hContext:输入类型;ScardEstablishContext()建立的资源管理器上下文的句柄,不能为NULL。
下面是释放资源管理上下文的代码:
lReturn = SCardReleaseContext(hSC);
if ( lReturn!=SCARD_S_SUCCESS )
printf("Failed SCardReleaseContext/n");

4 小结
以上介绍的通过PC/SC来操作智能卡的流程,可以封装在一个类中。例如,我们可以设计一个类:
class CSmartReader
{
private:
SCARDCONTEXT    hSC;
LONG            lReturn;
char            mszReaders[1024];
LPTSTR          pReader, pReaderName[2];
DWORD           dwLen;
int             nReaders, nCurrentReader;
SCARDHANDLE     hCardHandle[2];
DWORD           dwAP;
public:
    CSmartReader(); //建立上下文、取读卡器列表
    ~CSmartReader(); //释放上下文
    void SetCurrentReader(int currentReader);
    int GetReaders(); //获得读卡器数目
    int ConnectReader(); //与当前读卡器建立连接
    int DisConnectReader(); //与当前读卡器断开连接
    int SendCommand(BYTE command[], int commandLength, BYTE result[], int *resultLength); //向读卡器发送命令,并接收返回的数据。返回值为sw
};
    这样,我们就可以方便地使用PC/SC接口了。

作者:蒋遂平。
联系方式:jiangsp@couragetech.com.cnjiang_sweeping@263.net
文章出处:DIY部落(http://www.diybl.com/course/3_program/c++/cppsl/200866/122898.html)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值