zoukankan      html  css  js  c++  java
  • 常用的PC/SC接口函数

       PC/SC规范是一个基于WINDOWS平台的一个标准用户接口(API),提供了一个从个人电脑(Personal Computer)到智能卡(SmartCard)的整合环境,PC/SC规范建立在工业标准-ISO7816和EMV标准的基础上,但它对底层的设备接口和独立于设备的应用API接口(例如用来允许多个应用共享使用系统同一张智能卡的资源管理器)做了更详尽的补充。PC/SC体系由三个主要部件组成,分别规定的操作系统厂商、读写器(IFD)厂商、智能卡(ICC)厂商的职责。PC/SC的API函数由操作系统提供,在微软公司提供的MSDN有相关帮助(路径\MSDNPlatform SDKSecuritySmart Card),函数声明在Winscard.h中。
       由于经常使用,所以我将PC/SC几个常用函数进行封装,方便调用。


    1.载入头文件

    #include <WinSCard.h>
    #pragma comment(lib,"WinSCard.lib")
    
    #define NUMBER_OF_READERS	4
    #define INDEX_LENGTH	    2
    #define KEY_LENGTH			32
    #define NAME_LENGTH			100
    #define MAX_INPUT			1024
    #define MAX_OUTPUT			4000
    #define MAX_RESPONSE		2000


    2 建立资源管理器的上下文,并获得读卡器列表

    /************************************************************************/
    /* 
       与读卡器建立连接
       返回:连接失败0,否则返回读卡器列表数目
    */
    /************************************************************************/
    
    extern "C" __declspec(dllexport) int CardReaderInit(
    	char* messageBuffer,                   //_out_ 返回错误信息
    	char(*ReaderName)[NAME_LENGTH],		   //_out_ 返回读卡器列表信息
    	SCARDCONTEXT* ContextHandle			   //_out_ 返回读卡器句柄
    	)
    {
    	// extra initialization 
    	//char	ReaderName[NUMBER_OF_READERS][NAME_LENGTH];
    	memset(messageBuffer, 0, NAME_LENGTH);
    	memset(ReaderName[0], 0, NAME_LENGTH);
    	memset(ReaderName[1], 0, NAME_LENGTH);
    	memset(ReaderName[2], 0, NAME_LENGTH);
    	memset(ReaderName[3], 0, NAME_LENGTH);
    
    	PBYTE pOutBuffer = (PBYTE)malloc(MAX_OUTPUT);  
    	int OutBufferLine = 0;
    
    	PBYTE pResponseBuffer = (PBYTE)malloc(MAX_RESPONSE);
    
    	memset(pResponseBuffer, 0x00, MAX_RESPONSE);
    
    	//
    	//	Open a context which communication to the Resource Manager
    	//
    	long ret = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, ContextHandle);
    
    	if (ret != SCARD_S_SUCCESS) {
    		sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardEstablishContext returned 0x%X error code.", ret);
    		return false;
    	}
    
    	int ReaderCount = 0;
    	unsigned long ResponseLength = MAX_RESPONSE;
    
    	ret = SCardListReaders(*ContextHandle, 0, (char *)pResponseBuffer, &ResponseLength);
    
    	if (ret != SCARD_S_SUCCESS) {
    		sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardListReaders returned 0x%X error code.", ret);
    		return false;
    	}
    	else {
    		unsigned int		StringLen = 0;
    		SCARDHANDLE CardHandle = NULL;
    		while (ResponseLength > StringLen + 1) {
    			strcpy(ReaderName[ReaderCount], (LPCTSTR)pResponseBuffer + StringLen);
    			DWORD	ActiveProtocol = 0;
    			ret = SCardConnect(*ContextHandle, ReaderName[ReaderCount], SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &CardHandle, &ActiveProtocol);
    			if (ret != SCARD_E_UNKNOWN_READER)
    				ReaderCount++;
    			if (ret == SCARD_S_SUCCESS)
    				SCardDisconnect(CardHandle, SCARD_EJECT_CARD);
    			StringLen += strlen((LPCTSTR)pResponseBuffer + StringLen + 1);
    			StringLen += 2;
    		}
    	}
    
    	if (ReaderCount == 0) {
    		sprintf_s(messageBuffer, NAME_LENGTH, "No driver is available for use with the resource manager!");
    		return false;
    	}
    
    	return ReaderCount;
    }


    3 读卡器与智能卡连接


    /************************************************************************/
    /*
    	与卡片建立连接
    	返回:连接失败0,否则返回1
    */
    /************************************************************************/
    extern "C" __declspec(dllexport) bool CardConnect(
    	SCARDCONTEXT ContextHandle,           //_in_  传入读卡器句柄			  
    	char(*ReaderName)[NAME_LENGTH],		  //_in_  传入读卡器列表信息(二维数组)
    	int actName, 						  //_in_  传入选择的列表序号
    	SCARDHANDLE *CardHandle,              //_out_ 返回卡片句柄
    	long* ProtocolType,					  //_out_ 返回卡片协议
    	char* messageBuffer					  //_out_ 返回错误信息
    	)
    {      // <span style="font-family: 'Courier New';font-size:14px;">ScardTransmit  </span><a target=_blank target="_blank" href="http://baike.baidu.com/view/8257336.htm" style="font-family: 'Courier New';font-size:14px;">http://baike.baidu.com/view/8257336.htm</a>
    	DWORD	ActiveProtocol = 0;
    	*ProtocolType = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
    	long ret = SCardConnect(ContextHandle, ReaderName[actName], SCARD_SHARE_EXCLUSIVE, *ProtocolType, CardHandle, &ActiveProtocol);
    
    	memset(messageBuffer, 0x00, sizeof(messageBuffer) / sizeof(char));
    	if (ret != SCARD_S_SUCCESS){
    		GetErrorCode(ret, messageBuffer);
    		return false;
    	}
    
    	*ProtocolType = ActiveProtocol;
    
    	switch (*ProtocolType) {
    	case SCARD_PROTOCOL_T0:
    		sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardConnect ok
    Protocoltype = T0");
    		break;
    	case SCARD_PROTOCOL_T1:
    		sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardConnect ok
    Protocoltype = T1");
    		break;
    	default:
    		sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardConnect ok
    %.8x", ActiveProtocol);
    		break;
    	}
    
    	return true;
    }
    


    4 断开与读卡器的连接

    /************************************************************************/
    /*
    	与卡片断开连接
    	返回:连接成功0.否则错误http://msdn.microsoft.com/en-us/library/windows/desktop/aa374738(v=vs.85).aspx
    */
    /************************************************************************/
    extern "C" __declspec(dllexport) long CardDisconnect(
    	SCARDHANDLE CardHandle               //_in_ 传入卡片句柄
    	)
    {
    	return SCardDisconnect(CardHandle, SCARD_EJECT_CARD);
    }

    5 释放资源管理上下文

    /************************************************************************/
    /*
    	与读卡器断开连接
    	返回:连接成功0.否则错误http://msdn.microsoft.com/en-us/library/windows/desktop/aa374738(v=vs.85).aspx
    */
    /************************************************************************/
    extern "C" __declspec(dllexport) long CardReaderDisconnect(
    	SCARDCONTEXT ContextHandle           //_in_ 传入读卡器句柄
    	)
    {
    	return SCardReleaseContext(ContextHandle);
    }

    6 向智能卡发送指令

    int Transmit(byte* cmd,
    	long ProtocolType, 
    	SCARDHANDLE CardHandle
    	)
    int Transmit(byte* cmd, long ProtocolType, SCARDHANDLE CardHandle)
    {
    	char	mhstr[MAX_INPUT];
    	char	buf[MAX_INPUT / 2];
    	PBYTE	pInBuffer;
    	PBYTE   pResponseBuffer;
    	memset(mhstr, 0, MAX_INPUT);
    
    	sprintf_s(mhstr, MAX_INPUT, "%s", cmd);
    	int bufferLen = AToHex((char *)&mhstr, (BYTE *)&buf);
    	if (!bufferLen)  {
    		return false;
    	}
    
    	SCARD_IO_REQUEST IO_Request;
    	IO_Request.dwProtocol = ProtocolType;
    	IO_Request.cbPciLength = (DWORD) sizeof(SCARD_IO_REQUEST);
    
    	pInBuffer = (PBYTE)malloc(MAX_INPUT);
    	memcpy(pInBuffer, buf, bufferLen);
    	pResponseBuffer = (PBYTE)malloc(MAX_INPUT);
    	memset(pResponseBuffer, 0x00, bufferLen);
    
    	unsigned long ResponseLength = MAX_RESPONSE;
    	
    	long ret = SCardTransmit(CardHandle, &IO_Request, pInBuffer, bufferLen, 0, pResponseBuffer, &ResponseLength);
    
    	if (ret != SCARD_S_SUCCESS){
    		GetErrorCode(ret, (char*)cmd);
    		return false;
    	}
    
    	DataX::AscToHex(pResponseBuffer, ResponseLength, cmd);
    	cmd[ResponseLength * 2] = 0x00;
    	return ResponseLength * 2;
    }

    7 获取错误信息

    void GetErrorCode(long ret, char* messageBuffer)
    {
    	switch (ret) {
    	case SCARD_E_CANCELLED:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The action was cancelled by an SCardCancel request.");
    		break;
    	case SCARD_E_CANT_DISPOSE:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The system could not dispose of the media in the requested manner.");
    		break;
    	case SCARD_E_CARD_UNSUPPORTED:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The smart card does not meet minimal requirements for support.");
    		break;
    	case SCARD_E_DUPLICATE_READER:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The reader driver didn't produce a unique reader name.");
    		break;
    	case SCARD_E_INSUFFICIENT_BUFFER:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The data buffer to receive returned data is too small for the returned data.");
    		break;
    	case SCARD_E_INVALID_ATR:
    		sprintf_s(messageBuffer, NAME_LENGTH, "An ATR obtained from the registry is not a valid ATR string.");
    		break;
    	case SCARD_E_INVALID_HANDLE:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The supplied handle was invalid.");
    		break;
    	case SCARD_E_INVALID_PARAMETER:
    		sprintf_s(messageBuffer, NAME_LENGTH, "One or more of the supplied parameters could not be properly interpreted.");
    		break;
    	case SCARD_E_INVALID_TARGET:
    		sprintf_s(messageBuffer, NAME_LENGTH, "Registry startup information is missing or invalid.");
    		break;
    	case SCARD_E_INVALID_VALUE:
    		sprintf_s(messageBuffer, NAME_LENGTH, "One or more of the supplied parameters?values could not be properly interpreted.");
    		break;
    	case SCARD_E_NOT_READY:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The reader or card is not ready to accept commands.");
    		break;
    	case SCARD_E_NOT_TRANSACTED:
    		sprintf_s(messageBuffer, NAME_LENGTH, "An attempt was made to end a non-existent transaction.");
    		break;
    	case SCARD_E_NO_MEMORY:
    		sprintf_s(messageBuffer, NAME_LENGTH, "Not enough memory available to complete this command.");
    		break;
    	case SCARD_E_NO_SERVICE:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The Smart card resource manager is not running.");
    		break;
    	case SCARD_E_NO_SMARTCARD:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The operation requires a smart card but no smart card is currently in the device.");
    		break;
    	case SCARD_E_PCI_TOO_SMALL:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The PCI Receive buffer was too small.");
    		break;
    	case SCARD_E_PROTO_MISMATCH:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The requested protocols are incompatible with the protocol currently in use with the card.");
    		break;
    	case SCARD_E_READER_UNAVAILABLE:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The specified reader is not currently available for use.");
    		break;
    	case SCARD_E_READER_UNSUPPORTED:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The reader driver does not meet minimal requirements for support.");
    		break;
    	case SCARD_E_SERVICE_STOPPED:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The Smart card resource manager has shut down.");
    		break;
    	case SCARD_E_SHARING_VIOLATION:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The card cannot be accessed because of other connections outstanding.");
    		break;
    	case SCARD_E_SYSTEM_CANCELLED:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The action was cancelled by the system presumably to log off or shut down.");
    		break;
    	case SCARD_E_TIMEOUT:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The user-specified timeout value has expired.");
    		break;
    	case SCARD_E_UNKNOWN_CARD:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The specified card name is not recognized.");
    		break;
    	case SCARD_E_UNKNOWN_READER:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The specified reader name is not recognized.");
    		break;
    	case SCARD_F_COMM_ERROR:
    		sprintf_s(messageBuffer, NAME_LENGTH, "An internal communications error has been detected.");
    		break;
    	case SCARD_F_INTERNAL_ERROR:
    		sprintf_s(messageBuffer, NAME_LENGTH, "An internal consistency check failed.");
    		break;
    	case SCARD_F_UNKNOWN_ERROR:
    		sprintf_s(messageBuffer, NAME_LENGTH, "An internal error has been detected but the source is unknown.");
    		break;
    	case SCARD_F_WAITED_TOO_LONG:
    		sprintf_s(messageBuffer, NAME_LENGTH, "An internal consistency timer has expired.");
    		break;
    	case SCARD_S_SUCCESS:
    		sprintf_s(messageBuffer, NAME_LENGTH, "OK");
    		break;
    	case SCARD_W_REMOVED_CARD:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The card has been removed so that further communication is not possible.");
    		break;
    	case SCARD_W_RESET_CARD:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The card has been reset so any shared state information is invalid.");
    		break;
    	case SCARD_W_UNPOWERED_CARD:
    		sprintf_s(messageBuffer, NAME_LENGTH, "Power has been removed from the card so that further communication is not possible.");
    		break;
    	case SCARD_W_UNRESPONSIVE_CARD:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The card is not responding to a reset.");
    		break;
    	case SCARD_W_UNSUPPORTED_CARD:
    		sprintf_s(messageBuffer, NAME_LENGTH, "The reader cannot communicate with the card due to ATR configuration conflicts.");
    		break;
    	default:
    		sprintf_s(messageBuffer, NAME_LENGTH, "Function returned unknown error code: #%ld", ret);
    		break;
    	}
    }

    8 复位卡片

    bool CpuReset(SCARDHANDLE CardHandle, byte* atr)
    {
    	CHAR            szReader[200];
    	DWORD           cch = 200;
    	BYTE            bAttr[32];
    	DWORD           cByte = 32;
    	DWORD           dwState, dwProtocol;
    	LONG            lReturn;
    	string			AtrValue;
    
    	memset(bAttr, 0, 32);
    	memset(szReader, 0, 200);
    
    	// Determine the status.
    	// hCardHandle was set by an earlier call to SCardConnect.
    	lReturn = SCardStatus(CardHandle,
    		szReader,
    		&cch,
    		&dwState,
    		&dwProtocol,
    		(LPBYTE)&bAttr,
    		&cByte);
    
    	if (SCARD_S_SUCCESS != lReturn)
    		return FALSE;
    	
    	DataX::AscToHex(bAttr, cByte, atr);
    	return TRUE;
    }


    文/yanxin8原创,获取更多信息请移步至yanxin8.com...


  • 相关阅读:
    【Leetcode】23. Merge k Sorted Lists
    【Leetcode】109. Convert Sorted List to Binary Search Tree
    【Leetcode】142.Linked List Cycle II
    【Leetcode】143. Reorder List
    【Leetcode】147. Insertion Sort List
    【Leetcode】86. Partition List
    jenkins 配置安全邮件
    python 发送安全邮件
    phpstorm 同步远程服务器代码
    phpUnit 断言
  • 原文地址:https://www.cnblogs.com/iplus/p/4467093.html
Copyright © 2011-2022 走看看