Quick Start Guide: Simulator API

jCardSim was originally developed for a fast prototyping of the Java Card applications, and writing unit-tests.

There are two ways to use the simulator:

  • Using of Simulator API
  • Using the javax.smartcardio for an interaction with JavaCard

In both cases it is possible to interact with a remote instance of jCardSim. For example you may run one or multiple instances of virtual Java Card and connect to it via TCP/IP.
Using Simulator API's methods
The main interface for working with simulator is com.licel.jcardsim.io.JavaCardInterface, its specification available here. In order to get its implementation use com.licel.jcardsim.io.CAD.

At first it is necessary to set connection parameters:

// 0 - Local Mode
// 1 - Remote Mode
// 2 - Local Mode with ResponseAPDU transmitCommand(CommandAPDU) method
System.setProperty("com.licel.jcardsim.terminal.type", "2");
CAD cad = new CAD(System.getProperties());

Create connection:

JavaxSmartCardInterface simulator = (JavaxSmartCardInterface) cad.getCardInterface();

Next, installing an applet:

simulator.installApplet(appletAID, HelloWorldApplet.class);

Selecting:

simulator.selectApplet(appletAID);

Sending an APDU command:

ResponseAPDU response = simulator.transmitCommand(new CommandAPDU(0x01, 0x01, 0x00, 0x00));

And check a result of the execution:

assertEquals(0x9000, response.getSW());

The example of how to work with HelloWorldApplet (from first part of Quick Start Guide: Using in CLI mode):

System.setProperty("com.licel.jcardsim.terminal.type", "2");
CAD cad = new CAD(System.getProperties());
JavaxSmartCardInterface simulator = (JavaxSmartCardInterface) cad.getCardInterface();
byte[] appletAIDBytes = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
AID appletAID = new AID(appletAIDBytes, (short) 0, (byte) appletAIDBytes.length);
simulator.installApplet(appletAID, HelloWorldApplet.class);
simulator.selectApplet(appletAID);
// test NOP
ResponseAPDU response = simulator.transmitCommand(new CommandAPDU(0x01, 0x02, 0x00, 0x00));
assertEquals(0x9000, response.getSW());
// test hello world from card
response = simulator.transmitCommand(new CommandAPDU(0x01, 0x01, 0x00, 0x00));
assertEquals(0x9000, response.getSW());
assertEquals("Hello world !", new String(response.getData()));
// test echo
response = simulator.transmitCommand(new CommandAPDU(0x01, 0x01, 0x01, 0x00, ("Hello javacard world !").getBytes()));
assertEquals(0x9000, response.getSW());
assertEquals("Hello javacard world !", new String(response.getData()));

Using javax.smartcardio for an interaction with JavaCard
For ease of writing Unit tests for an applications which use javax.smartcardio, we have the provider for Java Card Terminal's emulation in jCardSim.

The complete example can be found at JCardSimProviderTest.java

To use it you have to register jCardSim TerminalFactory Provider:

if (Security.getProvider("jCardSim") == null) {
       JCardSimProvider provider = new JCardSimProvider();
       Security.addProvider(provider);
}

Choose terminal:

TerminalFactory tf = TerminalFactory.getInstance("jCardSim", null);
CardTerminals ct = tf.terminals();
List<CardTerminal> list = ct.list();
CardTerminal jcsTerminal = null;
for (int i = 0; i < list.size(); i++) {
     if (list.get(i).getName().equals("jCardSim.Terminal")) {
         jcsTerminal = list.get(i);
         break;
      }
}

Then, you can use javax.smartcardio API.
Note: Pre-installed applets can be configured using system properties: System.setProperty(...), the format is equal with configuration file of the CLI mode of jCardSim.

Example of how to work with HelloWorldApplet:

String TEST_APPLET_AID = "010203040506070809";
System.setProperty("com.licel.jcardsim.applet.0.AID", TEST_APPLET_AID);
System.setProperty("com.licel.jcardsim.applet.0.Class", "com.licel.jcardsim.samples.HelloWorldApplet");
if (Security.getProvider("jCardSim") == null) {
      JCardSimProvider provider = new JCardSimProvider();
       Security.addProvider(provider);
}
TerminalFactory tf = TerminalFactory.getInstance("jCardSim", null);
CardTerminals ct = tf.terminals();
List<CardTerminal> list = ct.list();
CardTerminal jcsTerminal = null;
for (int i = 0; i < list.size(); i++) {
     if (list.get(i).getName().equals("jCardSim.Terminal")) {
           jcsTerminal = list.get(i);
          break;
      }
}
Card jcsCard = jcsTerminal.connect("T=0");
CardChannel jcsChannel = jcsCard.getBasicChannel();
// create applet data = aid len (byte), aid bytes, params lenth (byte), param
byte[] aidBytes = Hex.decode(TEST_APPLET_AID);
byte[] createData = new byte[1+aidBytes.length+1];
createData[0] = (byte) aidBytes.length;
System.arraycopy(aidBytes, 0, createData, 1, aidBytes.length);
CommandAPDU createApplet = new CommandAPDU(0x80, 0xb8, 0, 0, createData);
ResponseAPDU response = jcsChannel.transmit(createApplet);
assertEquals(response.getSW(), 0x9000);
assertEquals(true, Arrays.equals(response.getData(), aidBytes));
// select applet
CommandAPDU selectApplet = new CommandAPDU(ISO7816.CLA_ISO7816, ISO7816.INS_SELECT, 0, 0, Hex.decode(TEST_APPLET_AID));
response = jcsChannel.transmit(selectApplet);
assertEquals(response.getSW(), 0x9000);
// test NOP
response = jcsChannel.transmit(new CommandAPDU(0x01, 0x02, 0x00, 0x00));
assertEquals(0x9000, response.getSW());
// test hello world from card
response = jcsChannel.transmit(new CommandAPDU(0x01, 0x01, 0x00, 0x00));
assertEquals(0x9000, response.getSW());
assertEquals("Hello world !", new String(response.getData()));
// test echo
response = jcsChannel.transmit(new CommandAPDU(0x01, 0x01, 0x01, 0x00, ("Hello javacard world !").getBytes()));
assertEquals(0x9000, response.getSW());
assertEquals("Hello javacard world !", new String(response.getData()));

Current version's limitations: The openLogicalChannel() method always returns the basicChannel.