VC中PCSC操作读卡器.docx

上传人:b****5 文档编号:6787822 上传时间:2023-01-10 格式:DOCX 页数:7 大小:18.77KB
下载 相关 举报
VC中PCSC操作读卡器.docx_第1页
第1页 / 共7页
VC中PCSC操作读卡器.docx_第2页
第2页 / 共7页
VC中PCSC操作读卡器.docx_第3页
第3页 / 共7页
VC中PCSC操作读卡器.docx_第4页
第4页 / 共7页
VC中PCSC操作读卡器.docx_第5页
第5页 / 共7页
点击查看更多>>
下载资源
资源描述

VC中PCSC操作读卡器.docx

《VC中PCSC操作读卡器.docx》由会员分享,可在线阅读,更多相关《VC中PCSC操作读卡器.docx(7页珍藏版)》请在冰豆网上搜索。

VC中PCSC操作读卡器.docx

VC中PCSC操作读卡器

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

来源:

网络  作者:

蒋遂平  发布时间:

2010-12-1010:

53:

20  字体:

[大中小]

关键字:

智能卡  接口  读卡器          

摘   要:

终端应用程序需要通过读卡器来访问智能卡,在一个系统中,通常存在多家厂商提供的读卡器,因此需要一个统一的读卡器设备驱动接口。

    1引言

   完整的智能卡应用系统由后台服务程序、主机或终端应用程序和智能卡等组成,其中,后台服务程序提供了支持智能卡的服务。

例如,在一个电子付款系统中,后台服务程序可以提供到信用卡和帐户信息的访问;主机或终端应用程序一般存在于台式机或者终端、电子付款终端、手机或者一个安全子系统中,终端应用程序要处理用户、智能卡和后台服务程序之间的通讯;智能卡则存储用户的一些信息。

 

   终端应用程序需要通过读卡器来访问智能卡,在一个系统中,通常存在多家厂商提供的读卡器,因此需要一个统一的读卡器设备驱动接口。

 

   随着智能卡的广泛应用,为解决计算机与各种读卡器之间的互操作性问题,人们提出了PC/SC(PersonalComputer/SmartCard)规范,PC/SC规范作为读卡器和卡与计算机之间有一个标准接口,实现不同生产商的卡和读卡器之间的互操作性,其独立于设备的API使得应用程序开发人员不必考虑当前实现形式和将来实现形式之间的差异,并避免了由于基本硬件改变而引起的应用程序变更,从而降低了软件开发成本。

   Microsoft在其PlatformSDK中实现了PC/SC,作为连接智能卡读卡器与计算机的一个标准模型,提供了独立于设备的API,并与Windows平台集成。

因此,我们可以用PC/SC接口来访问智能卡。

   2PC/SC概述

   PC/SC接口包含30多个以Scard为前缀的函数,所有函数的原型都在winscard.h中声明,应用程序需要包含winscard.lib,所有函数的正常返回值都是SCARD_S_SUCCESS。

在这30多个函数中,常用的函数只有几个,与智能卡的访问流程(图2)对应,下面将详细介绍这些常用函数。

   3PC/SC的使用

   3.1建立资源管理器的上下文

   函数ScardEstablishContext()用于建立将在其中进行设备数据库操作的资源管理器上下文(范围)。

 

   函数原型:

LONGSCardEstablishContext(DWORDdwScope,LPCVOIDpvReserved1,LPCVOIDpvReserved2,LPSCARDCONTEXTphContext);

各个参数的含义:

(1)dwScope:

输入类型;表示资源管理器上下文范围,取值为:

SCARD_SCOPE_USER(在用户域中完成设备数据库操作)、SCARD_SCOPE_SYSTEM(在系统域中完成设备数据库操作)。

要求应用程序具有相应的操作权限。

(2)pvReserved1:

输入类型;保留,必须为NULL。

(3)pvReserved2:

输入类型;保留,必须为NULL。

(4)phContext:

输出类型;建立的资源管理器上下文的句柄。

 

   下面是建立资源管理器上下文的代码:

   SCARDCONTEXThSC; 

   LONGlReturn; 

   lReturn=SCardEstablishContext(SCARD_SCOPE_USER,NULL,NULL,&hSC); 

   if(lReturn!

=SCARD_S_SUCCESS) 

   printf("FailedSCardEstablishContext\n");

   3.2获得系统中安装的读卡器列表

   函数ScardListReaders()可以列出系统中安装的读卡器的名字。

 

   函数原型:

LONGSCardListReaders(SCARDCONTEXThContext,LPCTSTRmszGroups,LPTSTRmszReaders,LPDWORDpcchReaders);

各个参数的含义:

(1)hContext:

输入类型;ScardEstablishContext()建立的资源管理器上下文的句柄,不能为NULL。

(2)mszGroups:

输入类型;读卡器组名,为NULL时,表示列出所有读卡器。

(3)mszReaders:

输出类型;系统中安装的读卡器的名字,各个名字之间用’\0’分隔,最后一个名字后面为两个连续的’\0’。

(4)pcchReaders:

输入输出类型;mszReaders的长度。

   系统中可能安装多个读卡器,因此,需要保存各个读卡器的名字,以便以后与需要的读卡器建立连接。

   下面是获得系统中安装的读卡器列表的代码:

   charmszReaders[1024];

   LPTSTRpReader,pReaderName[2]; 

   DWORDdwLen=sizeof(mzsReaders); 

   intnReaders=0; 

   lReturn=SCardListReaders(hSC,NULL,(LPTSTR)mszReaders,&dwLen); 

   if(lReturn==SCARD_S_SUCCESS) 

   { 

   pReader=(LPTSTR)pmszReaders; 

   while(*pReader!

='\0') 

   { 

   if(nReaders<2)//使用系统中前2个读卡器 

   pReaderName[nReaders++]=pReader; 

   printf("Reader:

%S\n",pReader); 

   //下一个读卡器名 

   pReader=pReader+strlen(pReader)+1; 

   } 

   }

   3.3与读卡器(智能卡)连接 

   函数ScardConnect()在应用程序与读卡器上的智能卡之间建立一个连接。

    函数原型:

LONGSCardConnect(SCARDCONTEXThContext,LPCTSTRszReader,DWORDdwShareMode,DWORDdwPreferredProtocols,LPSCARDHANDLEphCard,LPDWORDpdwActiveProtocol);

   各个参数的含义:

(1)hContext:

输入类型;ScardEstablishContext()建立的资源管理器上下文的句柄。

(2)szReader:

输入类型;包含智能卡的读卡器名称(读卡器名称由ScardListReaders()给出)。

(3)dwShareMode:

输入类型;应用程序对智能卡的操作方式,SCARD_SHARE_SHARED(多个应用共享同一个智能卡)、SCARD_SHARE_EXCLUSIVE(应用独占智能卡)、SCARD_SHARE_DIRECT(应用将智能卡作为私有用途,直接操纵智能卡,不允许其它应用访问智能卡)。

(4)dwPreferredProtocols:

输入类型;连接使用的协议,SCARD_PROTOCOL_T0(使用T=0协议)、SCARD_PROTOCOL_T1(使用T=1协议)。

(5)phCard:

输出类型;与智能卡连接的句柄。

(6)PdwActiveProtocol:

输出类型;实际使用的协议。

   下面是与智能卡建立连接的代码:

   SCARDHANDLEhCardHandle[2]; 

   DWORDdwAP; 

   lReturn=SCardConnect(hContext,pReaderName[0],SCARD_SHARE_SHARED, 

   SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1,&hCardHandle[0],&dwAP); 

   if(lReturn!

=SCARD_S_SUCCESS) 

   { 

   printf("FailedSCardConnect\n"); 

   exit

(1); 

   }

   与智能卡建立连接后,就可以向智能卡发送指令,与其交换数据了。

   3.4向智能卡发送指令

   函数ScardTransmit()向智能卡发送指令,并接受返回的数据。

   函数原型:

LONGSCardTransmit(SCARDHANDLEhCard,LPCSCARD_I0_REQUESTpioSendPci,LPCBYTEpbSendBuffer,DWORDcbSendLength,LPSCARD_IO_REQUESTpioRecvPci,LPBYTEpbRecvBuffer,LPDWORDpcbRecvLength);

   各个参数的含义:

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

 

   BYTErecvBuffer[260]; 

   intsendSize,recvSize; 

   BTYEsw1,sw2; 

   BYTEselect_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("FailedSCardTransmit\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。

 

   BYTEget_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("FailedSCardTransmit\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。

   BYTEset_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("FailedSCardTransmit\n"); 

   exit

(1); 

   } 

   //返回的数据,recvSize=2 

   sw1=recvBuffer[recvSize-2]; 

   sw2=recvBuffer[recvSize-1];

   (d)向智能卡发送具有双向数据交换的命令:

T=0协议中,应用程序不能同时向智能卡发送数据,并从智能卡接收数据,即发送到智能卡的指令中,不能同时有Lc和Le。

这只能分两步实现:

向智能卡发送数据,接收智能卡返回的状态码,其中,SW2是智能卡将要返回的数据字节数目;从智能卡接收数据(指令为0x00、0xC0、0x00、0x00、Le)。

   BYTEget_response={0x00,0xc0,0x00,0x00,0x00}; 

   BYTEinternal_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("FailedSCardTransmit\n"); 

   exit

(1); 

   } 

   //返回的数据,recvSize=2 

   sw1=recvBuffer[recvSize-2]; 

   sw2=recvBuffer[recvSize-1]; 

   if(sw1!

=0x61) 

   { 

   printf("FailedCommand\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("FailedSCardTransmit\n"); 

   exit

(1); 

   } 

   //返回的数据,recvSize=10 

   sw1=recvBuffer[recvSize-2]; 

   sw2=recvBuffer[recvSize-1]; 

   //data=recvBuffer[0]----recvBuffer[7]

   3.5断开与读卡器(智能卡)的连接

   在与智能卡的数据交换完成后,可以使用函数ScardDisconnect()终止应用与智能卡之间的连接。

 

   函数原型:

LONGSCardDisconnect(SCARDHANDLEhCard,DWORDdwDisposition); 

   各个参数的含义:

(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("FailedSCardDisconnect\n"); 

   exit

(1); 

   }

   3.6释放资源管理上下文

   在应用程序终止前时,应该调用函数ScardReleaseContext()释放资源管理器的上下文。

 

   函数原型:

LONGSCardReleaseContext(SCARDCONTEXThContext); 

   各个参数含义:

(1)hContext:

输入类型;ScardEstablishContext()建立的资源管理器上下文的句柄,不能为NULL。

 

   下面是释放资源管理上下文的代码:

 

   lReturn=SCardReleaseContext(hSC); 

   if(lReturn!

=SCARD_S_SUCCESS) 

   printf("FailedSCardReleaseContext\n");

   4小结

   以上介绍的通过PC/SC来操作智能卡的流程,可以封装在一个类中。

例如,我们可以设计一个类:

 

   classCSmartReader 

   { 

   private:

 

   SCARDCONTEXThSC; 

   LONGlReturn; 

   charmszReaders[1024]; 

   LPTSTRpReader,pReaderName[2]; 

   DWORDdwLen; 

   intnReaders,nCurrentReader; 

   SCARDHANDLEhCardHandle[2]; 

   DWORDdwAP; 

   public:

 

   CSmartReader();//建立上下文、取读卡器列表 

   ~CSmartReader();//释放上下文 

   voidSetCurrentReader(intcurrentReader); 

   intGetReaders();//获得读卡器数目 

   intConnectReader();//与当前读卡器建立连接 

   intDisConnectReader();//与当前读卡器断开连接 

   intSendCommand(BYTEcommand[],intcommandLength,BYTEresult[],int*resultLength);//向读卡器发送命令,并接收返回的数据。

返回值为sw 

   };

   这样,我们就可以方便地使用PC/SC接口了。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1