一个 scriptgen 工具,用于将 CAP 文件转换为 APDU 脚本文件。该工具简称为卡片外部安装程序。
支持库(用于 Java Card API 的类文件和导出文件)、文档和示例。
虽然 Sun Java Card 开发工具箱允许编写并测试 Java Card applet,部署真正的端到端智能卡应用程序却要求这些工具不被包含在开发工具箱内,例如:像 OpenCard 和 Global Platform API 这样的终端 API 的使用。可能还要求使用像用户识别模块(Subscriber Identification Module,SIM)这样的工具箱来帮助你管理 SIM。
表 1 显示了工具箱的目录结构(Windows 版本),以及包含开发工具的 bin 目录内容。
图 1a. 开发工具箱目录结构
图 1b. Bin 目录的内容
现在让我们重新访问 Java Card 开发步骤,记住这次要使用 Sun Java Card 开发工具箱:
/** * Installs the Applet. Creates an instance of MyApplet. The * JCRE calls this static method during applet installation. * @param bArray install parameter array. * @param bOffset where install data begins. * @param bLength install parameter data length. * @throw ISOException if the install method fails. */ public static void install(byte[] bArray, short bOffset, byte bLength) throws ISOException { // Instantiate MyApplet new MyApplet(); ... }
/** * Called by the JCRE to inform this applet that it has been * selected. Perform any initialization that may be required to * process APDU commands. This method returns a boolean to * indicate whether it is ready to accept incoming APDU commands * via its process() method. * @return If this method returns false, it indicates to the JCRE * that this Applet declines to be selected. */ public boolean select() { // Perform any applet-specific session initialization. return true; }
/** * Called by the JCRE to inform this currently selected applet * it is being deselected on this logical channel. Performs * the session cleanup. */ public void deselect() { // Perform appropriate cleanup. ownerPin.reset(); }
/** * Called by the JCRE to process an incoming APDU command. An * applet is expected to perform the action requested and return * response data if any to the terminal. * * Upon normal return from this method the JCRE sends the ISO- * 7816-4-defined success status (90 00) in the APDU response. If * this method throws an ISOException the JCRE sends the * associated reason code as the response status instead. * @param apdu is the incoming APDU. * @throw ISOException if the process method fails. */ public void process(APDU apdu) throws ISOException { // Get the incoming APDU buffer. byte[] buffer = apdu.getBuffer(); // Get the CLA; mask out the logical-channel info. buffer[ISO7816.OFFSET_CLA] = (byte)(buffer[ISO7816.OFFSET_CLA] & (byte)0xFC); // If INS is Select, return - no need to process select // here. if ((buffer[ISO7816.OFFSET_CLA] == 0) && (buffer[ISO7816.OFFSET_INS] == (byte)(0xA4)) ) return; // If unrecognized class, return "unsupported class." if (buffer[ISO7816.OFFSET_CLA] != MyAPPLET_CLA) ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); // Process (application-specific) APDU commands aimed at // MyApplet. switch (buffer[ISO7816.OFFSET_INS]) { case VERIFY_INS: verify(apdu); break; case GET_BALANCE_INS: getBalance(apdu); break; default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); break; } }
/** * Retrieves and returns the balance stored in this card. * @param apdu is the incoming APDU. */ private void getBalance(APDU apdu) { // Get the incoming APDU buffer. byte[] buffer = apdu.getBuffer(); // Set the data transfer direction to outbound and obtain // the expected length of response (Le). short le = apdu.setOutgoing(); // If the expected size is incorrect, send a wrong-length // status Word. if (le != GET_BALANCE_RESPONSE_SZ) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); // Set the actual number of bytes in the response data field. apdu.setOutgoingLength((byte)GET_BALANCE_RESPONSE_SZ); // Set the response data field; split the balance into 2 // separate bytes. buffer[0] = (byte)(balance >> 8); buffer[1] = (byte)(balance & 0xFF); // Send the 2-byte balance starting at the offset in the APDU // buffer. apdu.sendBytes((short)0, (short)GET_BALANCE_RESPONSE_SZ); }
/** * Validates (verifies) the Owner's PIN number. * @param apdu is the incoming APDU. */ private void verify(APDU apdu) { // Get the incoming APDU buffer. byte[] buffer = apdu.getBuffer(); // Get the PIN data. byte bytesRead = (byte)apdu.setIncomingAndReceive();
// Check/verify the PIN number. Read bytesRead number of PIN // bytes into the APDU buffer at the offset // ISO7816.OFFSET_CDATA. if (ownerPin.check(buffer, ISO7816.OFFSET_CDATA, byteRead) == false ) ISOException.throwIt(SW_PINVERIFY_FAILED); }
... byte[] buffer = apdu.getBuffer(); short bytes_left = (short) buffer[ISO.OFFSET_LC]; short readCount = apdu.setIncomingAndReceive(); while (bytes_left > 0) { // Process received data in buffer; copy chunk to temp buf. Util.arrayCopy(buffer, ISO.OFFSET_CDATA, tbuf, 0, readCount); bytes_left -= readCount; // Get more data readCount = apdu.receiveBytes(ISO.OFFSET_CDDATA); } ...
import java.rmi.*; import javacard.framework.*; public interface MyRemoteInterface extends Remote { ... public short getBalance() throws RemoteException; ... // A complete credit card application would also define other // methods such as credit() and debit() methods. ... }
public class MyApplet extends javacard.framework.Applet { private Dispatcher disp; private RemoteService serv; private Remote myRemoteInterface; /** * Construct the applet. Here instantiate the remote * implementation(s), the APDU Dispatcher, and the * RMIService. Before returning, register the applet. */ public MyApplet () { // Create the implementation for my applet. myRemoteInterface = new MyRemoteInterfaceImpl(); // Create a new Dispatcher that can hold a maximum of 1 // service, the RMIService. disp = new Dispatcher((short)1); // Create the RMIService serv = new RMIService(myRemoteInterface); disp.addService(serv, Dispatcher.PROCESS_COMMAND); // Complete the registration process register(); } ...
... /** * Installs the Applet. Creates an instance of MyApplet. * The JCRE calls this static method during applet * installation. * @param bArray install parameter array. * @param bOffset where install data begins. * @param bLength install parameter data length. */ public static void install(byte[] aid, short s, byte b) { new MyApplet(); }
/** * Called by the JCRE to process an incoming APDU command. An * applet is expected to perform the action requested and * return response data, if any. * * This JCRMI version of the applet dispatches remote * invocation APDUs by invoking the Dispatcher. * * Upon normal return from this method the JCRE sends the ISO- * 7816-4-defined success status (90 00) in the APDU response. * If this method throws an ISOException, the JCRE sends the * associated reason code as the response status instead. * @param apdu is the incoming APDU. * @throw ISOException if the install method fails. */ public void process(APDU apdu) throws ISOException { // Dispatch the incoming command APDU to the RMIService. disp.process(apdu); } }
import java.rmi.RemoteException; import javacard.framework.service.CardRemoteObject; import javacard.framework.Util; import javacard.framework.UserException; /** * Provides the implementation for MyRemoteInterface. */ public class MyRemoteImpl extends CardRemoteObject implements MyRemoteInterface { /** The balance. */ private short balance = 0; /** * The Constructor invokes the superclass constructor, * which exports this remote implementation. */ public MyRemoteImpl() { super(); // make this remote object visible } /** * This method returns the balance. * @return the stored balance. * @throws RemoteException if a JCRMI exception is * encountered */ public short getBalance() throws RemoteException { return balance; } // Other methods ... }