一個 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 ... }