IC卡应用系统开发-(一)卡片读写

IC卡应用系统开发-(一)卡片读写
最近在开发一个基于CPU卡应用的J2EE项目,应用服务器用的是Weblogic,数据库是oracle, 开发工具jbuilder2005.系统架构是:客户端(pc/sc读写器)客户端首先要安装IC读写器驱动(必须支持PC/SC规范),然后到pcscworkgroup网站下载文件installOCF.class和Reference_Impl.class.
运行>java installOCF
按照提示一步一步进行安装操作.
运行>java Reference_Impl
默认安装操作.
在安装完后将thirdpartyOCF1.2libOCFPCSC1.DLL和thirdpartyOCF1.2libOCFPCSCM.DLL拷贝到jdk的bin目录.
在jbuilder工程文件目录下建立opencard.properties文件,内容如下,
# Configure the CardService Registry:
# Use the service factory for the IBM MultiFunction Cards
OpenCard.services = opencard.opt.util.PassThruCardServiceFactory
#OpenCard.services = com.ibm.opencard.factory.MFCCardServiceFactory
# OpenCard.services = com.slb.opencard.CyberflexAccess.CyberflexAccessCardServiceFactory

# Configure the CardTerminal Registry:
com.ibm.opencard.terminal.pcscmig.PcscMigCardTerminalFactory
OpenCard.terminals = com.ibm.opencard.terminal.pcsc10.Pcsc10CardTerminalFactory

# Configure Tracing. Detailed for all samples only:
OpenCard.trace = opencard:8

在jbuilder中建立pcsc库.
tools-->configure-->libraries
在user home下建立pcsc10,在required libraries选项卡中选择安装的目录下lib下的所有文件.
我用的读写期是某公司的,命令集与PBOC稍有改动,但基本格式是按照PCSC的.
我建立了3个文件:
接口文件:IReader.java,用于程序将来兼容其他读写器;
实现文件:ReaderMA,java,实现接口,
异常文件:ReaderException,用户捕获异常及错误处理.
实现文件如下:
package com.microapp.application.reader;

/**
*

Title: 基于PC/SC标准的读写器实现


*
*

Description:


*
*

Copyright: Copyright (c) 2005


*
*

Company: 我的软件公司


*
* @author etd group
* @version 1.0
*/
import java.util.*;

import opencard.core.*;
import opencard.core.service.*;
import opencard.core.terminal.*;
import opencard.core.util.*;
import opencard.opt.util.*;

public class ReaderMA implements IReader
{
private static final int IFD_TIMEOUT = 5; // unit: seconds
private static final int MAX_APDU_SIZE = 200; // unit: byte
private static final int SW1_OK = (byte)0x90;
private static final int SW2_OK = 0x00;
private static final int RESPONSE_OK = 0x61;

private static SmartCard sc = null;
private static PassThruCardService ptcs = null;
private static CardRequest cr = null;
private static CommandAPDU capdu = null;
private static ResponseAPDU rapdu = null;
byte[] rbuf = null;

public ReaderMA()
{
}

/**
* 复位
* @throws ReaderPCSCException
*/
public byte[] Reset() throws ReaderException
{
try
{
if (cr == null)
{
SmartCard.start();
cr = new CardRequest(CardRequest.ANYCARD, null, PassThruCardService.class);
}

cr.setTimeout(IFD_TIMEOUT);
sc = SmartCard.waitForCard(cr);
if(sc == null)
{
throw new ReaderPCSCException("did not get a SmartCard object!");
}

CardID cardID = sc.getCardID();
byte[] atr = cardID.getATR();

capdu = new CommandAPDU(MAX_APDU_SIZE);
ptcs = (PassThruCardService) sc.getCardService(PassThruCardService.class, true);
return atr;
}
catch(CardTerminalException ex)
{
throw new ReaderException("Reset failed!" + ex.getMessage());
}
catch(CardServiceException ex)
{
throw new ReaderException("Reset failed!" + ex.getMessage());
}
catch(ClassNotFoundException ex)
{
throw new ReaderException("Reset failed!" + ex.getMessage());
}
catch(OpenCardPropertyLoadingException ex)
{
throw new ReaderException("Reset failed!" + ex.getMessage());
}
}

/**
* 下电
* @throws ReaderPCSCException
*/
public void ShutDown() throws ReaderException
{
try
{
if(sc.isStarted())
{
sc.shutdown();
sc.close();
SmartCard.shutdown();
}

sc = null;
cr = null;
}
catch(CardTerminalException ex)
{
throw new ReaderException("Shutdown failed!" + ex.getMessage());
}
}

/**
* 读随机数
* @return byte[]
*/
public byte[] getChallenge() throws ReaderException
{
try
{
byte[] command = new byte[5];
command[0] = 0x00; // CLA
command[1] = (byte)0x84; // INS
command[2] = 0x00; // P1
command[3] = 0x00; // P2
command[4] = 0x08; // Lc

capdu.setLength(0);
capdu.append(command);
ResponseAPDU response = ptcs.sendCommandAPDU(capdu);
if(((response.sw1() == SW1_OK) && (response.sw2() == SW2_OK)) || (response.sw1() == RESPONSE_OK))
{
return response.data();
}
else
{
throw new ReaderPCSCException(response.sw1(), response.sw2());
}
}
catch(OpenCardException ex)
{
throw new ReaderPCSCException("Get challenge failed!" + ex.getMessage());
}
}

/**
* SelectTicketApplication
* @return boolean
*/
public boolean SelectApplication() throws ReaderPCSCException
{
try
{
byte[] command = new byte[7];
command[0] = 0x00; // CLA
command[1] = (byte)0xA4; // INS
command[2] = 0x00; // P1
command[3] = 0x00; // P2
command[4] = 0x02; // Lc
command[5] = 0x2F;
command[6] = 0x01;

capdu.setLength(0);
capdu.append(command);
ResponseAPDU response = ptcs.sendCommandAPDU(capdu);

if(((response.sw1() == SW1_OK) && (response.sw2() == SW2_OK)) ||
(response.sw1() == RESPONSE_OK))
{
return true;
}

return false;
}
catch(OpenCardException ex)
{
throw new ReaderPCSCException("Select Ticket Application failed!" + ex.getMessage());
}
}

/**
* 外部认证
* @param data String
* @return boolean : true: pass, false: error.
*/
public boolean ExternalAuthentication(byte[] data) throws IndexOutOfBoundsException,
NumberFormatException, ReaderPCSCException
{
try
{
byte[] command = new byte[13];
command[0] = 0x00; // CLA
command[1] = (byte)0x82; // INS
command[2] = 0x00; // P1
command[3] = 0x02; // P2
command[4] = 0x08; // Lc
command[5] = data[0];
command[6] = data[1];
command[7] = data[2];
command[8] = data[3];
command[9] = data[4];
command[10] = data[5];
command[11] = data[6];
command[12] = data[7];

capdu.setLength(0);
capdu.append(command);
ResponseAPDU response = ptcs.sendCommandAPDU(capdu);

if((response.sw1() != SW1_OK) || (response.sw2() != SW2_OK))
{
throw new ReaderPCSCException(response.getByte(0), response.getByte(1));
}

return true;
}
catch(OpenCardException ex)
{
throw new ReaderPCSCException("Get challenge failed!" + ex.getMessage());
}
catch(ReaderPCSCException ex)
{
throw new ReaderPCSCException(ex.getMessage());
}
}

/**
* 内部认证
* @param data String
* @return byte[]
*/
public byte[] IntenalAuthentication(byte[] data) throws IndexOutOfBoundsException,
NumberFormatException, ReaderPCSCException
{
try
{
byte[] command = new byte[13];
command[0] = 0x00; // CLA
command[1] = (byte)0x88; // INS
command[2] = 0x00; // P1
command[3] = 0x01; // P2
command[4] = 0x08; // Lc
command[5] = data[0];
command[6] = data[1];
command[7] = data[2];
command[8] = data[3];
command[9] = data[4];
command[10] = data[5];
command[11] = data[6];
command[12] = data[7];

capdu.setLength(0);
capdu.append(command);
ResponseAPDU response = ptcs.sendCommandAPDU(capdu);

if(response.sw1() == 0x61)
{
command = new byte[5];
command[0] = 0x00; // CLA
command[1] = (byte)0xC0; // INS
command[2] = 0x00; // P1
command[3] = 0x00; // P2
command[4] = 0x08; // Lc

capdu.setLength(0);
capdu.append(command);
response = ptcs.sendCommandAPDU(capdu);

if((response.sw1() != SW1_OK) || (response.sw2() != SW2_OK))
{
throw new ReaderPCSCException(response.sw1(), response.sw2());
}

return response.data();
}
else
{
throw new ReaderPCSCException(response.getByte(0), response.getByte(1));
}

}
catch(OpenCardException ex)
{
throw new ReaderPCSCException("Get challenge failed!" + ex.getMessage());
}
catch(ReaderPCSCException ex)
{
throw new ReaderPCSCException(ex.getMessage());
}
}

/**
* 读基本信息文件
* @return byte[]
* @throws ReaderPCSCException
*/
public byte[] ReadBasicFile() throws ReaderPCSCException
{
try
{
byte[] command = new byte[5];
command[0] = 0x00; // CLA
command[1] = (byte)0xb0; // INS
command[2] = (byte)0x95; // P1
command[3] = 0x00; // P2
command[4] = 0x27; // Lc

capdu.setLength(0);
capdu.append(command);
ResponseAPDU response = ptcs.sendCommandAPDU(capdu);

if((response.sw1() != SW1_OK) || (response.sw2() != SW2_OK))
{
throw new ReaderPCSCException(response.getByte(39), response.getByte(40));
}

return response.data();
}
catch(OpenCardException ex)
{
throw new ReaderPCSCException("Read base file failed!" + ex.getMessage());
}
}

/**
* 读持卡人信息文件
* @return String
* @throws ReaderPCSCException
*/
public byte[] ReadHolderFile() throws ReaderPCSCException
{
return null;
}

/**
* 读基本信息文件
* @param record int
* @return String
* @throws ReaderPCSCException
*/
public byte[] ReadBasicInfo(int record) throws ReaderPCSCException
{
try
{
byte[] command = new byte[5];
command[0] = 0x00;
command[1] = (byte)0xB2;
command[2] = (byte)record;
command[3] = (byte)0x84;
command[4] = (byte)0x9C;

capdu.setLength(0);
capdu.append(command);
ResponseAPDU response = ptcs.sendCommandAPDU(capdu);

if((response.sw1() != SW1_OK) || (response.sw2() != SW2_OK))
{
throw new ReaderPCSCException(response.sw1(), response.sw2());
}

return response.data();
}
catch(OpenCardException ex)
{
throw new ReaderPCSCException("Read ticket file error!" + ex.getMessage());
}
}

/**
* 写基本信息文件
* @param record
* @param data String
* @throws ReaderPCSCException
*/
public boolean WriteBasicInfo(int record, byte[] data) throws ReaderPCSCException
{
try
{
byte[] command = new byte[161];
command[0] = 0x00;
command[1] = (byte)0xDC;
command[2] = (byte)record;
command[3] = (byte)0x84;
command[4] = (byte)0x9C;
System.arraycopy(data, 0, command, 5, 0x9C);

capdu.setLength(0);
capdu.append(command);
ResponseAPDU response = ptcs.sendCommandAPDU(capdu);

if((response.sw1() != SW1_OK) || (response.sw2() != SW2_OK))
{
throw new ReaderPCSCException(response.sw1(), response.sw2());
}

return true;
}
catch(OpenCardException ex)
{
throw new ReaderPCSCException("Get challenge failed!" + ex.getMessage());
}
catch(ReaderPCSCException ex)
{
throw new ReaderPCSCException(ex.getMessage());
}
}
用opencard规范开发非常的简单,特别是处理返回数据,在responseAPDU内用sw1和sw22个方法用于返回sw1,sw2.数据是直接用response.data()即可.省缺了一般读写拼字节的过程.

在读写器之上我定义了一个基于应用的卡片类,AppCard,在这个类内实现卡片的具体操作.
如内部认证,外部认证,获取随机数等.

public void reset() throws TicketException
{
try
{
byte[] batr = reader.Reset();
StringBuffer sb = new StringBuffer();
String s = new String();

for(int i = 0; i < batr.length; i++)
{
s = Integer.toHexString(batr[i]).toUpperCase();
if(s.length() == 1)
{
sb.append("0" + s);
}
else if(s.length() > 2)
{
sb.append(s.substring(s.length() - 2, s.length()));
}
else
{
sb.append(s);
}
sb.append(" ");
}

atr = sb.toString();
}
catch(ReaderPCSCException rex)
{
throw new TicketException("Reset failed! " + rex.getMessage());
}
}

/**
* ShutDown
*/
public void ShutDown() throws TicketException
{
try
{
reader.ShutDown();
}
catch(ReaderException ex)
{
throw new TicketException("Shutdown failed!");
}
}

/**
* 获取随机数
* @return String
*/
public String getChallenge() throws TicketException
{
try
{
StringBuffer sb = new StringBuffer();
String s = new String();
byte[] buf = reader.getChallenge();

for(int i = 0; i < buf.length; i++)
{
s = Integer.toHexString(buf[i]).toUpperCase();
if(s.length() == 1)
{
sb.append("0" + s);
}
else if(s.length() > 2)
{
sb.append(s.substring(s.length() - 2, s.length()));
}
else
{
sb.append(s);
}
}

return sb.toString();
}
catch(ReaderPCSCException rex)
{
throw new TicketException(rex.getMessage());
}
}

/**
* 内部认证
* @param data String
* @return String
*/
public String IntenalAuthentication(String data) throws TicketException
{
try
{
byte[] sendbuf = new byte[8];
sendbuf[0] = (byte)(Integer.parseInt(data.substring(0,2), 16));
sendbuf[1] = (byte)(Integer.parseInt(data.substring(2,4), 16));
sendbuf[2] = (byte)(Integer.parseInt(data.substring(4,6), 16));
sendbuf[3] = (byte)(Integer.parseInt(data.substring(6,8), 16));
sendbuf[4] = (byte)(Integer.parseInt(data.substring(8,10), 16));
sendbuf[5] = (byte)(Integer.parseInt(data.substring(10,12), 16));
sendbuf[6] = (byte)(Integer.parseInt(data.substring(12,14), 16));
sendbuf[7] = (byte)(Integer.parseInt(data.substring(14,16), 16));
StringBuffer sb = new StringBuffer();
String s = new String();
byte[] recvbuf = reader.IntenalAuthentication(sendbuf);

for(int i = 0; i < recvbuf.length; i++)
{
s = Integer.toHexString(recvbuf[i]).toUpperCase();
if(s.length() == 1)
{
sb.append("0" + s);
}
else if(s.length() > 2)
{
sb.append(s.substring(s.length() - 2, s.length()));
}
else
{
sb.append(s);
}
}

return sb.toString();
}
catch(ReaderPCSCException rex)
{
throw new TicketException(rex.getMessage());
}
catch(NumberFormatException ex)
{
throw new TicketException(ex.getMessage());
}
catch(IndexOutOfBoundsException ex)
{
throw new TicketException(ex.getMessage());
}
}

/**
* 外部认证
*
* @param data String
*/
public boolean ExternalAuthentication(String data) throws TicketException
{
try
{
byte[] buf = new byte[8];
buf[0] = (byte)(Integer.parseInt(data.substring(0,2), 16));
buf[1] = (byte)(Integer.parseInt(data.substring(2,4), 16));
buf[2] = (byte)(Integer.parseInt(data.substring(4,6), 16));
buf[3] = (byte)(Integer.parseInt(data.substring(6,8), 16));
buf[4] = (byte)(Integer.parseInt(data.substring(8,10), 16));
buf[5] = (byte)(Integer.parseInt(data.substring(10,12), 16));
buf[6] = (byte)(Integer.parseInt(data.substring(12,14), 16));
buf[7] = (byte)(Integer.parseInt(data.substring(14,16), 16));

return reader.ExternalAuthentication(buf);
}
catch(ReaderPCSCException rex)
{
throw new TicketException(rex.getMessage());
}
catch(NumberFormatException ex)
{
throw new TicketException(ex.getMessage());
}
catch(IndexOutOfBoundsException ex)
{
throw new TicketException(ex.getMessage());
}
}
利用该方法,在客户端实现了用户卡的读写,大大简化了开发,并运行稳定,性能完全预期要求.

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-129998/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/374079/viewspace-129998/

你可能感兴趣的:(IC卡应用系统开发-(一)卡片读写)