在公交车上采用,刷卡收费的系统,的相关的技术资料
请大家提供
请大家提供
解决方案 »
- 如何把非模态对话框临时转为模态对话框然后再转化回来?
- Button按钮如何实行可以让用户任意拖动??????????????????????????????????????????
- 初学MFC,请问MFC中可以使用C的库文件吗?
- 请教,关于记事本问题,???急死了,????/
- 問一個關于硬件方面的問題?
- 编程爱好者请进
- 小弟请教 请写下你的答案,非常感谢!!
- 一个通过Socks5代理发送UDP数据的类
- 在线等待一个小问题,请大家一定帮帮忙。
- 用了C++MFC一段时间了,现在发现WPF做界面比较好,换C#是否容易上手?有没有必要?
- 求救各位兄弟:如何在DirectShow中使用DivX5.0.5?
- 怎样在控件中使用控件
我也不知道,有的给我一份。
[email protected]
明华澳汉 http://www.mwcard.com/gb/Service/Download.htm
深圳市世礴创科技有限公司 http://www.szbc.net/support.htm
北京佳联特技术有限责任公司 http://www.cntchina.com/index.htm
我认为看程序还不如自己写程序!”呵呵!......
庆崽同志,没有IC读写器的厂家给你提供的资料你的程序又从何处下手啊!!!
难道写出程序后自己做一个适合你自己的程序的读写器和适合你的读写器用的射频IC卡
对了,现在的射频IC都是有CPU的,主要用于数据的加密. 别小看了一张卡片.
非接触式IC卡性能简介(M1)一、 主要指标
 容量为8K位EEPROM
 分为16个扇区,每个扇区为4块,每块16个字节,以块为存取单位
 每个扇区有独立的一组密码及访问控制
 每张卡有唯一序列号,为32位
 具有防冲突机制,支持多卡操作
 无电源,自带天线,内含加密控制逻辑和通讯逻辑电路
 数据保存期为10年,可改写10万次,读无限次
 工作温度:-20℃~50℃(温度为90%)
 工作频率:13.56MHZ
 通信速率:106KBPS
 读写距离:10mm以内(与读写器有关)二、 存储结构
1、 M1卡分为16个扇区,每个扇区由4块(块0、块1、块2、块3)组成,(我们也将16个扇区的64个块按绝对地址编号为0~63,存贮结构如下图所示:
块0 数据块 0
扇区0 块1 数据块 1
块2 数据块 2
块3 密码A 存取控制 密码B 控制块 3
块0 数据块 4
扇区1 块1 数据块 5
块2 数据块 6
块3 密码A 存取控制 密码B 控制块 7
∶
∶
∶
0 数据块 60
扇区15 1 数据块 61
2 数据块 62
3 密码A 存取控制 密码B 控制块 632、 第0扇区的块0(即绝对地址0块),它用于存放厂商代码,已经固化,不可更改。
3、 每个扇区的块0、块1、块2为数据块,可用于存贮数据。
数据块可作两种应用:
★ 用作一般的数据保存,可以进行读、写操作。
★ 用作数据值,可以进行初始化值、加值、减值、读值操作。
4、 每个扇区的块3为控制块,包括了密码A、存取控制、密码B。具体结构如下:
密码A(6字节) 存取控制(4字节) 密码B(6字节) 5、 每个扇区的密码和存取控制都是独立的,可以根据实际需要设定各自的密码及存取控制。存取控制为4个字节,共32位,扇区中的每个块(包括数据块和控制块)的存取条件是由密码和存取控制共同决定的,在存取控制中每个块都有相应的三个控制位,定义如下:
块0: C10 C20 C30
块1: C11 C21 C31
块2: C12 C22 C32
块3: C13 C23 C33 三个控制位以正和反两种形式存在于存取控制字节中,决定了该块的访问权限(如
进行减值操作必须验证KEY A,进行加值操作必须验证KEY B,等等)。三个控制
位在存取控制字节中的位置,以块0为例:
对块0的控制:
bit 7 6 5 4 3 2 1 0
字节6 C20_b C10_b
字节7 C10 C30_b
字节8 C30 C20
字节9
( 注: C10_b表示C10取反 ) 存取控制(4字节,其中字节9为备用字节)结构如下所示:
bit 7 6 5 4 3 2 1 0
字节6 C23_b C22_b C21_b C20_b C13_b C12_b C11_b C10_b
字节7 C13 C12 C11 C10 C33_b C32_b C31_b C30_b
字节8 C33 C32 C31 C30 C23 C22 C21 C20
字节9
( 注: _b表示取反 ) 6、数据块(块0、块1、块2)的存取控制如下: 控制位(X=0.1.2)
访 问 条 件 (对数据块 0、1、2)
C1X C2X C3X Read Write Increment Decrement, transfer,
Restore
0 0 0 KeyA|B KeyA|B KeyA|B KeyA|B
0 1 0 KeyA|B Never Never Never
1 0 0 KeyA|B KeyB Never Never
1 1 0 KeyA|B KeyB KeyB KeyA|B
0 0 1 KeyA|B Never Never KeyA|B
0 1 1 KeyB KeyB Never Never
1 0 1 KeyB Never Never Never
1 1 1 Never Never Never Never
(KeyA|B 表示密码A或密码B,Never表示任何条件下不能实现) 例如:当块0的存取控制位C10 C20 C30=1 0 0时,验证密码A或密码B正确后可读;
验证密码B正确后可写;不能进行加值、减值操作。 7、控制块块3的存取控制与数据块(块0、1、2)不同,它的存取控制如下: 密码A 存取控制 密码B
C13 C23 C33 Read Write Read Write Read Write
0 0 0 Never KeyA|B KeyA|B Never KeyA|B KeyA|B
0 1 0 Never Never KeyA|B Never KeyA|B Never
1 0 0 Never KeyB KeyA|B Never Never KeyB
1 1 0 Never Never KeyA|B Never Never Never
0 0 1 Never KeyA|B KeyA|B KeyA|B KeyA|B KeyA|B
0 1 1 Never KeyB KeyA|B KeyB Never KeyB
1 0 1 Never Never KeyA|B KeyB Never Never
1 1 1 Never Never KeyA|B Never Never Never
例如:当块3的存取控制位C13 C23 C33=1 0 0时,表示:
密码A:不可读,验证KEYA或KEYB正确后,可写(更改)。
存取控制:验证KEYA或KEYB正确后,可读、可写。
密码B:验证KEYA或KEYB正确后,可读、可写。三、 工作原理
卡片的电气部分只由一个天线和ASIC组成。
天线:卡片的天线是只有几组绕线的线圈,很适于封装到IS0卡片中。
ASIC:卡片的ASIC由一个高速(106KB波特率)的RF接口,一个控制单元和一个
8K位EEPROM组成。
工作原理:读写器向M1卡发一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其频率与读写器发射的频率相同,在电磁波的激励下,LC谐振电路产生共振,从而使电容内有了电荷,在这个电容的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内储存,当所积累的电荷达到2V时,此电容可做为电源为其它电路提供工作电压,将卡内数据发射出去或接取读写器的数据。四、 M1射频卡与读写器的通讯
改变扇区 不改变扇区
复位应答(Answer to request)
M1射频卡的通讯协议和通讯波特率是定义好的,当有卡片进入读写器的操作范围时,读写器以特定的协议与它通讯,从而确定该卡是否为M1射频卡,即验证卡片的卡型。防冲突机制 (Anticollision Loop)
当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作,未选中的则处于空闲模式等待下一次选卡,该过程会返回被选卡的序列号。选择卡片(Select Tag)
选择被选中的卡的序列号,并同时返回卡的容量代码。三次互相确认(3 Pass Authentication)
选定要处理的卡片之后,读写器就确定要访问的扇区号,并对该扇区密码进行密码校验,在三次相互认证之后就可以通过加密流进行通讯。(在选择另一扇区时,则必须进行另一扇区密码校验。)对数据块的操作
读 (Read):读一个块;
写 (Write):写一个块;
加(Increment):对数值块进行加值;
减(Decrement):对数值块进行减值;
存储(Restore):将块中的内容存到数据寄存器中;
传输(Transfer):将数据寄存器中的内容写入块中;
中止(Halt):将卡置于暂停工作状态;非接触式IC卡性能介绍(ML)
一、 概述
MIFARE LIGHT 卡是一种小容量卡,共384位,适合于一卡一用。
二、 主要指标
 容量为384位
 16位的数值计算
 128位的数据区(如果不用钱包文件可达192位)
 用户可自定义控制权限
 唯一的32位序列号
 工作频率:13.56MHZ
 通信速率:106KB波特率
 防 冲 突:同一时间可处理多张卡
 读写距离:在10cm以内(与天线有关)
 卡内无需电源
三、 存储结构
ML卡共384位,分为12页,每页为4个字节。存储结构如下:
页号 字节0 字节1 字节2 字节3
0 SerNr(0) SerNr(1) SerNr(2) SerNr(3) Block 0
1 SerNr(4) Size Code Type(0) Type(1)
2 Data(0) Data(1) Data(2) Data(3) Data1
3 Data(4) Data(5) Data(6) Data(7)
4 Value(0) Value(1) Value_b(0) Value_b(1) Value
5 Value(0) Value(1) Value_b(0) Value_b(1)
6 KeyA(0) KeyA(1) KeyA(2) KeyA(3) KeyA
7 KeyA(4) KeyA(5) AC-A AC-A_b
8 KeyB(0) KeyB(1) KeyB(2) KeyB(3) KeyB
9 KeyB(4) KeyB(5) AC-B AC-B_b
A Data(0) Data(1) Data(2) Data(3) Data2
B Data(4) Data(5) Data(6) Data(7)
( 注:_b表示取反 )
1) 第0、1页存放着卡的序列号等信息,只可读。
2) 第2、3页及A、B两页数据块,可存贮一般的数据。
3) 和4、5页为数值块,可作为钱包使用,两字节的值以正和反两种形式存贮。只有减
值操作,没有加值操作。如果不做钱包使用,则可以做为普通的数据块使用。
4)第6、7、8、9页存储着密码A(6字节)、密码B(6字节)及存取控制。
5)第7页的2字节、第9页的2字节为存储控制,存储控制以正和反的形式存两次。Bit 7 ---
Bit 6 ---
Bit 5 Data2—Write –Enable
Bit 4 Data2—Read—Enable
Bit 3 Key+AC—Write—Enable
Bit 2 Value—Write—Enable
Bit 1 Data1—Write—Enable
Bit 0 Data1—Read—Enable
例如:AC-A的初始值为ff,即‘11111111’,即:
Data1:可读、可写;
Value:可写;
AC-A:可写;
Data2:可读、可写;
6)一次写一页(4个字节),一次读两页(8个字节)。
http://www.szbc.net/support.htm
http://www.cntchina.com/index.htm
而微软的 win32 API的提供的针对Smart Card的操作的API函数,
可以对任何符合PC/SC规范的读写器进行开发.
详细信息可以参考MSDN的Platform SDK\Security\Smart Card\以下程序从网上得来.有兴趣的可以参考MSDN
Windows API SmartCard使用例程:(供初学者调试使用)
// testpcsc.cpp : Defines the entry point for the application.
//#include "stdafx.h"
#include "Winscard.h"//安装微软的SMART CARD 组件后方可,并且在菜单栏--项目—设定
//—连接中加入--winscard.lib库文件
#include "windows.h"#define TRACE(a) OutputDebugString(a)
short __stdcall asc_hex(unsigned char *asc, unsigned char *hex, long pair_len);short __stdcall hex_asc(unsigned char *hex,unsigned char *asc,long length);int cpu_protocol(SCARDHANDLE hCardHandle,unsigned char *send_cmd,long int len,unsigned long *rLen,unsigned char *receive_data);int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
SCARDCONTEXT hContext;
LONG lReturn;
SCARDHANDLE hCardHandle;
DWORD dwAP; HRESULT hr = S_OK;
LPTSTR szReaders, szRdr;
DWORD cchReaders = SCARD_AUTOALLOCATE;
DWORD dwI, dwRdrCount;
SCARD_READERSTATE rgscState[MAXIMUM_SMARTCARD_READERS];
// TCHAR szCard[MAX_PATH];
//SCARDCONTEXT hSC;
//LONG lReturn;
/*
第一步:运行SCardEstablishContext创建上下文句柄hContext.
*/lReturn = SCardEstablishContext(SCARD_SCOPE_USER,//两个参数可选,SCARD_SCOPE_USER :用户权限访问数据库,SCARD_SCOPE_SYSTEM 系统权限访问数据库
NULL,//保留将来使用,附值NULL
NULL,//保留将来使用,附值NULL
&hContext);//返回资源管理的上下文句柄
/*
验证返回值。
*/
if ( SCARD_S_SUCCESS != lReturn )
{
TRACE("Failed SCardEstablishContext\n");
return 0;
} /*
第二步:获得读写器名列表。关键参数szReaders,如果cchReaders=SCARD_AUTOALLOCATE,最后用SCardFreeMemory释放内存块 */
lReturn = SCardListReaders(hContext,//利用SCardEstablishContext函数返回的句柄。
NULL,//读写器在系统中分组后,定义的组名。NULL选择所有的读写器。
(LPTSTR)&szReaders,//返回的读写器列表指针,可从分离出到读写器名。
&cchReaders );//
if ( SCARD_S_SUCCESS != lReturn )
{
TRACE("Failed SCardListReaders\n");
return 0;
} /*
从szReaders中分离出读写器名,存入结构体 SCARD_READERSTATE rgscState[MAXIMUM_SMARTCARD_READERS];
MAXIMUM_SMARTCARD_READERS:系统中读写器的最大数10
*/
szRdr = szReaders;
for ( dwI = 0; dwI < MAXIMUM_SMARTCARD_READERS; dwI++ )
{
if ( 0 == *szRdr )
break;
rgscState[dwI].szReader = szRdr;
// rgscState[dwI].dwCurrentState = SCARD_STATE_UNAWARE;
szRdr += lstrlen(szRdr) + 1;
}
dwRdrCount = dwI; /*
可以得到rgscState数组所有读写器的当前状态:存在、有卡、无卡,如果读写器中有卡得到复位信号
*/
lReturn=SCardGetStatusChange(
hContext,
0,//等待响应的最大延时
rgscState,
1);//读写器的个数//SCARD_STATE_CHANGED /*
从系统中删除所有读写器名,计算机重新启动后,可恢复*/
/* DWORD iFR;
for(iFR=0;iFR<=dwRdrCount;iFR++)
{ lReturn = SCardForgetReader(hContext,
rgscState[iFR].szReader);
}
if ( SCARD_S_SUCCESS != lReturn )
{
// printf("Failed SCardForgetReader\n");
}
*/ /*
第三步:用读写器名,连接读写器。(必须插入CPU卡)
*/
lReturn = SCardConnect( hContext,
rgscState[0].szReader,//读写器名:也可从
// rgscState[dwI].szReader取出。
SCARD_SHARE_EXCLUSIVE,//访问模式:独占,共享,直接。
/*SCARD_SHARE_SHARED,*/
SCARD_PROTOCOL_T0 ,//于卡的通讯协议。T0,T1,
&hCardHandle, //返回卡的句柄
&dwAP );//返回卡的通讯协议
//BYTE rgbAtr[36];
DWORD cByte=36 ; if ( SCARD_S_SUCCESS != lReturn )
{
TRACE("Failed SCardConnect\n");
//return 0; // Or other appropriate action.
} //跟踪通讯协议。
switch ( dwAP )
{
case SCARD_PROTOCOL_T0:
TRACE("Active protocol T0\n");
break; case SCARD_PROTOCOL_T1:
TRACE("Active protocol T1\n");
break; case SCARD_PROTOCOL_UNDEFINED:
default:
TRACE("Active protocol unnegotiated or unknown\n");
break;
} char ATRbuf[256],szAscATR[256];
unsigned long bufLen; bufLen = 110;
/*
得到当前读写器的属性,并不改变卡、读写器的状态。
下面返回卡的复位信号。
*/
lReturn = SCardGetAttrib(hCardHandle,//SCardConnect返回的值
SCARD_ATTR_ATR_STRING,//属性ID
(LPBYTE)ATRbuf,//返回复位信号。
&bufLen);//字符长度。
{
WCHAR szReader[200];
DWORD cch = 200;
BYTE bAttr[32];
DWORD cByte = 32;
DWORD dwState, dwProtocol;
LONG lReturn; // Determine the status.
// hCardHandle was set by an earlier call to SCardConnect.
lReturn = SCardStatus(hCardHandle,
(LPTSTR)szReader,
&cch,
&dwState,
&dwProtocol,
(LPBYTE)&bAttr,
&cByte);
}
if ( SCARD_S_SUCCESS != lReturn )
TRACE("Failed SCardGetAttrib\n");
else
{
//十六进制 转十六进制的字符。
hex_asc((unsigned char*)ATRbuf,(unsigned char*)szAscATR,bufLen);
TRACE("\n\n\n");
TRACE(szAscATR);
TRACE("\n\n\n");
}
/////////////////
//operation
// SCardBeginTransaction(hCardHandle);/*
向卡发送命令。
*/ char SendBuf[256],RecvBuf[256];
char Bufhex[256],RecvBufHex[256];
unsigned long dwSend,dwRecv=110; memset(SendBuf, 0, sizeof(SendBuf));
memset(RecvBuf, 0, sizeof(RecvBuf));
memset(Bufhex, 0, sizeof(Bufhex));
memset(RecvBufHex, 0, sizeof(RecvBufHex)); strcpy(SendBuf, "00A40000022f03");
dwSend = strlen(SendBuf)/2 ; //十六进制字符转换十六进制。"f5 e4" to 0xf50xe4
asc_hex((unsigned char*)SendBuf, (unsigned char*)Bufhex, strlen(SendBuf)/2);
//发送命令Bufhex,返回RecvBufHex.
cpu_protocol(hCardHandle,(unsigned char *)Bufhex,dwSend, &dwRecv, (unsigned char*)RecvBufHex);
//十六进制转换十六进制字符。0xf3 0xe4 to "f3 e4"
hex_asc((unsigned char*)RecvBufHex, (unsigned char*)RecvBuf, dwRecv);
TRACE(RecvBuf);
TRACE("\n");
/*
释放内存块
*/
SCardFreeMemory(
hContext,
&cchReaders);//SCardListReaders函数中定义的。 /*
断开连接
*/
lReturn =SCardDisconnect(
hCardHandle,
SCARD_LEAVE_CARD//参数可选SCARD_RESET_CARD:重启 SCARD_UNPOWER_CARD掉点 SCARD_EJECT_CARD 吐卡。 SCARD_LEAVE_CARD不做任何事情。
); return 0;
}
int cpu_protocol(SCARDHANDLE hCardHandle,unsigned char *send_cmd,long int len,unsigned long *rLen,unsigned char *receive_data)
{
LONG lReturn;
DWORD dwRecvlen=20;
lReturn = SCardTransmit(hCardHandle,
SCARD_PCI_T0,
(unsigned char*)send_cmd,
len,
NULL,
(unsigned char*)receive_data,
&dwRecvlen );
*rLen = dwRecvlen;
char szTemp[20]="\0";
memcpy(szTemp,receive_data,4);
if ( SCARD_S_SUCCESS != lReturn )
{
TRACE("Failed SCardTransmit\n");
return 0;
}
else if (receive_data[0] == 0x61)
{
send_cmd[0] = 0x00;
send_cmd[1] = 0xc0;
send_cmd[2] = 0x00;
send_cmd[3] = 0x00;
send_cmd[4] = receive_data[1];
len = 5;
dwRecvlen = 110;
lReturn = SCardTransmit(hCardHandle,
SCARD_PCI_T0,
(unsigned char*)send_cmd,
len,
NULL,
(unsigned char*)receive_data,
&dwRecvlen );
*rLen = dwRecvlen;
if ( SCARD_S_SUCCESS != lReturn )
{
TRACE("Failed SCardTransmit\n");
return 0;
}
}
return 1;
}
short __stdcall asc_hex(unsigned char *asc, unsigned char *hex, long pair_len)
{
char src1,src2,factor1,factor2;
long len;
factor1 = '7';
factor2 = '7';
_strupr( (char *)asc ); for (len=0; len < pair_len; len++)
{
src1 = *(asc+len*2);
src2 = *(asc+len*2+1);
if ((src1>='0') && (src1<='9'))
factor1 = '0';
else if ((src1>='A') && (src1<='F'))
factor1 = '7';
else
return 1;
if ((src2>='0') && (src2<='9'))
factor2 = '0';
else if ((src2>='A') && (src2<='F'))
factor2 = '7';
else
return 1;
src1 = src1 - factor1;
src2 = src2 - factor2;
*hex++ = (src1 << 4) | src2;
}
return 0;
}
short __stdcall hex_asc(unsigned char *hex,unsigned char *asc,long length)
{
UCHAR hLowbit,hHighbit;
long i;
for(i=0;i<length*2;i=i+2)
{
hLowbit=hex[i/2]&0x0f;
hHighbit=hex[i/2]/16;
if(hHighbit>=10)
asc[i]=hHighbit+'7';
else
asc[i]=hHighbit+'0';
if(hLowbit>=10)
asc[i+1]=hLowbit+'7';
else
asc[i+1]=hLowbit+'0';
}
asc[length*2]='\0';
return 0;
}