最近接触到一个使用Felica卡的项目,在开发Felica卡的读写过程中遇到的一些问题,将这些问题整理并记录下来,方便各位在开发Felica卡读写应用的过程中进行参考。
什么是Felica卡
首先,我们了解一下什么是Felica卡?FeliCa是Sony所开发出来的非接触式IC卡技术。名称由英语中代表“幸福”的 "Felicity" 和 "Card"(卡片)组合而成,是Sony的注册商标。liCa 是为了非接触式IC卡而开发出来的通信技术。非接触式IC卡由读写时送出的载波引导而供给电力,由载波的调变与卡片读写沟通。例如 ISO 14443 type B,使用ASK10%调变,及NRZ编码。与此相比,FeliCa的调变同样是 ASK10%,但不同的是采用曼彻斯特编码。
最初被提案为 ISO 14443 type C, 但未被采纳。之后,FeliCa和其向后相容方式被标准化为 ISO 18092(Near Field Communication, NFC, 近距离通信)。在日本国内,被当作 JICSAP IC卡规格 V2.0 “第四部份 高速处理用IC卡”和日本鉄道サイバネティクス协议会的IC卡规格而予以标准化。
FeliCa和一般的IC卡同样有适用于现金卡或识别卡的技术,但为了要求高速处理特性(自动充值设备、大楼进出管制等)或结帐(便利商店)等等的应用,将指令集加以特殊化。因此和 ISO 7816-3 的基本指令并不相容。且 IC芯片内部的内存固定为16字节长的纪录,因此和 ISO 7816-3规定的档案结构亦不相容。
加密处理方面,相互认证使用Triple DES,通讯使用DES或Triple DES。没有公开密钥加密的规格。双模型式(接触/非接触)虽然可以有公开密钥加密,但只在接触通讯时使用。
相互认证时、缩退码被作为加解的密码来使用。不是说每一个项目个别认证、它是通过复数的访问码加密生成的键称为退缩码,这个退缩码最多可供16个项目使用。缩退码生不成原来的密码。这样,不降低安全级别的情况下实现高速化处理。
反正就是Felica卡对于我们来说用的地方很多少,是个另类。
关于支持Felica 的读卡器选择
由于Felica卡在我们这里基本上没有被使用。所以,支持Felica卡的智能卡读写器就比较少了。买了很多个读卡器均不支持Felica卡的读写,好在皇天不负有心人,找到了诺塔斯智能科技的NTS-12-2823这款读卡器。
首先,它支持ISO14443 TYPE A、ISO14443 TYPE B和ISO15693等多种协议,可以与多种类型的非接触式智能卡和电子标签进行通信,从而满足用户在不同场景下的需求。
此外,诺塔斯L12-2823读写器提供了多种平台和多语言的二次开发包,包括丰富的函数接口和范例源码,使得用户在进行二次开发时能够轻松照搬范例,大大降低了开发难度,提高了开发效率。
目前这个项目中采用的是Dephi进行开发,诺塔斯提供的开发范例也比较齐全基本上照搬即可。以下是代码部分。
首先,初始化一下 unit LotusCardDriver;,这是里面定义了设备的各种参数,需要引用进来。windows环境中还需要引用LotusCardDriver.dll;这个文件分为32位和64位,这个要根据自己项目运行的操作系统选择正确的版本。
打开设备
{ /**
* 打开设备
*
* @param strDeviceName
* 串口设备名称
* @param nVID
* USB设备VID
* @param nPID
* USB设备PID
* @param unRecvTimeOut
* 接收等待长度
* @param nUsbDeviceIndex
* USB设备索引
* @return 句柄
*/}
function LotusCardOpenDevice(pszDeviceName:PAnsiChar;nVID, nPID, nUsbDeviceIndex, unRecvTimeOut:Integer;pExtendReadWrite:TLotusCardExtendReadWriteCallBackFunc):Integer;stdcall; external DLL_NAME;
设置卡类型和寻卡。
/**
* 设置卡片类型
* @param nDeviceHandle
* 设备句柄
* @param cCardType 卡片类型 A='A'/'a' B='B'/'b' F='F'/'f' C='C'/'c'
* @return true = 成功
*/}
function LotusCardSetCardType( nDeviceHandle:Integer; cCardType:AnsiChar):BOOL; stdcall; external DLL_NAME;
{ /**
* Felica寻卡
* @param nDeviceHandle
* 设备句柄
* @param unTimerSlot timer slot 0x00 0x01 0x03 0x07 0x0F
* @param tLotusCardParam 参数(读写缓冲)
* @return true = 成功
*/}
function LotusCardFelicaPolling(nDeviceHandle:Integer; unTimerSlot:Byte; sttpLotusCardParam:PLotusCardParamStruct):BOOL; stdcall; external DLL_NAME;
{
读卡和写卡
function LotusCardNfcVWriteNBlock(nDeviceHandle:Integer; unBlockIndex:DWORD; unBlockCount:DWORD; pUid:PByte; pBuffer:PByte; unBufferLength:DWORD):BOOL; stdcall; external DLL_NAME;
{ /**
* Felica寻卡
* @param nDeviceHandle
* 设备句柄
* @param pUid 参数 UID 8字节
* @param pPMM 参数 PMM
* @param pPSC 参数 Primary System Code
* @return true = 成功
*/}
function LotusCardNfcFRequest(nDeviceHandle:Integer; pUid, pPMM, pPSC:PByte):BOOL; stdcall; external DLL_NAME;
{ /**
* Felica读卡
* @param nDeviceHandle
* 设备句柄
* @param unBlockIndex 参数 块索引
* @param pUid 参数 UID 8字节
* @param pBuffer 参数 缓冲
* @param punBufferLength 参数 缓冲长度 返回结果长度
* @return true = 成功
*/}
function LotusCardNfcFReadBlock(nDeviceHandle:Integer; unBlockIndex:DWORD; pUid, pBuffer:PByte; punBufferLength:PDWORD):BOOL; stdcall; external DLL_NAME;
{ /**
* Felica读卡
* @param nDeviceHandle
* 设备句柄
* @param unBlockIndex 参数 块索引
* @param unBlockCount 参数 块数量
* @param pUid 参数 UID 8字节
* @param pBuffer 参数 缓冲
* @param punBufferLength 参数 缓冲长度 返回结果长度
* @return true = 成功
*/}
function LotusCardNfcFReadNBlock(nDeviceHandle:Integer; unBlockIndex:DWORD; unBlockCount:DWORD; pUid, pBuffer:PByte; punBufferLength:PDWORD):BOOL; stdcall; external DLL_NAME;
{ /**
* Felica写卡
* @param unBlockIndex 参数 块索引
* @param pUid 参数 UID 8字节
* @param pBuffer 参数 缓冲
* @param punBufferLength 参数 缓冲长度 返回结果长度
* @return true = 成功
*/}
function LotusCardNfcFWriteBlock( nDeviceHandle:Integer; unBlockIndex:DWORD; pUid, pBuffer:PByte; punBufferLength:PDWORD):BOOL; stdcall; external DLL_NAME;
{ /**
* Felica写卡
* @param unBlockIndex 参数 块索引
* @param unBlockCount 参数 块数量
* @param pUid 参数 UID 8字节
* @param pBuffer 参数 缓冲
* @param punBufferLength 参数 缓冲长度 返回结果长度
* @return true = 成功
*/}
function LotusCardNfcFWriteNBlock( nDeviceHandle:Integer; unBlockIndex, unBlockCount:DWORD; pUid, pBuffer:PByte; punBufferLength:PDWORD):BOOL; stdcall; external DLL_NAME;
关闭设备
/**
* 关闭设备
*
* @param nDeviceHandle
* 设备句柄
*/}
procedure LotusCardCloseDevice(nDeviceHandle:Integer);stdcall; external DLL_NAME;//'LotusCardDriver.dll';
以上是关于使用NTS-L12-2823读写器读写Felica智能卡的相关操作,仅供参考!开发过程中遇到技术问题也可以联系诺塔斯,还是比较方便。