PCSC接口API说明.doc_第1页
PCSC接口API说明.doc_第2页
PCSC接口API说明.doc_第3页
PCSC接口API说明.doc_第4页
PCSC接口API说明.doc_第5页
免费预览已结束,剩余6页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

VC中PC/SC智能卡接口的编程摘要本文介绍了如何在VC中通过PC/SC接口实现对智能卡读写器的操作,并给出了详细的例子代码。 关键词 智能卡、PC/SC、智能卡读写器 1 引言 完整的智能卡应用系统由后台服务程序、主机或终端应用程序和智能卡等组成。其中,后台服务程序提供了支持智能卡的服务。例如,在一个电子付款系统中,后台服务程序可以提供到信用卡和帐户信息的访问;主机或终端应用程序一般存在于台式机或者终端、电子付款终端、手机或者一个安全子系统中,终端应用程序要处理用户、智能卡和后台服务程序之间的通讯;智能卡则存储用户的一些信息。 终端应用程序需要通过读卡器来访问智能卡,在一个系统中,通常存在多家厂商提供的读卡器,因此需要一个统一的读卡器设备驱动接口。 随着智能卡的广泛应用,为解决计算机与各种读卡器之间的互操作性问题,人们提出了PC/SC(Personal Computer/Smart Card)规范,PC/SC规范作为读卡器和卡与计算机之间有一个标准接口,实现不同生产商的卡和读卡器之间的互操作性,其独立于设备的 API使得应用程序开发人员不必考虑当前实现形式和将来实现形式之间的差异,并避免了由于基本硬件改变而引起的应用程序变更,从而降低了软件开发成本。Microsoft在其Platform SDK中实现了PC/SC,作为连接智能卡读卡器与计算机的一个标准模型,提供了独立于设备的 API,并与Windows平台集成。因此,我们可以用PC/SC接口来访问智能卡。 2 PC/SC概述 PC/SC接口包含30多个以Scard为前缀的函数,所有函数的原型都在winscard.h中声明,应用程序需要包含winscard.lib,所有函数的正常返回值都是SCARD_S_SUCCESS。在这30多个函数中,常用的函数只有几个,与智能卡的访问流程对应,下面将详细介绍这些常用函数。 3 PC/SC的使用 3.1建立资源管理器的上下文 函数ScardEstablishContext()用于建立将在其中进行设备数据库操作的资源管理器上下文(范围)。 函数原型:LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext); 各个参数的含义:(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(Failed SCardEstablishContextn);3.2 获得系统中安装的读卡器列表 函数ScardListReaders()可以列出系统中安装的读卡器的名字。 函数原型:LONG SCardListReaders(SCARDCONTEXT hContext, LPCTSTR mszGroups, LPTSTR mszReaders, LPDWORD pcchReaders); 各个参数的含义:(1)hContext:输入类型;ScardEstablishContext()建立的资源管理器上下文的句柄,不能为NULL。(2)mszGroups:输入类型;读卡器组名,为NULL时,表示列出所有读卡器。(3)mszReaders:输出类型;系统中安装的读卡器的名字,各个名字之间用0分隔,最后一个名字后面为两个连续的0。(4)pcchReaders:输入输出类型;mszReaders的长度。 系统中可能安装多个读卡器,因此,需要保存各个读卡器的名字,以便以后与需要的读卡器建立连接。 下面是获得系统中安装的读卡器列表的代码: charmszReaders1024; LPTSTRpReader, pReaderName2; DWORDdwLen=sizeof(mzsReaders); intnReaders=0; lReturn = SCardListReaders(hSC, NULL, (LPTSTR)mszReaders, &dwLen); if ( lReturn=SCARD_S_SUCCESS ) pReader = (LPTSTR)mszReaders; while (*pReader !=0 ) if ( nReaders0字节数据时,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 recvBuffer260; intsendSize, recvSize; BTYE sw1, sw2; BYTE select_mf=0xC0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00; sendSize=7; recvSize=sizeof(recvBuffer); lReturn = SCardTransmit(hCardHandle0, SCARD_PCI_T0, select_mf, sendSize, NULL, recvBuffer, &recvSize); if ( lReturn != SCARD_S_SUCCESS ) printf(Failed SCardTransmitn); exit(1); /返回的数据,recvSize=2 sw1=recvBufferrecvSize-2; sw2=recvBufferrecvSize-1; (b)从智能卡接收数据:为从智能卡接收n0字节数据,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(hCardHandle0, SCARD_PCI_T0, get_challenge, sendSize, NULL, recvBuffer, &recvSize); if ( lReturn != SCARD_S_SUCCESS ) printf(Failed SCardTransmitn); exit(1); /返回的数据, recvSize=10 sw1=recvBufferrecvSize-2; sw2=recvBufferrecvSize-1; /data=recvBuffer0-recvBuffer7 (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(hCardHandle0, SCARD_PCI_T0, set_flag, sendSize, NULL, recvBuffer, &recvSize); if ( lReturn != SCARD_S_SUCCESS ) printf(Failed SCardTransmitn); exit(1); /返回的数据,recvSize=2 sw1=recvBufferrecvSize-2; sw2=recvBufferrecvSize-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(hCardHandle0, SCARD_PCI_T0, internal_auth, sendSize, NULL, recvBuffer, &recvSize); if ( lReturn != SCARD_S_SUCCESS ) printf(Failed SCardTransmitn); exit(1); /返回的数据,recvSize=2 sw1=recvBufferrecvSize-2; sw2=recvBufferrecvSize-1; if ( sw1!=0x61 ) printf(Failed Commandn); exit(1); get_response4=sw2; sendSize=5; recvSize=sizeof(recvBuffer); lReturn = SCardTransmit(hCardHandle0, SCARD_PCI_T0, get_response, sendSize, NULL, recvBuffer, &recvSize); if ( lReturn != SCARD_S_SUCCESS ) printf(Failed SCardTransmitn); exit(1); /返回的数据,recvSize=10 sw1=recvBufferrecvSize-2; sw2=recvBufferrecvSize-1; /data=recvBuffer0-recvBuffer7 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(hCardHandle0, SCARD_LEAVE_CARD); if ( lReturn != SCARD_S_SUCCESS ) printf(Failed SCardDisconnectn); exit(1); 3.6 释放资源管理上下文 在应用程序终止前时,应该调用函数ScardReleaseContext()释放资源管理器的上下文。 函数原型:LONG SCardReleaseContext(SCARDCONTEXT hContext); 各个参数含义:(1)hContext:输入类型;ScardEstablishContext()建立的资源管理器上下文的句柄,不能为NULL。 下面是释放资源管理上下文的代码: lReturn = SCardReleaseContext(hSC); if ( lReturn!=SCARD_S_SUCCESS ) printf(Failed SCardReleaseContextn); 4 小结 以上介绍的通过PC/SC来操作智能卡的流程,可以封装在一个类中。例如,我们可以设计一个类: class CSmartReader private: SCARDCONTEXT hSC; LONGlReturn; Char mszReaders1024; LPTSTR pReader, pReaderName2; DWORD dwLen; Int nReaders, nCurrentReader; SCARDHANDLE hCardHandle2; 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接口了。 经典笑话有一天,神创造了一头牛。 神对牛说:“你要整天在田里替农夫耕田,供应牛奶给人类饮用。你要工作直至日落,而你只能吃草。我给你50年的寿命。” 牛抗议道:“我这么辛苦,还只能吃草,我只要20年寿命,余下的还给你。” 神答应了。 第二天,神创造了猴子。 神跟猴子说:“你要娱乐人类,令他们欢笑,你要表演翻斤斗,而你只能吃香蕉。我给你20年的寿命。”猴子抗议:“要引人发笑,表演杂技,还要翻斤斗,这么辛苦,我活10年好了。”神答应了。 第三天,神创造了狗。 神对狗说:“你要站在门口吠,吃主人吃剩的东西。我给你25年的寿命。”狗抗议道:“整天坐在门口吠,我要15年好了,余下的还给你。”神答应了。 第四天,神创造了人。 神对人说:“你只需要睡觉、吃东西和玩耍,不用做任何事情,只需要尽情地享受生命,我给你20年的寿命。”人抗议道:“这么好的生活只有20年,太短!”神没说话。 人对神说:“这样吧。牛还了30年给你,猴子还了10年,狗也还了10年,这些都给我好了,那我就能活到70岁。” 神答应了。 这就是为什么我们的头20年只需吃饭、睡觉和玩耍;之后的30年,我们像一条牛整天工作养家;接着的10年,我们退休了,不得不像只猴子表演杂耍来娱乐自己的孙儿;最后的10年,整天留在家里,像一条狗坐在门口看门怎么可以这么经典。一、IC卡与操作系统的整合前面所谈的标准及各种IC卡的规格,多半只论及IC卡或卡片阅读机。使用者要使用卡片阅读机时,必须安装厂商提供之驱动程序(drivers),开发应用程序。PC/SC(Personal Computer/Smart Card)支持ISO7816-4的基本指令集,界定了IC卡、卡片阅读机及操作系统的责任与分工,各家卡片阅读机厂商只要遵循PC/SC所定义之接口与方法开发驱动程序,即可结合到Windows或其它操作系统,应用程序只要透过单一标准接口与操作系统沟通,就可轻易操控各种卡片阅读机读写IC卡。Microsoft也在1997年底提供了Smart Card SDK给应用程序开发者,陆陆续续许多厂商的IC卡、卡片阅读机产品开始宣称其产品符合PC/SC规范,PC/SC俨然成为未来时势的潮流。应用程序与Smartcard之运作如下:1、应用程序使用PC/SC API 传送APDU指令传给操作系统。2、操作系统透过符合PC/SC规范之驱动程序将APDU指令传给卡片阅读机。3、卡片阅读机使用T=0或T=1之通讯协议将指令传送至Smartcard传输管理器。4、传输管理器再将APDU指令传送至Smartcard COS运作后回复处理结果。 二、PC/SC API for Visual C+1、i nclude winscard.h是Visual C+编译时所需要的参数及基本数据结构,请记得连结时加入winscard.lib,这样才能完成您的程序,此两文件在Visual C+ 的 include及library目录下可以找到,这种方式称为隐式调用DLL,程序好像与winscard.dll无关但实际上是透过DLL执行,.h档案内容大致如下:#define SCARD_STATE_UNAWARE 0x00000000#define SCARD_STATE_IGNORE 0x00000001#define SCARD_STATE_CHANGED 0x00000002#define SCARD_STATE_UNKNOWN 0x00000004#define SCARD_STATE_UNAVAILABLE 0x00000008WINSCARDDATA extern const SCARD_IO_REQUESTg_rgSCardT0Pci,g_rgSCardT1Pci,g_rgSCardRawPci;extern WINSCARDAPI LONG WINAPISCardEstablishContext(IN DWORD dwScope,IN LPCVOID pvReserved1,IN LPCVOID pvReserved2,OUT LPSCARDCONTEXT phContext);其实 PC/SC 不一定要在Windows 系统执行,以下定义为Linux系统所使用之PC/SC,请比较一下差异在哪里。typedef struct DWORD dwProtocol; /* SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1 */DWORD cbPciLength; /* Length of this structure - not used */ SCARD_IO_REQUEST;long SCardEstablishContext(unsigned long dwScope,const void *pvReserved1, const void *pvReserved2, long *phContext);以下说明一些重要函式之功能,细节部分请参考,附件二、PC/SC API Reference Document。2、ScardEstablishContextSCardEstablishContext 直觉的解释就是建立PC/SC在操作系统下的资源,所有PC/SC应用程序开始时一定要呼叫此函式建立资源后才能开始运作,范例如下。SCARDCONTEXT hContext;LONG rv;rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);3、ScardListReadersSCardListReaders 直觉的解释就是列出此台机器可用之Smartcard 卡片阅读机,比较特别的是第一次呼叫时并不知道机器有几台可用之卡片阅读机所以mszReaders先代入NULL,取得实际数量后再呼叫一次就可列出卡片阅读机名称,此技巧运用在很多API 呼叫中,第一次看到觉得怪怪,仔细想想此种呼叫方式真聪明。LPTSTR mszReaders;DWORD dwReaders;rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);mszReaders = (LPTSTR)malloc(sizeof(char)*dwReaders);rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);4、ScardConnectSCardConnect 直觉的解释就是建立Smartcard之联机,参数就是代入SCardListReaders 所列出之卡片阅读机名称;当联机完成后Smartcard会被重置,传回ATR讯息。SCARDHANDLE hCard;DWORD dwActiveProtocol;rv = SCardConnect(hContext, Reader X, SCARD_SHARE_SHARED,SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);5、ScardBeginTransaction当卡片阅读机以分享方式开启时,SCardBeginTransaction 就是宣告尔后将执行一连串的APDU指令以确保中间不被插断,当结束所有APDU指令后需呼叫ScardEndTransaction让其它联机继续运作;当卡片阅读机以独占方式开启时,可以不必执行此函式,直接执行SCardTransmit即可。rv = SCardBeginTransaction(hCard);6、ScardTransmitSCardTransmit是在呼叫SCardConnect函式后,传送APDU 指令到Smartcard的函

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论