常用的PC/SC接口函数

PC/SC规范是一个基于WINDOWS平台的一个标准用户接口(API),提供了一个从个人电脑(Personal Computer)到智能卡(SmartCard)的整合环境,PC/SC规范建立在工业标准-ISO7816和EMV标准的基础上,但它对底层的设备接口和独立于设备的应用API接口(例如用来允许多个应用共享使用系统同一张智能卡的资源管理器)做了更详尽的补充。PC/SC体系由三个主要部件组成,分别规定的操作系统厂商、读写器(IFD)厂商、智能卡(ICC)厂商的职责。PC/SC的API函数由操作系统提供,在微软公司提供的MSDN有相关帮助(路径\\MSDN\Platform
SDK\Security\Smart 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\nProtocoltype = T0");
		break;
	case SCARD_PROTOCOL_T1:
		sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardConnect ok\nProtocoltype = T1");
		break;
	default:
		sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardConnect ok\n%.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;
}

文/闫鑫原创转载请注明出处http://blog.csdn.net/yxstars/article/details/41522467

时间: 2024-11-07 21:01:09

常用的PC/SC接口函数的相关文章

Linux操作系统中的系统调用接口函数

在分析病毒样本时发现有些系统函数是必用,有些超常用,现在都列出来,希望和大家交流 转载请注明出处:http://blog.csdn.net/u010484477     O(∩_∩)O谢谢 进程控制 fork 创建一个新进程 clone 按指定条件创建子进程 execve 运行可执行文件 exit 中止进程 _exit 立即中止当前进程 getdtablesize 进程所能打开的最大文件数 getpgid 获取指定进程组标识号 setpgid 设置指定进程组标志号 getpgrp 获取当前进程组

自定义的常用文件与目录操作函数库

自定义的常用文件与目录操作函数库,在win和linux平台做了跨平台的处理.(跨平台的处理可以作为参考比较.在win下目录的符号可以是\或者/,但是在linux下只能是/.) 下面给出的是源文件,实现接口函数的代码.每个接口函数都有很详细的功能说明. /* 判断文件或目录是否存在 * 在操作系统中,目录也是一个文件,如果要判断一个目录是否存在则应当使用DirectoryExists, * 要判断一个文件是否存在且是一个归档文件则应当使用IsArchive. * @如果文件或目录存在则返回true

COM接口函数通用Hook方法

本文是我的本科学位论文, 今发表在此, 以示原创之据 第1章 绪论 研究背景 研究意义 相关技术简介 COM概述 COM内存模型描述及C语言和C++语言实现 调用约定 Hook API原理 Windows钩子原理及进程注入 开发及调试环境 第2章 问题抽象及关键技术研究 实验01:通过调试器查看C++类的虚函数表 实验02:通过函数指针调用C++虚函数 实验03:交换两个相同C++类的虚函数表 实验04-1:替换C++虚函数表中的虚函数(__thiscall)地址 实验04-2:替换C++虚函数

Oracle官网JNI简介和接口函数分析

第一章 概述 本章主要介绍JNI(Java Native Interface),JNI是一种本地编程接口.它允许运行在JAVA虚拟机中的JAVA代码和用其他编程语言,诸如C语言.C++.汇编,写的应用和库之间的交互操作. JNI的最大优势在于没有强加任何限制在JAVA虚拟机的下层实现上,因此,JAVA虚拟机供应商能够提供JNI的支持而不影响虚拟机的其他部分,程序员只需写出一个版本的本地应用和库,就可使之运行在一切支持JNI的JAVA虚拟机上. 本章包含了以下的要点: ? JNI概述 ? 目标 ?

ABAP语言常用的系统字段及函数

常用的系统变量如下: 1. SY-PAGNO当前页号 2. SY-DATUM当前时间 3. SY-LINSZ当前报表宽度 4. SY-LINCT当前报表长度 5. SPACE空字符 6. SY-SUBRC执行状态为0,表示成功. 7. SY-UNAME 用户名 8. SY-UZEIT当前时间 9. SY-TCODE当前的事务代码 10. SY-LSIND列表索引页 11. SY-LISTI上一个列表的索引 12. SY-LILLI绝对列表中选定行的行号 13. SY-CUROW屏幕上的行 14.

STM32 对内部FLASH读写接口函数

因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. 原理:先要把整页FLASH的内容搬到RAM中,然后在RAM中改动,然后擦除整页FLASH,再把改动后的内容写入原Flash页.下面程序调试通过. /******************************************************************************** Function Name  :

sysfs接口函数的建立_DEVICE_ATTR(转)

sysfs接口函数到建立_DEVICE_ATTR 最近在弄Sensor驱动,看过一个某厂家的成品驱动,里面实现的全都是sysfs接口,hal层利用sysfs生成的接口,对Sensor进行操作. 说道sysfs接口,就不得不提到函数宏 DEVICE_ATTR 原型是#define DEVICE_ATTR(_name, _mode, _show, _store) \ struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _sh

接口函数开发总结

复杂接口函数总结: 1.注意入参检查,出参和返回值要明确返回: 2.注意打印日志,进入函数 打印,异常打印,结束函数打印: 版权声明:本文为博主原创文章,未经博主允许不得转载.

php一些不是很常用的操作mysql的函数

<?php $con=mysql_connect('localhost','root','1234'); echo '<hr>1.mysql_client_encoding<br>'; echo mysql_client_encoding();//返回当前数据库的编码方式 // mysql_data_seek(result, row_number):移动数据内部指针到指定的行:result // 是mysql_query():获取的数据集 //mysql_list_dbs($