diff options
| -rw-r--r-- | !uploader/simpleECC.cap | bin | 9542 -> 9854 bytes | |||
| -rw-r--r-- | dist/SimpleAPDU.jar | bin | 47118 -> 52783 bytes | |||
| -rw-r--r-- | src/applets/EC_Consts.java | 3 | ||||
| -rw-r--r-- | src/applets/SimpleECCApplet.java | 88 | ||||
| -rw-r--r-- | src/simpleapdu/CardMngr.java | 67 | ||||
| -rw-r--r-- | src/simpleapdu/DirtyLogger.java | 50 | ||||
| -rw-r--r-- | src/simpleapdu/SimpleAPDU.java | 123 |
7 files changed, 266 insertions, 65 deletions
diff --git a/!uploader/simpleECC.cap b/!uploader/simpleECC.cap Binary files differindex ee8fefd..9d36664 100644 --- a/!uploader/simpleECC.cap +++ b/!uploader/simpleECC.cap diff --git a/dist/SimpleAPDU.jar b/dist/SimpleAPDU.jar Binary files differindex c1fcaba..3a13dc6 100644 --- a/dist/SimpleAPDU.jar +++ b/dist/SimpleAPDU.jar diff --git a/src/applets/EC_Consts.java b/src/applets/EC_Consts.java index b7128dc..b607921 100644 --- a/src/applets/EC_Consts.java +++ b/src/applets/EC_Consts.java @@ -9,6 +9,9 @@ import javacard.security.KeyPair; import javacard.security.RandomData; public class EC_Consts { + public static final byte TAG_ECPUBKEY = (byte) 0x41; + public static final byte TAG_ECPRIVKEY = (byte) 0x42; + public static byte[] EC_FP_P = null; public static byte[] EC_FP_A = null; public static byte[] EC_FP_B = null; diff --git a/src/applets/SimpleECCApplet.java b/src/applets/SimpleECCApplet.java index 720ee4e..18eec5a 100644 --- a/src/applets/SimpleECCApplet.java +++ b/src/applets/SimpleECCApplet.java @@ -27,6 +27,8 @@ public class SimpleECCApplet extends javacard.framework.Applet final static byte INS_TESTEC_LASTUSEDPARAMS = (byte) 0x40; + public final static byte P1_SETCURVE = (byte) 0x01; + public final static byte P1_GENERATEKEYPAIR = (byte) 0x02; final static short ARRAY_LENGTH = (short) 0xff; @@ -192,10 +194,10 @@ public class SimpleECCApplet extends javacard.framework.Applet case INS_ALLOCATEKEYPAIRS: AllocateKeyPairs(apdu); break; +*/ case INS_GENERATEKEY: - GenerateKey(apdu); + GenerateAndReturnKey(apdu); break; -*/ default : // The INS code is not supported by the dispatcher ISOException.throwIt( ISO7816.SW_INS_NOT_SUPPORTED ) ; @@ -741,7 +743,7 @@ public class SimpleECCApplet extends javacard.framework.Applet short bitLen = Util.getShort(apdubuf, ISO7816.OFFSET_CDATA); - // Note: all locations shoudl happen in constructor. But here it is intentional + // Note: all locations should happen in constructor. But here it is intentional // as we like to test for result of allocation ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, bitLen); @@ -827,7 +829,64 @@ public class SimpleECCApplet extends javacard.framework.Applet apdu.setOutgoingAndSend((short) 0, secretLen); } - + void GenerateAndReturnKey(APDU apdu) { + byte[] apdubuf = apdu.getBuffer(); + apdu.setIncomingAndReceive(); + + short bitLen = Util.getShort(apdubuf, ISO7816.OFFSET_CDATA); + + short offset = 0; + + switch (apdubuf[ISO7816.OFFSET_P1]) { + case P1_SETCURVE: { + ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, bitLen); + + ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); + ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); + // Some implementation wil not return valid pub key until ecKeyPair.genKeyPair() is called + // Other implementation will fail with exception if same is called => try catch + try { + if (ecPubKey == null) { + ecKeyPair.genKeyPair(); + } + } catch (Exception e) { + } // do nothing + + // If required, initialize curve parameters first + EC_Consts.setValidECKeyParams(ecPubKey, ecPrivKey, KeyPair.ALG_EC_FP, bitLen, m_ramArray); + + break; + } + case P1_GENERATEKEYPAIR: { + // Assumption: proper EC keyPair is already allocated and initialized + ecKeyPair.genKeyPair(); + ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); + ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); + + offset = 0; + apdubuf[offset] = EC_Consts.TAG_ECPUBKEY; + offset++; + offset += 2; // reserve space for length + short len = ecPubKey.getW(apdubuf, offset); + Util.setShort(apdubuf, (short) (offset - 2), len); + offset += len; + apdubuf[offset] = EC_Consts.TAG_ECPRIVKEY; + offset++; + offset += 2; // reserve space for length + len = ecPrivKey.getS(apdubuf, offset); + Util.setShort(apdubuf, (short) (offset - 2), len); + offset += len; + + break; + } + default: + ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); + } + + + + apdu.setOutgoingAndSend((short) 0, offset); + } @@ -891,28 +950,7 @@ public class SimpleECCApplet extends javacard.framework.Applet EC_Consts.setValidECKeyParams(ecPubKey, ecPrivKey, KeyPair.ALG_EC_FP, bitLen, m_ramArray); } - void GenerateAndReturnKey(APDU apdu) { - byte[] apdubuf = apdu.getBuffer(); - apdu.setIncomingAndReceive(); - - // Assumption: proper EC keyPair is already allocated and initialized - - ecKeyPair.genKeyPair(); - ecPubKey = (ECPublicKey) ecKeyPair.getPrivate(); - ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); - - short offset = 0; - offset += 2; // reserve space for length - short len = ecPubKey.getW(apdubuf, offset); - Util.setShort(apdubuf, (short) (offset - 2), len); - offset += len; - offset += 2; // reserve space for length - len = ecPrivKey.getS(apdubuf, offset); - Util.setShort(apdubuf, (short) (offset - 2), len); - offset += len; - apdu.setOutgoingAndSend((short) 0, offset); - } */ } diff --git a/src/simpleapdu/CardMngr.java b/src/simpleapdu/CardMngr.java index 1ab6408..d778bc8 100644 --- a/src/simpleapdu/CardMngr.java +++ b/src/simpleapdu/CardMngr.java @@ -3,6 +3,7 @@ package simpleapdu; import com.licel.jcardsim.io.CAD; import com.licel.jcardsim.io.JavaxSmartCardInterface; import java.util.List; +import java.util.Scanner; import javacard.framework.AID; import javax.smartcardio.*; @@ -11,9 +12,9 @@ import javax.smartcardio.*; * @author xsvenda */ public class CardMngr { - CardTerminal m_terminal = null; - CardChannel m_channel = null; - Card m_card = null; + static CardTerminal m_terminal = null; + static CardChannel m_channel = null; + static Card m_card = null; // Simulator related attributes private static CAD m_cad = null; @@ -62,6 +63,49 @@ public class CardMngr { return cardFound; } + + static boolean ConnectToCardSelect() throws CardException { + // Test available card - if more present, let user to select one + List<CardTerminal> terminalList = CardMngr.GetReaderList(); + if (terminalList.isEmpty()) { + System.out.println("ERROR: No suitable reader with card detected. Please check your reader connection"); + return false; + } else { + if (terminalList.size() == 1) { + m_terminal = terminalList.get(0); // return first and only reader + } else { + int terminalIndex = 1; + // Let user select target terminal + for (CardTerminal terminal : terminalList) { + Card card; + try { + card = terminal.connect("*"); + ATR atr = card.getATR(); + System.out.println(terminalIndex + " : " + terminal.getName() + " - " + CardMngr.bytesToHex(atr.getBytes())); + terminalIndex++; + } catch (CardException ex) { + System.out.println(ex); + } + } + System.out.print("Select index of target reader you like to use 1.." + (terminalIndex - 1) + ": "); + Scanner sc = new Scanner(System.in); + int answ = sc.nextInt(); + System.out.println(String.format("%d", answ)); + answ--; // is starting with 0 + // BUGBUG; verify allowed index range + m_terminal = terminalList.get(answ); + } + } + + if (m_terminal != null) { + m_card = m_terminal.connect("*"); + System.out.println("card: " + m_card); + m_channel = m_card.getBasicChannel(); + } + + return true; + } + public void DisconnectFromCard() throws Exception { if (m_card != null) { @@ -116,7 +160,7 @@ public class CardMngr { } } - public List GetReaderList() { + public static List GetReaderList() { try { TerminalFactory factory = TerminalFactory.getDefault(); List readersList = factory.terminals().list(); @@ -158,7 +202,7 @@ public class CardMngr { return (responseAPDU); } - public String byteToHex(byte data) { + public static String byteToHex(byte data) { StringBuilder buf = new StringBuilder(); buf.append(toHexChar((data >>> 4) & 0x0F)); buf.append(toHexChar(data & 0x0F)); @@ -166,7 +210,7 @@ public class CardMngr { } - public char toHexChar(int i) { + public static char toHexChar(int i) { if ((0 <= i) && (i <= 9)) { return (char) ('0' + i); } else { @@ -174,16 +218,19 @@ public class CardMngr { } } - public String bytesToHex(byte[] data) { + public static String bytesToHex(byte[] data) { + return bytesToHex(data, 0, data.length, true); + } + + public static String bytesToHex(byte[] data, int offset, int len, boolean bAddSpace) { StringBuilder buf = new StringBuilder(); - for (int i = 0; i < data.length; i++) { + for (int i = offset; i < (offset + len); i++) { buf.append(byteToHex(data[i])); - buf.append(" "); + if (bAddSpace) { 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()); diff --git a/src/simpleapdu/DirtyLogger.java b/src/simpleapdu/DirtyLogger.java new file mode 100644 index 0000000..69e5e65 --- /dev/null +++ b/src/simpleapdu/DirtyLogger.java @@ -0,0 +1,50 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package simpleapdu; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author xsvenda + */ +public class DirtyLogger { + FileOutputStream m_logFile; + boolean m_bOutputSystemOut = true; + public DirtyLogger(FileOutputStream logFile, boolean bOutputSystemOut) { + m_logFile = logFile; + m_bOutputSystemOut = bOutputSystemOut; + } + public void println() { + String logLine = "\n"; + print(logLine); + } + public void println(String logLine) { + logLine += "\n"; + print(logLine); + } + public void print(String logLine) { + if (m_bOutputSystemOut) { + System.out.print(logLine); + } + if (m_logFile != null) { + try { + m_logFile.write(logLine.getBytes()); + } catch (IOException ex) { + } + } + } + + void flush() { + try { + m_logFile.flush(); + } catch (IOException ex) { + } + } +} diff --git a/src/simpleapdu/SimpleAPDU.java b/src/simpleapdu/SimpleAPDU.java index 0ea9ca3..575f562 100644 --- a/src/simpleapdu/SimpleAPDU.java +++ b/src/simpleapdu/SimpleAPDU.java @@ -1,13 +1,15 @@ package simpleapdu; +import applets.EC_Consts; import applets.SimpleECCApplet; -import static applets.SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_CUSTOMCURVE; -import static applets.SimpleECCApplet.ECTEST_SET_INVALIDCURVE; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; import javacard.framework.ISO7816; import javacard.security.CryptoException; import javacard.security.KeyPair; import javax.smartcardio.ResponseAPDU; -import org.bouncycastle.util.Arrays; /** * @@ -15,7 +17,8 @@ import org.bouncycastle.util.Arrays; */ public class SimpleAPDU { static CardMngr cardManager = new CardMngr(); - + static DirtyLogger m_SystemOutLogger = null; + private final static byte SELECT_ECTESTERAPPLET[] = {(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x0a, (byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x31}; @@ -32,6 +35,8 @@ public class SimpleAPDU { private static final short INVALIDCURVEB_CORRUPTIONTYPE_OFFSET = 7; private static final short INVALIDCURVEB_REWINDONSUCCESS_OFFSET = 9; + private static final byte TESTECSUPPORT_GENERATEECCKEY[] = {(byte) 0xB0, (byte) 0x5a, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00}; + static short getShort(byte[] array, int offset) { return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF)); } @@ -64,7 +69,7 @@ public class SimpleAPDU { PrintECSupport(resp); } static void testSupportECAll(CardMngr cardManager) throws Exception { - byte[] testAPDU = Arrays.clone(TESTECSUPPORT_GIVENALG); + byte[] testAPDU = Arrays.copyOf(TESTECSUPPORT_GIVENALG, TESTECSUPPORT_GIVENALG.length); testAPDU[TESTECSUPPORT_ALG_OFFSET] = KeyPair.ALG_EC_FP; setShort(testAPDU, TESTECSUPPORT_KEYLENGTH_OFFSET, (short) 128); @@ -93,17 +98,73 @@ public class SimpleAPDU { testSupportECGivenAlg(testAPDU, cardManager); } - public static void main(String[] args) { + public static void main(String[] args) throws FileNotFoundException, IOException { + String logFileName = String.format("ECTESTER_log_%d.log", System.currentTimeMillis()); + FileOutputStream systemOutLogger = new FileOutputStream(logFileName); + m_SystemOutLogger = new DirtyLogger(systemOutLogger, true); + try { - // - // REAL CARDS - // - if (cardManager.ConnectToCard()) { + // Gather large number of ECC keypairs + if (cardManager.ConnectToCardSelect()) { + cardManager.sendAPDU(SELECT_ECTESTERAPPLET); + + String keyFileName = String.format("ECKEYS_%d.log", System.currentTimeMillis()); + FileOutputStream keysFile = new FileOutputStream(keyFileName); + + String message = "index;pubW;privS\n"; + keysFile.write(message.getBytes()); + byte[] gatherKeyAPDU = Arrays.copyOf(TESTECSUPPORT_GENERATEECCKEY, TESTECSUPPORT_GENERATEECCKEY.length); + // Prepare keypair object + gatherKeyAPDU[ISO7816.OFFSET_P1] = SimpleECCApplet.P1_SETCURVE; + setShort(gatherKeyAPDU, (short) 5, (short) 192); // ecc length + ResponseAPDU respGather = cardManager.sendAPDU(gatherKeyAPDU); + // Generate new keypair + gatherKeyAPDU[ISO7816.OFFSET_P1] = SimpleECCApplet.P1_GENERATEKEYPAIR; + int counter = 0; + while (true) { + counter++; + long elapsed = -System.nanoTime(); + respGather = cardManager.sendAPDU(gatherKeyAPDU); + elapsed += System.nanoTime(); + + byte[] data = respGather.getData(); + int offset = 0; + String pubKeyW = ""; + String privKeyS = ""; + if (data[offset] == EC_Consts.TAG_ECPUBKEY) { + offset++; + short len = getShort(data, offset); + offset += 2; + pubKeyW = CardMngr.bytesToHex(data, offset, len, false); + offset += len; + } + if (data[offset] == EC_Consts.TAG_ECPRIVKEY) { + offset++; + short len = getShort(data, offset); + offset += 2; + privKeyS = CardMngr.bytesToHex(data, offset, len, false); + offset += len; + } + + message = String.format("%d;%d;%s;%s\n", counter, elapsed / 1000000, pubKeyW, privKeyS); + keysFile.write(message.getBytes()); + + m_SystemOutLogger.flush(); + keysFile.flush(); + } + } + + if (cardManager.ConnectToCard()) { + byte[] testAPDU2 = Arrays.copyOf(TESTECSUPPORT_GIVENALG, TESTECSUPPORT_GIVENALG.length); + testAPDU2[TESTECSUPPORT_ALG_OFFSET] = KeyPair.ALG_EC_FP; + setShort(testAPDU2, TESTECSUPPORT_KEYLENGTH_OFFSET, (short) 384); + testSupportECGivenAlg(testAPDU2, cardManager); + testSupportECAll(cardManager); // Test setting invalid parameter B of curve - byte[] testAPDU = Arrays.clone(TESTECSUPPORTALL_FP_KEYGEN_INVALIDCURVEB); + byte[] testAPDU = Arrays.copyOf(TESTECSUPPORTALL_FP_KEYGEN_INVALIDCURVEB, TESTECSUPPORTALL_FP_KEYGEN_INVALIDCURVEB.length); //testFPkeyGen_setCorruptionType(testAPDU, SimpleECCApplet.CORRUPT_B_LASTBYTEINCREMENT); testFPkeyGen_setCorruptionType(testAPDU, SimpleECCApplet.CORRUPT_B_ONEBYTERANDOM); //testFPkeyGen_setCorruptionType(testAPDU, SimpleECCApplet.CORRUPT_B_FULLRANDOM); @@ -127,11 +188,13 @@ public class SimpleAPDU { cardManager.DisconnectFromCard(); } else { - System.out.println("Failed to connect to card"); + m_SystemOutLogger.println("Failed to connect to card"); } } catch (Exception ex) { - System.out.println("Exception : " + ex); + m_SystemOutLogger.println("Exception : " + ex); } + + systemOutLogger.close(); } static String getPrintError(short code) { @@ -175,11 +238,11 @@ public class SimpleAPDU { } static int VerifyPrintResult(String message, byte expectedTag, byte[] buffer, int bufferOffset, ExpResult expRes) { if (bufferOffset >= buffer.length) { - System.out.println(" No more data returned"); + m_SystemOutLogger.println(" No more data returned"); } else { if (buffer[bufferOffset] != expectedTag) { - System.out.println(" ERROR: mismatched tag"); + m_SystemOutLogger.println(" ERROR: mismatched tag"); assert(buffer[bufferOffset] == expectedTag); } bufferOffset++; @@ -194,10 +257,10 @@ public class SimpleAPDU { bHiglight = true; } if (bHiglight) { - System.out.println(String.format("!! %-50s%s", message, getPrintError(resCode))); + m_SystemOutLogger.println(String.format("!! %-50s%s", message, getPrintError(resCode))); } else { - System.out.println(String.format(" %-50s%s", message, getPrintError(resCode))); + m_SystemOutLogger.println(String.format(" %-50s%s", message, getPrintError(resCode))); } } return bufferOffset; @@ -205,8 +268,8 @@ public class SimpleAPDU { static void PrintECSupport(ResponseAPDU resp) { byte[] buffer = resp.getData(); - System.out.println(); - System.out.println("### Test for support and with valid and invalid EC curves"); + m_SystemOutLogger.println(); + m_SystemOutLogger.println("### Test for support and with valid and invalid EC curves"); int bufferOffset = 0; while (bufferOffset < buffer.length) { assert(buffer[bufferOffset] == SimpleECCApplet.ECTEST_SEPARATOR); @@ -218,10 +281,10 @@ public class SimpleAPDU { if (buffer[bufferOffset] == KeyPair.ALG_EC_F2M) { ecType = "ALG_EC_F2M"; } - System.out.println(String.format("%-53s%s", "EC type:", ecType)); + m_SystemOutLogger.println(String.format("%-53s%s", "EC type:", ecType)); bufferOffset++; short keyLen = getShort(buffer, bufferOffset); - System.out.println(String.format("%-53s%d bits", "EC key length (bits):", keyLen)); + m_SystemOutLogger.println(String.format("%-53s%d bits", "EC key length (bits):", keyLen)); bufferOffset += 2; bufferOffset = VerifyPrintResult("KeyPair object allocation:", SimpleECCApplet.ECTEST_ALLOCATE_KEYPAIR, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD); @@ -233,14 +296,14 @@ public class SimpleAPDU { bufferOffset = VerifyPrintResult("Set invalid custom curve (may fail):", SimpleECCApplet.ECTEST_SET_INVALIDCURVE, buffer, bufferOffset, ExpResult.MAY_FAIL); bufferOffset = VerifyPrintResult("Generate key with invalid curve (fail is good):", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE, buffer, bufferOffset, ExpResult.MUST_FAIL); - System.out.println(); + m_SystemOutLogger.println(); } } static void PrintECKeyGenInvalidCurveB(ResponseAPDU resp) { byte[] buffer = resp.getData(); - System.out.println(); - System.out.println("### Test for computation with invalid parameter B for EC curve"); + m_SystemOutLogger.println(); + m_SystemOutLogger.println("### Test for computation with invalid parameter B for EC curve"); int bufferOffset = 0; while (bufferOffset < buffer.length) { assert (buffer[bufferOffset] == SimpleECCApplet.ECTEST_SEPARATOR); @@ -252,15 +315,15 @@ public class SimpleAPDU { if (buffer[bufferOffset] == KeyPair.ALG_EC_F2M) { ecType = "ALG_EC_F2M"; } - System.out.println(String.format("%-53s%s", "EC type:", ecType)); + m_SystemOutLogger.println(String.format("%-53s%s", "EC type:", ecType)); bufferOffset++; short keyLen = getShort(buffer, bufferOffset); - System.out.println(String.format("%-53s%d bits", "EC key length (bits):", keyLen)); + m_SystemOutLogger.println(String.format("%-53s%d bits", "EC key length (bits):", keyLen)); bufferOffset += 2; short numRepeats = getShort(buffer, bufferOffset); bufferOffset += 2; - System.out.println(String.format("%-53s%d times", "Executed repeats before unexpected error: ", numRepeats)); + m_SystemOutLogger.println(String.format("%-53s%d times", "Executed repeats before unexpected error: ", numRepeats)); bufferOffset = VerifyPrintResult("KeyPair object allocation:", SimpleECCApplet.ECTEST_ALLOCATE_KEYPAIR, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD); @@ -274,16 +337,16 @@ public class SimpleAPDU { bufferOffset = VerifyPrintResult("Generate key with valid curve:", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_CUSTOMCURVE, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD); } - System.out.println(); + m_SystemOutLogger.println(); } } static void PrintECKeyGenInvalidCurveB_lastUserParams(ResponseAPDU resp) { byte[] buffer = resp.getData(); short offset = 0; - System.out.print("Last used value of B: "); + m_SystemOutLogger.print("Last used value of B: "); while (offset < buffer.length) { - System.out.print(String.format("%x ", buffer[offset])); + m_SystemOutLogger.print(String.format("%x ", buffer[offset])); offset++; } |
