aboutsummaryrefslogtreecommitdiff
path: root/src/simpleapdu
diff options
context:
space:
mode:
Diffstat (limited to 'src/simpleapdu')
-rw-r--r--src/simpleapdu/CardMngr.java209
-rw-r--r--src/simpleapdu/ISO7816_status_words.txt71
-rw-r--r--src/simpleapdu/SimpleAPDU.java78
3 files changed, 358 insertions, 0 deletions
diff --git a/src/simpleapdu/CardMngr.java b/src/simpleapdu/CardMngr.java
new file mode 100644
index 0000000..d3ff86b
--- /dev/null
+++ b/src/simpleapdu/CardMngr.java
@@ -0,0 +1,209 @@
+package simpleapdu;
+
+import com.licel.jcardsim.io.CAD;
+import com.licel.jcardsim.io.JavaxSmartCardInterface;
+import java.util.List;
+import javacard.framework.AID;
+import javax.smartcardio.*;
+
+/**
+ *
+ * @author xsvenda
+ */
+public class CardMngr {
+ CardTerminal m_terminal = null;
+ CardChannel m_channel = null;
+ Card m_card = null;
+
+ // Simulator related attributes
+ private static CAD m_cad = null;
+ private static JavaxSmartCardInterface m_simulator = null;
+
+
+ private final byte selectCM[] = {
+ (byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x07, (byte) 0xa0, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x18, (byte) 0x43, (byte) 0x4d};
+
+ public static final byte OFFSET_CLA = 0x00;
+ public static final byte OFFSET_INS = 0x01;
+ public static final byte OFFSET_P1 = 0x02;
+ public static final byte OFFSET_P2 = 0x03;
+ public static final byte OFFSET_LC = 0x04;
+ public static final byte OFFSET_DATA = 0x05;
+ public static final byte HEADER_LENGTH = 0x05;
+ public final static short DATA_RECORD_LENGTH = (short) 0x80; // 128B per record
+ public final static short NUMBER_OF_RECORDS = (short) 0x0a; // 10 records
+
+ public boolean ConnectToCard() throws Exception {
+ // TRY ALL READERS, FIND FIRST SELECTABLE
+ List terminalList = GetReaderList();
+
+ if (terminalList.isEmpty()) {
+ System.out.println("No terminals found");
+ }
+
+ //List numbers of Card readers
+ boolean cardFound = false;
+ for (int i = 0; i < terminalList.size(); i++) {
+ System.out.println(i + " : " + terminalList.get(i));
+ m_terminal = (CardTerminal) terminalList.get(i);
+ if (m_terminal.isCardPresent()) {
+ m_card = m_terminal.connect("*");
+ System.out.println("card: " + m_card);
+ m_channel = m_card.getBasicChannel();
+
+ //reset the card
+ ATR atr = m_card.getATR();
+ System.out.println(bytesToHex(m_card.getATR().getBytes()));
+
+ cardFound = true;
+ }
+ }
+
+ return cardFound;
+ }
+
+ public void DisconnectFromCard() throws Exception {
+ if (m_card != null) {
+ m_card.disconnect(false);
+ m_card = null;
+ }
+ }
+
+ public byte[] GetCPLCData() throws Exception {
+ byte[] data;
+
+ // TODO: Modify to obtain CPLC data
+ byte apdu[] = new byte[HEADER_LENGTH];
+ apdu[OFFSET_CLA] = (byte) 0x00;
+ apdu[OFFSET_INS] = (byte) 0x00;
+ apdu[OFFSET_P1] = (byte) 0x00;
+ apdu[OFFSET_P2] = (byte) 0x00;
+ apdu[OFFSET_LC] = (byte) 0x00;
+
+ ResponseAPDU resp = sendAPDU(apdu);
+ if (resp.getSW() != 0x9000) { // 0x9000 is "OK"
+ System.out.println("Fail to obtain card's response data");
+ data = null;
+ } else {
+ byte temp[] = resp.getBytes();
+ data = new byte[temp.length - 2];
+ System.arraycopy(temp, 0, data, 0, temp.length - 2);
+ // Last two bytes are status word (also obtainable by resp.getSW())
+ // Take a look at ISO7816_status_words.txt for common codes
+ }
+
+ return data;
+ }
+
+ public void ProbeCardCommands() throws Exception {
+ // TODO: modify to probe for instruction
+ for (int i = 0; i <= 0; i++) {
+ byte apdu[] = new byte[HEADER_LENGTH];
+ apdu[OFFSET_CLA] = (byte) 0x00;
+ apdu[OFFSET_INS] = (byte) 0x00;
+ apdu[OFFSET_P1] = (byte) 0x00;
+ apdu[OFFSET_P2] = (byte) 0x00;
+ apdu[OFFSET_LC] = (byte) 0x00;
+
+ ResponseAPDU resp = sendAPDU(apdu);
+
+ System.out.println("Response: " + Integer.toHexString(resp.getSW()));
+
+ if (resp.getSW() != 0x6D00) { // Note: 0x6D00 is SW_INS_NOT_SUPPORTED
+ // something?
+ }
+ }
+ }
+
+ public List GetReaderList() {
+ try {
+ TerminalFactory factory = TerminalFactory.getDefault();
+ List readersList = factory.terminals().list();
+ return readersList;
+ } catch (Exception ex) {
+ System.out.println("Exception : " + ex);
+ return null;
+ }
+ }
+
+ public ResponseAPDU sendAPDU(byte apdu[]) throws Exception {
+ CommandAPDU commandAPDU = new CommandAPDU(apdu);
+
+ System.out.println(">>>>");
+ System.out.println(commandAPDU);
+
+ System.out.println(bytesToHex(commandAPDU.getBytes()));
+
+ long elapsed = -System.nanoTime();
+
+ ResponseAPDU responseAPDU = m_channel.transmit(commandAPDU);
+
+ elapsed += System.nanoTime();
+
+ System.out.println(responseAPDU);
+ System.out.println(bytesToHex(responseAPDU.getBytes()));
+
+ if (responseAPDU.getSW1() == (byte) 0x61) {
+ CommandAPDU apduToSend = new CommandAPDU((byte) 0x00,
+ (byte) 0xC0, (byte) 0x00, (byte) 0x00,
+ (int) responseAPDU.getSW1());
+
+ responseAPDU = m_channel.transmit(apduToSend);
+ System.out.println(bytesToHex(responseAPDU.getBytes()));
+ }
+
+ System.out.println("<<<<");
+ System.out.println("Elapsed time (ms): " + elapsed / 1000000);
+ return (responseAPDU);
+ }
+
+ public String byteToHex(byte data) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(toHexChar((data >>> 4) & 0x0F));
+ buf.append(toHexChar(data & 0x0F));
+ return buf.toString();
+ }
+
+ public char toHexChar(int i) {
+ if ((0 <= i) && (i <= 9)) {
+ return (char) ('0' + i);
+ } else {
+ return (char) ('a' + (i - 10));
+ }
+ }
+
+ public String bytesToHex(byte[] data) {
+ StringBuilder buf = new StringBuilder();
+ for (int i = 0; i < data.length; i++) {
+ buf.append(byteToHex(data[i]));
+ buf.append(" ");
+ }
+ return (buf.toString());
+ }
+
+
+ public boolean prepareLocalSimulatorApplet(byte[] appletAIDArray, byte[] installData, Class appletClass) {
+ System.setProperty("com.licel.jcardsim.terminal.type", "2");
+ m_cad = new CAD(System.getProperties());
+ m_simulator = (JavaxSmartCardInterface) m_cad.getCardInterface();
+ AID appletAID = new AID(appletAIDArray, (short) 0, (byte) appletAIDArray.length);
+
+ AID appletAIDRes = m_simulator.installApplet(appletAID, appletClass, installData, (short) 0, (byte) installData.length);
+ return m_simulator.selectApplet(appletAID);
+ }
+
+ public byte[] sendAPDUSimulator(byte apdu[]) throws Exception {
+ System.out.println(">>>>");
+ System.out.println(bytesToHex(apdu));
+
+ byte[] responseBytes = m_simulator.transmitCommand(apdu);
+
+ System.out.println(bytesToHex(responseBytes));
+ System.out.println("<<<<");
+
+ return responseBytes;
+ }
+
+
+}
diff --git a/src/simpleapdu/ISO7816_status_words.txt b/src/simpleapdu/ISO7816_status_words.txt
new file mode 100644
index 0000000..bf5af2b
--- /dev/null
+++ b/src/simpleapdu/ISO7816_status_words.txt
@@ -0,0 +1,71 @@
+public interface ISO7816 {
+
+ // Fields
+ public static final byte INS_EXTERNAL_AUTHENTICATE = -126;
+ public static final byte INS_SELECT = -92;
+ public static final byte CLA_ISO7816 = 0;
+ public static final byte OFFSET_CDATA = 5;
+ public static final byte OFFSET_LC = 4;
+ public static final byte OFFSET_P2 = 3;
+ public static final byte OFFSET_P1 = 2;
+ public static final byte OFFSET_INS = 1;
+ public static final byte OFFSET_CLA = 0;
+ public static final short SW_FILE_FULL = 27268; 0x6A84
+ public static final short SW_UNKNOWN = 28416; 0x6F00
+ public static final short SW_CLA_NOT_SUPPORTED = 28160; 0x6E00
+ public static final short SW_INS_NOT_SUPPORTED = 27904; 0x6D00
+ public static final short SW_CORRECT_LENGTH_00 = 27648; 0x6C00
+ public static final short SW_WRONG_P1P2 = 27392; 0x6B00
+ public static final short SW_INCORRECT_P1P2 = 27270; 0x6A86
+ public static final short SW_RECORD_NOT_FOUND = 27267; 0x6A83
+ public static final short SW_FILE_NOT_FOUND = 27266; 0x6A82
+ public static final short SW_FUNC_NOT_SUPPORTED = 27265; 0x6A81
+ public static final short SW_WRONG_DATA = 27264; 0x6A80
+ public static final short SW_APPLET_SELECT_FAILED = 27033; 0x6999
+ public static final short SW_COMMAND_NOT_ALLOWED = 27014; 0x6986
+ public static final short SW_CONDITIONS_NOT_SATISFIED = 27013; 0x6985
+ public static final short SW_DATA_INVALID = 27012; 0x6984
+ public static final short SW_FILE_INVALID = 27011; 0x6983
+ public static final short SW_SECURITY_STATUS_NOT_SATISFIED = 27010; 0x6982
+ public static final short SW_WRONG_LENGTH = 26368; 0x6700
+ public static final short SW_BYTES_REMAINING_00 = 24832; 0x6100
+ public static final short SW_NO_ERROR = -28672; 0x9000
+}
+
+public interface JCStatus {
+static int ALGORITHM_NOT_SUPPORTED = 0x9484;
+static int APPLET_INVALIDATED = 0x6283;
+static int APPLET_SELECT_FAILED = 0x6999
+static int AUTHENTICATION_FAILED = 0x6300
+static int AUTHORIZATION_FAILED = 0x9482
+static int CHECKSUM_FAILED = 0x9584
+static int CLA_NOT_SUPPORTED = 0x6E00
+static int COMMAND_NOT_ALLOWED = 0x6986
+static int CONDITIONS_NOT_SATISFIED = 0x6985
+static int CORRECT_LENGTH_00 = 0x6C00
+static int DATA_INVALID = 0x6984
+static int DECRYPTION_FAILED = 0x9583
+static int FILE_FULL = 0x6A84
+static int FILE_INVALID = 0x6983
+static int FILE_NOT_FOUND = 0x6A82
+static int FUNC_NOT_SUPPORTED = 0x6A81
+static int INCORRECT_P1P2 = 0x6A86
+static int INS_NOT_SUPPORTED = 0x6D00
+static int INSTALLATION_FAILED = 0x9585
+static int INVALID_STATE = 0x9481
+static int NO_ERROR = 0x9000
+static int NO_SPECIFIC_DIAGNOSIS = 0x6400
+static int PIN_REQUIRED = 0x6982
+static int RECORD_NOT_FOUND = 0x6A83
+static int REFERENCE_DATA_NOT_FOUND = 0x6A88
+static int REGISTRATION_FAILED = 0x9586
+static int SECURITY_STATUS_NOT_SATISFIED = 0x6982
+static int SIGNATURE_CHECK_FAILED = 0x9582
+static int SM_INCORRECT = 0x6988
+static int SM_MISSING = 0x6987
+static int TRUNCATED_DATA = 0x6100
+static int UNKNOWN = 0x6F00
+static int WRONG_DATA = 0x6A80
+static int WRONG_LENGTH = 0x6700
+static int WRONG_P1P2 = 0x6B00
+} \ No newline at end of file
diff --git a/src/simpleapdu/SimpleAPDU.java b/src/simpleapdu/SimpleAPDU.java
new file mode 100644
index 0000000..240a1cf
--- /dev/null
+++ b/src/simpleapdu/SimpleAPDU.java
@@ -0,0 +1,78 @@
+package simpleapdu;
+
+import applets.SimpleECCApplet;
+import javax.smartcardio.ResponseAPDU;
+
+/**
+ *
+ * @author xsvenda
+ */
+public class SimpleAPDU {
+ static CardMngr cardManager = new CardMngr();
+
+ private static byte DEFAULT_USER_PIN[] = {(byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30};
+ private static byte NEW_USER_PIN[] = {(byte) 0x31, (byte) 0x31, (byte) 0x31, (byte) 0x31};
+ private static byte APPLET_AID[] = {(byte) 0x4C, (byte) 0x61, (byte) 0x62, (byte) 0x61, (byte) 0x6B,
+ (byte) 0x41, (byte) 0x70, (byte) 0x70, (byte) 0x6C, (byte) 0x65, (byte) 0x74};
+ private static byte SELECT_SIMPLEAPPLET[] = {(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x0b,
+ (byte) 0x4C, (byte) 0x61, (byte) 0x62, (byte) 0x61, (byte) 0x6B,
+ (byte) 0x41, (byte) 0x70, (byte) 0x70, (byte) 0x6C, (byte) 0x65, (byte) 0x74};
+
+ private final byte selectCM[] = {
+ (byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x07, (byte) 0xa0, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x18, (byte) 0x43, (byte) 0x4d};
+
+ private static byte GENERATEKEY[] = {(byte) 0xB0, (byte) 0x5A, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00};
+ private static byte RESPONDDATA[] = {(byte) 0xB0, (byte) 0x5B, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x30};
+ public static void main(String[] args) {
+ try {
+ //
+ // SIMULATED CARDS
+ //
+/*
+ // Prepare simulated card
+ byte[] installData = new byte[10]; // no special install data passed now - can be used to pass initial keys etc.
+ cardManager.prepareLocalSimulatorApplet(APPLET_AID, installData, SimpleECCApplet.class);
+
+ // TODO: prepare proper APDU command
+ short additionalDataLen = 0;
+ byte apdu[] = new byte[CardMngr.HEADER_LENGTH + additionalDataLen];
+ apdu[CardMngr.OFFSET_CLA] = (byte) 0xB0;
+ apdu[CardMngr.OFFSET_INS] = (byte) 0x5a;
+ apdu[CardMngr.OFFSET_P1] = (byte) 0x00;
+ apdu[CardMngr.OFFSET_P2] = (byte) 0x00;
+ apdu[CardMngr.OFFSET_LC] = (byte) additionalDataLen;
+
+ // TODO: if additional data are supplied (additionalDataLen != 0), then set proper inpupt here
+
+ // NOTE: we are using sendAPDUSimulator() instead of sendAPDU()
+ byte[] response = cardManager.sendAPDUSimulator(apdu);
+ // TODO: parse response data - status, data
+ response = cardManager.sendAPDUSimulator(apdu);
+
+*/
+
+
+ //
+ // REAL CARDS
+ //
+
+ // TODO: Try same with real card
+ if (cardManager.ConnectToCard()) {
+ // Select our application on card
+ cardManager.sendAPDU(SELECT_SIMPLEAPPLET);
+
+ for (int i = 0; i < 10; i++) {
+ cardManager.sendAPDU(GENERATEKEY);
+ }
+ cardManager.sendAPDU(RESPONDDATA);
+
+ cardManager.DisconnectFromCard();
+ } else {
+ System.out.println("Failed to connect to card");
+ }
+ } catch (Exception ex) {
+ System.out.println("Exception : " + ex);
+ }
+ }
+}