diff options
Diffstat (limited to 'src/simpleapdu')
| -rw-r--r-- | src/simpleapdu/CardMngr.java | 209 | ||||
| -rw-r--r-- | src/simpleapdu/ISO7816_status_words.txt | 71 | ||||
| -rw-r--r-- | src/simpleapdu/SimpleAPDU.java | 78 |
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); + } + } +} |
