Quick Start Guide: Simulator API

Использование Simulator API.

jCardSim изначально разрабатывался для быстрого прототипирования Java Card приложений и написания unit-тестов. Поэтому использовать его API достаточно просто и удобно.
Возможны два варианта использования симулятора:

  • Использование методов Simulator API
  • Взаимодействие с виртуальной Java Card через javax.smartcardio

В обоих случаях возможно использование клиент-серверного взаимодействия. В этом случае возможен запуск одного или нескольких экземпляров виртуальной Java Card и подключение к ним по протоколу TCP/IP.

Использование методов Simulator API
Основной интерфейс для работы с симулятором com.licel.jcardsim.io.JavaCardInterface, его описание доступно по ссылке: JavaCardInterface.html. Для его получения необходимо использовать класс com.licel.jcardsim.io.CAD.

Вначале необходимо задать параметры подключения к Java Card

// 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());

Создать подключение

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

Затем установить апплет

simulator.installApplet(appletAID, HelloWorldApplet.class);

Выбрать апплет

simulator.selectApplet(appletAID);

Послать APDU-команду

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

Проверить результат исполнения

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

Пример работы с HelloWorldApplet из первой части 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()));

Взаимодействие с виртуальной Java Card через javax.smartcardio
Для удобства написания unit-тестов приложений использующих javax.smartcardio в jCardSim реализован провайдер для эмуляции работы Java Card Terminal.

Полный пример можно найти по ссылке: JCardSimProviderTest.java

Чтобы подключить его, необходимо зарегистрировать jCardSim TerminalFactory Provider

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;
      }
}

И дальше использовать javax.smartcardio API.
Примечание:Предустановленные апплеты, конфигурируются установкой системных свойств System.setProperty(...), формат аналогичен конфигурационному
файлу консольного режима использования симулятора.

Пример работы с HelloWorldApplet из первой части Quick Start Guide

String TEST_APPLET_AID = "010203040506070809";
System.setProperty("com.licel.jcardsim.card.applet.0.AID", TEST_APPLET_AID);
System.setProperty("com.licel.jcardsim.card.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()));

Ограничения текущей версии В текущей версии при вызове метода openLogicalChannel() всегда возвращается основной канал (basicChannel).