From dd620345feba56c413fcba1376c8a536033940b6 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 13 Mar 2019 17:50:56 +0100 Subject: Add custom command chaining to be able to test T=0 cards. --- src/cz/crcs/ectester/applet/ECTesterAppletExtended.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cz/crcs/ectester/applet/ECTesterAppletExtended.java') diff --git a/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java index 83e0851..8ddfeb9 100644 --- a/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java +++ b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java @@ -1,6 +1,6 @@ /* * ECTester, tool for testing Elliptic curve cryptography implementations. - * Copyright (c) 2016-2018 Petr Svenda + * Copyright (c) 2016-2019 Petr Svenda * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal -- cgit v1.2.3-70-g09d2 From f3accb655d349bb6d78fdc3c66a5d2d0cd15731d Mon Sep 17 00:00:00 2001 From: J08nY Date: Thu, 14 Mar 2019 13:38:22 +0100 Subject: Add better chunking support and detect it at runtime. --- build-applet.xml | 7 ++++--- src/cz/crcs/ectester/applet/AppletBase.java | 9 ++++++--- src/cz/crcs/ectester/applet/ECTesterApplet.java | 2 +- .../ectester/applet/ECTesterAppletExtended.java | 2 +- src/cz/crcs/ectester/reader/CardMngr.java | 13 ++++++++++--- src/cz/crcs/ectester/reader/ECTesterReader.java | 21 +++++++++++++-------- 6 files changed, 35 insertions(+), 19 deletions(-) (limited to 'src/cz/crcs/ectester/applet/ECTesterAppletExtended.java') diff --git a/build-applet.xml b/build-applet.xml index 84d399a..d74af6d 100644 --- a/build-applet.xml +++ b/build-applet.xml @@ -16,7 +16,8 @@ - + + @@ -43,7 +44,7 @@ - + @@ -51,7 +52,7 @@ - + diff --git a/src/cz/crcs/ectester/applet/AppletBase.java b/src/cz/crcs/ectester/applet/AppletBase.java index 94f790b..31ddbd9 100644 --- a/src/cz/crcs/ectester/applet/AppletBase.java +++ b/src/cz/crcs/ectester/applet/AppletBase.java @@ -97,10 +97,13 @@ public abstract class AppletBase extends Applet { // go to proprietary data dataOffset++; */ + short resetMemory = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_RESET); + short deselectMemory = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT); + byte memoryType = (resetMemory > deselectMemory) ? JCSystem.CLEAR_ON_RESET : JCSystem.CLEAR_ON_DESELECT; - ramArray = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET); - ramArray2 = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET); - apduArray = JCSystem.makeTransientByteArray(APDU_MAX_LENGTH, JCSystem.CLEAR_ON_RESET); + ramArray = JCSystem.makeTransientByteArray(ARRAY_LENGTH, memoryType); + ramArray2 = JCSystem.makeTransientByteArray(ARRAY_LENGTH, memoryType); + apduArray = JCSystem.makeTransientByteArray(APDU_MAX_LENGTH, memoryType); randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM); EC_Consts.randomData = randomData; diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index 95009aa..b222d46 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -22,7 +22,7 @@ */ /* * PACKAGEID: 4543546573746572 - * APPLETID: 45435465737465723031 + * APPLETID: 454354657374657230333262 // VERSION v0.3.2 */ package cz.crcs.ectester.applet; diff --git a/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java index 8ddfeb9..c31544a 100644 --- a/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java +++ b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java @@ -22,7 +22,7 @@ */ /* * PACKAGEID: 4543546573746572 - * APPLETID: 45435465737465723031 + * APPLETID: 454354657374657230333278 // VERSION v0.3.2 */ package cz.crcs.ectester.applet; diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index 5479f31..abbc440 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -23,7 +23,7 @@ public class CardMngr { private boolean simulate = false; private boolean verbose = true; - private boolean extendedLength = false; + private boolean chunking = false; private final byte[] selectCM = { (byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x07, (byte) 0xa0, (byte) 0x00, (byte) 0x00, @@ -59,6 +59,9 @@ public class CardMngr { if (verbose) System.out.println("T=1 failed, trying protocol '*'"); card = terminal.connect("*"); + if (card.getProtocol().equals("T=0")) { + chunking = true; + } } } @@ -176,6 +179,10 @@ public class CardMngr { } } + public void setChunking(boolean state) { + chunking = state; + } + // Functions for CPLC taken and modified from https://github.com/martinpaljak/GlobalPlatformPro private static final byte CLA_GP = (byte) 0x80; private static final byte ISO7816_INS_GET_DATA = (byte) 0xCA; @@ -330,7 +337,7 @@ public class CardMngr { } long elapsed; - if (card.getProtocol().equals("T=0") && apdu.getNc() >= 0xff) { + if (chunking && apdu.getNc() >= 0xff) { if (verbose) { System.out.print("Chunking:"); } @@ -407,7 +414,7 @@ public class CardMngr { } /* - if (apdu.getNc() >= 0xff) { + if (chunking && apdu.getNc() >= 0xff) { byte[] data = apdu.getBytes(); int numChunks = (data.length + 254) / 255; for (int i = 0; i < numChunks; ++i) { diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 9447814..ab21cd9 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -81,9 +81,9 @@ public class ECTesterReader { private static String CLI_HEADER; private static String CLI_FOOTER = "\n" + LICENSE; - private static final 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}; - private static final byte[] AID = {(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x31}; + private static final byte[] SELECT_PREFIX = {(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x0c}; + private static final byte[] AID_221 = {(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x33, (byte) 0x32, (byte) 0x62}; // VERSION v0.3.2 + private static final byte[] AID_222 = {(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x33, (byte) 0x32, (byte) 0x78}; // VERSION v0.3.2 private static final byte[] INSTALL_DATA = new byte[10]; static { @@ -137,7 +137,7 @@ public class ECTesterReader { //connect or simulate connection if (cfg.simulate) { - if (!cardManager.prepareLocalSimulatorApplet(AID, INSTALL_DATA, ECTesterApplet.class)) { + if (!cardManager.prepareLocalSimulatorApplet(AID_221, INSTALL_DATA, ECTesterApplet.class)) { System.err.println(Colors.error("Failed to establish a simulator.")); System.exit(1); } @@ -146,11 +146,16 @@ public class ECTesterReader { System.err.println(Colors.error("Failed to connect to card.")); System.exit(1); } - ResponseAPDU selectResp = cardManager.send(SELECT_ECTESTERAPPLET); + ResponseAPDU selectResp = cardManager.send(ByteUtil.concatenate(SELECT_PREFIX, AID_222)); if ((short) selectResp.getSW() != ISO7816.SW_NO_ERROR) { - System.err.println(Colors.error("Failed to select ECTester applet, is it installed?")); - cardManager.disconnectFromCard(); - System.exit(1); + selectResp = cardManager.send(ByteUtil.concatenate(SELECT_PREFIX, AID_221)); + if ((short) selectResp.getSW() != ISO7816.SW_NO_ERROR) { + System.err.println(Colors.error("Failed to select ECTester applet, is it installed?")); + cardManager.disconnectFromCard(); + System.exit(1); + } else { + cardManager.setChunking(true); + } } } -- cgit v1.2.3-70-g09d2 From ff50f6d45ddb265e06fe275c1d4ad2cf1e4e5440 Mon Sep 17 00:00:00 2001 From: J08nY Date: Thu, 14 Mar 2019 17:29:43 +0100 Subject: Fix chunking. --- .gitignore | 4 + build-applet.xml | 1 - src/cz/crcs/ectester/applet/AppletBase.java | 42 +++++++---- .../ectester/applet/ECTesterAppletExtended.java | 2 + src/cz/crcs/ectester/reader/CardMngr.java | 85 ++++++++++------------ src/cz/crcs/ectester/reader/ECTesterReader.java | 2 + src/cz/crcs/ectester/reader/response/Response.java | 3 +- 7 files changed, 75 insertions(+), 64 deletions(-) (limited to 'src/cz/crcs/ectester/applet/ECTesterAppletExtended.java') diff --git a/.gitignore b/.gitignore index 4024180..3162005 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ /dist/*.degenerate /dist/*.edge-cases /dist/*.xml +/dist/*.yml # Built binaries in /src. /src/**/*.a @@ -34,3 +35,6 @@ /src/**/*.exp /src/**/*.lib /src/**/*.pdb + +# Python stuff +/util/__pycache__/ \ No newline at end of file diff --git a/build-applet.xml b/build-applet.xml index d74af6d..5c8da5c 100644 --- a/build-applet.xml +++ b/build-applet.xml @@ -23,7 +23,6 @@ - diff --git a/src/cz/crcs/ectester/applet/AppletBase.java b/src/cz/crcs/ectester/applet/AppletBase.java index 31ddbd9..7e79dd6 100644 --- a/src/cz/crcs/ectester/applet/AppletBase.java +++ b/src/cz/crcs/ectester/applet/AppletBase.java @@ -51,6 +51,7 @@ public abstract class AppletBase extends Applet { public static final short SW_KA_NULL = (short) 0x0ee4; public static final short SW_SIGNATURE_NULL = (short) 0x0ee5; public static final short SW_OBJECT_NULL = (short) 0x0ee6; + public static final short SW_CANNOT_FIT = (short) 0x0ee7; public static final short SW_Exception = (short) 0xff01; public static final short SW_ArrayIndexOutOfBoundsException = (short) 0xff02; public static final short SW_ArithmeticException = (short) 0xff03; @@ -67,6 +68,10 @@ public abstract class AppletBase extends Applet { public static final short BASE_221 = (short) 0x0221; public static final short BASE_222 = (short) 0x0222; + // + public static final short CDATA_BASIC = (short) 5; + public static final short CDATA_EXTENDED = (short) 7; + // public static final byte[] VERSION = {'v', '0', '.', '3', '.', '2'}; @@ -78,6 +83,7 @@ public abstract class AppletBase extends Applet { byte[] ramArray2 = null; byte[] apduArray = null; short apduEnd = 0; + short cdata = 0; RandomData randomData = null; @@ -99,7 +105,7 @@ public abstract class AppletBase extends Applet { */ short resetMemory = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_RESET); short deselectMemory = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT); - byte memoryType = (resetMemory > deselectMemory) ? JCSystem.CLEAR_ON_RESET : JCSystem.CLEAR_ON_DESELECT; + byte memoryType = (resetMemory >= deselectMemory) ? JCSystem.CLEAR_ON_RESET : JCSystem.CLEAR_ON_DESELECT; ramArray = JCSystem.makeTransientByteArray(ARRAY_LENGTH, memoryType); ramArray2 = JCSystem.makeTransientByteArray(ARRAY_LENGTH, memoryType); @@ -127,15 +133,24 @@ public abstract class AppletBase extends Applet { if (cla == CLA_ECTESTERAPPLET) { try { if (ins == INS_BUFFER) { - apduEnd += readAPDU(apdu, true); + short read = readAPDU(apdu, true); + if (read == -1) { + ISOException.throwIt(SW_CANNOT_FIT); + return; + } + apduEnd += read; apdu.setOutgoingAndSend((short) 0, (short) 0); return; } else { apduEnd = 0; if (ins == INS_PERFORM) { ins = apduArray[ISO7816.OFFSET_INS]; + apdu.setIncomingAndReceive(); } else { - readAPDU(apdu, false); + if (readAPDU(apdu, false) == -1) { + ISOException.throwIt(SW_CANNOT_FIT); + return; + } } } @@ -228,13 +243,19 @@ public abstract class AppletBase extends Applet { private short readAPDU(APDU apdu, boolean skipHeader) { byte[] apduBuffer = apdu.getBuffer(); - short cdataOffset = getOffsetCdata(apdu); /* How much stuff is in apduBuffer */ short read = apdu.setIncomingAndReceive(); + short cdataOffset = getOffsetCdata(apdu); read += cdataOffset; /* Where to start reading from? */ - short offset = skipHeader ? cdataOffset : 0; + short offset = 0; + if (skipHeader) { + offset = cdataOffset; + cdata = CDATA_EXTENDED; + } else { + cdata = CDATA_BASIC; + } /* How much stuff was really sent in this APDU? */ short total = (short) (getIncomingLength(apdu) + cdataOffset); @@ -268,7 +289,6 @@ public abstract class AppletBase extends Applet { * @return length of response */ private short insAllocateKA(APDU apdu) { - short cdata = getOffsetCdata(apdu); byte kaType = apduArray[cdata]; short sw = keyTester.allocateKA(kaType); Util.setShort(apdu.getBuffer(), (short) 0, sw); @@ -282,7 +302,6 @@ public abstract class AppletBase extends Applet { * @return length of response */ private short insAllocateSig(APDU apdu) { - short cdata = getOffsetCdata(apdu); byte sigType = apduArray[cdata]; short sw = keyTester.allocateSig(sigType); Util.setShort(apdu.getBuffer(), (short) 0, sw); @@ -301,7 +320,6 @@ public abstract class AppletBase extends Applet { */ private short insAllocate(APDU apdu) { byte keyPair = apduArray[ISO7816.OFFSET_P1]; - short cdata = getOffsetCdata(apdu); short keyLength = Util.getShort(apduArray, cdata); byte keyClass = apduArray[(short) (cdata + 2)]; @@ -347,7 +365,6 @@ public abstract class AppletBase extends Applet { private short insSet(APDU apdu) { byte keyPair = apduArray[ISO7816.OFFSET_P1]; byte curve = apduArray[ISO7816.OFFSET_P2]; - short cdata = getOffsetCdata(apdu); short params = Util.getShort(apduArray, cdata); short len = 0; @@ -375,7 +392,6 @@ public abstract class AppletBase extends Applet { private short insTransform(APDU apdu) { byte keyPair = apduArray[ISO7816.OFFSET_P1]; byte key = apduArray[ISO7816.OFFSET_P2]; - short cdata = getOffsetCdata(apdu); short params = Util.getShort(apduArray, cdata); short transformation = Util.getShort(apduArray, (short) (cdata + 2)); @@ -424,7 +440,6 @@ public abstract class AppletBase extends Applet { private short insExport(APDU apdu) { byte keyPair = apduArray[ISO7816.OFFSET_P1]; byte key = apduArray[ISO7816.OFFSET_P2]; - short cdata = getOffsetCdata(apdu); short params = Util.getShort(apduArray, cdata); short swOffset = 0; @@ -455,7 +470,6 @@ public abstract class AppletBase extends Applet { private short insECDH(APDU apdu) { byte pubkey = apduArray[ISO7816.OFFSET_P1]; byte privkey = apduArray[ISO7816.OFFSET_P2]; - short cdata = getOffsetCdata(apdu); byte export = apduArray[cdata]; short transformation = Util.getShort(apduArray, (short) (cdata + 1)); byte type = apduArray[(short) (cdata + 3)]; @@ -477,7 +491,6 @@ public abstract class AppletBase extends Applet { private short insECDH_direct(APDU apdu) { byte privkey = apduArray[ISO7816.OFFSET_P1]; byte export = apduArray[ISO7816.OFFSET_P2]; - short cdata = getOffsetCdata(apdu); short transformation = Util.getShort(apduArray, cdata); byte type = apduArray[(short) (cdata + 2)]; short length = Util.getShort(apduArray, (short) (cdata + 3)); @@ -499,7 +512,6 @@ public abstract class AppletBase extends Applet { private short insECDSA(APDU apdu) { byte keyPair = apduArray[ISO7816.OFFSET_P1]; byte export = apduArray[ISO7816.OFFSET_P2]; - short cdata = getOffsetCdata(apdu); byte sigType = apduArray[cdata]; short len = 0; @@ -524,7 +536,6 @@ public abstract class AppletBase extends Applet { private short insECDSA_sign(APDU apdu) { byte keyPair = apduArray[ISO7816.OFFSET_P1]; byte export = apduArray[ISO7816.OFFSET_P2]; - short cdata = getOffsetCdata(apdu); byte sigType = apduArray[cdata]; short len = 0; @@ -549,7 +560,6 @@ public abstract class AppletBase extends Applet { private short insECDSA_verify(APDU apdu) { byte keyPair = apduArray[ISO7816.OFFSET_P1]; byte sigType = apduArray[ISO7816.OFFSET_P2]; - short cdata = getOffsetCdata(apdu); short len = 0; if ((keyPair & KEYPAIR_LOCAL) != 0) { diff --git a/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java index c31544a..79ccf7b 100644 --- a/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java +++ b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java @@ -27,6 +27,8 @@ package cz.crcs.ectester.applet; import javacard.framework.APDU; +import javacard.framework.CardRuntimeException; +import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacardx.apdu.ExtendedLength; diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index abbc440..87384c3 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -8,6 +8,7 @@ import javacard.framework.ISO7816; import javax.smartcardio.*; import java.util.*; +import java.util.function.Function; /** * @author Petr Svenda petr@svenda.com @@ -328,6 +329,39 @@ public class CardMngr { } } + private CommandAPDU chunk(CommandAPDU apdu) throws CardException { + if (verbose) { + System.out.print("Chunking:"); + } + byte[] data = apdu.getBytes(); + int numChunks = (data.length + 254) / 255; + for (int i = 0; i < numChunks; ++i) { + int chunkStart = i *255; + int chunkLength = 255; + if (chunkStart + chunkLength > data.length) { + chunkLength = data.length - chunkStart; + } + if (verbose) { + System.out.print(" " + chunkLength); + } + byte[] chunk = new byte[chunkLength]; + System.arraycopy(data, chunkStart, chunk, 0, chunkLength); + CommandAPDU cmd = new CommandAPDU(apdu.getCLA(), 0x7a, 0, 0, chunk); + ResponseAPDU resp; + if (simulate) { + resp = simulator.transmitCommand(cmd); + } else { + resp = channel.transmit(cmd); + } + if ((short) resp.getSW() != ISO7816.SW_NO_ERROR) { + throw new CardException("Chunking failed!"); + } + } + if (verbose) + System.out.println(); + return new CommandAPDU(apdu.getCLA(), 0x7b, 0, 0, 0xff); + } + public ResponseAPDU sendAPDU(CommandAPDU apdu) throws CardException { if (verbose) { System.out.println(">>>>"); @@ -338,31 +372,7 @@ public class CardMngr { long elapsed; if (chunking && apdu.getNc() >= 0xff) { - if (verbose) { - System.out.print("Chunking:"); - } - byte[] data = apdu.getBytes(); - int numChunks = (data.length + 254) / 255; - for (int i = 0; i < numChunks; ++i) { - int chunkStart = i *255; - int chunkLength = 255; - if (chunkStart + chunkLength > data.length) { - chunkLength = data.length - chunkStart; - } - if (verbose) { - System.out.print(" " + chunkLength); - } - byte[] chunk = new byte[chunkLength]; - System.arraycopy(data, chunkStart, chunk, 0, chunkLength); - CommandAPDU cmd = new CommandAPDU(apdu.getCLA(), 0x7a, 0, 0, chunk); - ResponseAPDU resp = channel.transmit(cmd); - if ((short) resp.getSW() != ISO7816.SW_NO_ERROR) { - return resp; - } - } - if (verbose) - System.out.println(); - apdu = new CommandAPDU(apdu.getCLA(), 0x7b, 0, 0, 0xff); + apdu = chunk(apdu); } elapsed = -System.nanoTime(); @@ -389,6 +399,7 @@ public class CardMngr { if (verbose) { System.out.println("<<<<"); System.out.println("Elapsed time (ms): " + elapsed / 1000000); + System.out.println("---------------------------------------------------------"); } return responseAPDU; } @@ -406,34 +417,16 @@ public class CardMngr { return simulator.selectApplet(appletAID); } - public ResponseAPDU sendAPDUSimulator(CommandAPDU apdu) { + public ResponseAPDU sendAPDUSimulator(CommandAPDU apdu) throws CardException { if (verbose) { System.out.println(">>>>"); System.out.println(apdu); System.out.println(ByteUtil.bytesToHex(apdu.getBytes())); } - /* if (chunking && apdu.getNc() >= 0xff) { - byte[] data = apdu.getBytes(); - int numChunks = (data.length + 254) / 255; - for (int i = 0; i < numChunks; ++i) { - int chunkStart = i *255; - int chunkLength = 255; - if (chunkStart + chunkLength > data.length) { - chunkLength = data.length - chunkStart; - } - byte[] chunk = new byte[chunkLength]; - System.arraycopy(data, chunkStart, chunk, 0, chunkLength); - CommandAPDU cmd = new CommandAPDU(apdu.getCLA(), 0x7a, 0, 0, chunk); - ResponseAPDU resp = simulator.transmitCommand(cmd); - if ((short) resp.getSW() != ISO7816.SW_NO_ERROR) { - return resp; - } - } - apdu = new CommandAPDU(apdu.getCLA(), 0x7b, 0, 0); + apdu = chunk(apdu); } - */ ResponseAPDU response = simulator.transmitCommand(apdu); byte[] responseBytes = response.getBytes(); @@ -447,7 +440,7 @@ public class CardMngr { return response; } - public ResponseAPDU sendAPDUSimulator(byte[] apdu) { + public ResponseAPDU sendAPDUSimulator(byte[] apdu) throws CardException { CommandAPDU commandAPDU = new CommandAPDU(apdu); return sendAPDUSimulator(commandAPDU); } diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index ab21cd9..e0a8a24 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -140,6 +140,8 @@ public class ECTesterReader { if (!cardManager.prepareLocalSimulatorApplet(AID_221, INSTALL_DATA, ECTesterApplet.class)) { System.err.println(Colors.error("Failed to establish a simulator.")); System.exit(1); + } else { + cardManager.setChunking(true); } } else { if (!cardManager.connectToCardSelect()) { diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index 53a757b..f36d087 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -26,7 +26,7 @@ public abstract class Response { this.time = time; } - void parse(int numSW, int numParams) { + boolean parse(int numSW, int numParams) { this.numSW = numSW; this.sws = new short[numSW]; @@ -73,6 +73,7 @@ public abstract class Response { System.arraycopy(data, offset, params[i], 0, paramLength); offset += paramLength; } + return success; } public ResponseAPDU getAPDU() { -- cgit v1.2.3-70-g09d2 From 648d8718af10186e5c585844f6bb8c32e244c3a0 Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 18 Mar 2019 10:44:39 +0100 Subject: Add customizable time resolution. --- README.md | 36 +++++---- src/cz/crcs/ectester/applet/ECTesterApplet.java | 1 + .../ectester/applet/ECTesterAppletExtended.java | 1 + src/cz/crcs/ectester/common/util/Util.java | 15 ++++ src/cz/crcs/ectester/reader/CardMngr.java | 34 +++++--- src/cz/crcs/ectester/reader/ECTesterReader.java | 90 +++++++--------------- .../ectester/standalone/ECTesterStandalone.java | 3 +- 7 files changed, 93 insertions(+), 87 deletions(-) create mode 100644 src/cz/crcs/ectester/common/util/Util.java (limited to 'src/cz/crcs/ectester/applet/ECTesterAppletExtended.java') diff --git a/README.md b/README.md index a766235..bdc8cd8 100644 --- a/README.md +++ b/README.md @@ -53,18 +53,18 @@ See `java -jar ECTesterReader.jar -h`, `java -jar ECTesterReader.jar -ls` and [D -t,--test Test ECC support. Optionally specify a test number to run only a part of a test suite. : - - default: - - compression: - - invalid: - - twist: - - degenerate: - - cofactor: - - wrong: - - signature: - - composite: - - test-vectors: - - edge-cases: - - miscellaneous: + - default + - compression + - invalid + - twist + - degenerate + - cofactor + - wrong + - signature + - composite + - test-vectors + - edge-cases + - miscellaneous -dh,--ecdh Do EC KeyAgreement (ECDH...), [count] times. -dsa,--ecdsa Sign data with ECDSA, [count] times. @@ -109,12 +109,21 @@ See `java -jar ECTesterReader.jar -h`, `java -jar ECTesterReader.jar -ls` and [D running command in dry run mode and normal mode, and subtracting the two. + --time-unit Use given time unit in measurement, + one of: milli, micro, nano. --cleanup Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations. -s,--simulate Simulate a card with jcardsim instead of using a terminal. -y,--yes Accept all warnings and prompts. + -to,--test-options Test options to use: + - preset: Use preset semi-random + private keys (derived from curve) + instead of generating keypairs on + the cards when the test needs one. + - random: Use fully random private + keys instead of generating keypairs. -ka,--ka-type Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants. @@ -198,7 +207,8 @@ Lists the implemented test suites and gives their short description. Get and print ECTester applet info from an applet installed on a card. Outputs: - + - Card ATR + - Negotiated protocol (T=0/T=1) - ECTester applet version - ECTester APDU support (basic/extended APDU) - JavaCard API version diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index b222d46..e9e7235 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -1,6 +1,7 @@ /* * ECTester, tool for testing Elliptic curve cryptography implementations. * Copyright (c) 2016-2019 Petr Svenda + * Copyright (c) 2016-2019 Jan Jancar * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java index 79ccf7b..cbbe650 100644 --- a/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java +++ b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java @@ -1,6 +1,7 @@ /* * ECTester, tool for testing Elliptic curve cryptography implementations. * Copyright (c) 2016-2019 Petr Svenda + * Copyright (c) 2016-2019 Jan Jancar * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/cz/crcs/ectester/common/util/Util.java b/src/cz/crcs/ectester/common/util/Util.java new file mode 100644 index 0000000..7f18368 --- /dev/null +++ b/src/cz/crcs/ectester/common/util/Util.java @@ -0,0 +1,15 @@ +package cz.crcs.ectester.common.util; + +public class Util { + public static long convertTime(long nanos, String timeUnit) { + switch (timeUnit) { + default: + case "nano": + return nanos; + case "micro": + return nanos / 1000; + case "milli": + return nanos / 1000000; + } + } +} diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index 87384c3..0a01d9e 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -8,7 +8,6 @@ import javacard.framework.ISO7816; import javax.smartcardio.*; import java.util.*; -import java.util.function.Function; /** * @author Petr Svenda petr@svenda.com @@ -184,6 +183,18 @@ public class CardMngr { chunking = state; } + public String getProtocol() { + if (simulate) { + return simulator.getProtocol(); + } else { + if (card != null) { + return card.getProtocol(); + } else { + return null; + } + } + } + // Functions for CPLC taken and modified from https://github.com/martinpaljak/GlobalPlatformPro private static final byte CLA_GP = (byte) 0x80; private static final byte ISO7816_INS_GET_DATA = (byte) 0xCA; @@ -280,6 +291,18 @@ public class CardMngr { } } + public ATR getATR() { + if (simulate) { + return new ATR(simulator.getATR()); + } else { + if (card != null) { + return card.getATR(); + } else { + return null; + } + } + } + public CPLC getCPLC() throws CardException { byte[] data = fetchCPLC(); return new CPLC(data); @@ -311,13 +334,6 @@ public class CardMngr { } } - public ATR getATR() { - if (simulate) { - return new ATR(simulator.getATR()); - } else { - return card.getATR(); - } - } public static List getReaderList() { try { @@ -336,7 +352,7 @@ public class CardMngr { byte[] data = apdu.getBytes(); int numChunks = (data.length + 254) / 255; for (int i = 0; i < numChunks; ++i) { - int chunkStart = i *255; + int chunkStart = i * 255; int chunkLength = 255; if (chunkStart + chunkLength > data.length) { chunkLength = data.length - chunkStart; diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index e0a8a24..cb64b4c 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -1,6 +1,7 @@ /* * ECTester, tool for testing Elliptic curve cryptography implementations. * Copyright (c) 2016-2019 Petr Svenda + * Copyright (c) 2016-2019 Jan Jancar * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,10 +30,8 @@ import cz.crcs.ectester.common.cli.Colors; import cz.crcs.ectester.common.ec.EC_Curve; import cz.crcs.ectester.common.output.OutputLogger; import cz.crcs.ectester.common.output.TestWriter; -import cz.crcs.ectester.common.util.ByteUtil; -import cz.crcs.ectester.common.util.CardUtil; -import cz.crcs.ectester.common.util.ECUtil; -import cz.crcs.ectester.common.util.FileUtil; +import cz.crcs.ectester.common.util.Util; +import cz.crcs.ectester.common.util.*; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.output.FileTestWriter; @@ -77,7 +76,7 @@ public class ECTesterReader { public static final String VERSION = "v0.3.2"; public static String GIT_COMMIT = ""; private static String DESCRIPTION; - private static String LICENSE = "MIT Licensed\nCopyright (c) 2016-2018 Petr Svenda "; + private static String LICENSE = "MIT Licensed\nCopyright © 2016-2019 Petr Svenda \nCopyright © 2016-2019 Jan Jancar "; private static String CLI_HEADER; private static String CLI_FOOTER = "\n" + LICENSE; @@ -249,54 +248,6 @@ public class ECTesterReader { * @throws ParseException if there are any problems encountered while parsing the command line tokens */ private CommandLine parseArgs(String[] args) throws ParseException { - /* - * Actions: - * -V / --version - * -h / --help - * -e / --export - * -g / --generate [amount] - * -t / --test [test_suite] - * -dh / --ecdh [count]] - * -dsa / --ecdsa [count] - * -ln / --list-named [obj] - * -ls / --list-suites - * -nfo / --info - * - * Options: - * -b / --bit-size // -a / --all - * - * -fp / --prime-field - * -f2m / --binary-field - * - * -u / --custom - * -nc / --named-curve - * -c / --curve field,a,b,gx,gy,r,k - * - * -pub / --public wx,wy - * -npub / --named-public - * - * -priv / --private s - * -npriv / --named-private - * - * -k / --key wx,wy,s - * -nk / --named-key - * - * -v / --verbose - * - * -i / --input - * -o / --output - * --format - * -l / --log [log_file] - * - * -f / --fresh - * --cleanup - * -s / --simulate - * -y / --yes - * -ka/ --ka-type - * -sig/--sig-type - * -C / --color - * -to/ --test-options - */ OptionGroup actions = new OptionGroup(); actions.setRequired(true); actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); @@ -348,6 +299,7 @@ public class ECTesterReader { opts.addOption(Option.builder().longOpt("fixed-public").desc("Generate public key only once, keep it for later ECDH.").build()); opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build()); opts.addOption(Option.builder().longOpt("time").desc("Output better timing values, by running command in dry run mode and normal mode, and subtracting the two.").build()); + opts.addOption(Option.builder().longOpt("time-unit").desc("Use given time unit in measurement, one of: milli, micro, nano.").hasArg().argName("unit").build()); opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations.").build()); opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build()); opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build()); @@ -390,11 +342,13 @@ public class ECTesterReader { private void info() throws CardException { Response.GetInfo info = new Command.GetInfo(cardManager).send(); - System.out.println(String.format("ECTester applet version: %s", info.getVersion())); - System.out.println(String.format("ECTester applet APDU support: %s", (info.getBase() == ECTesterApplet.BASE_221) ? "basic" : "extended length")); - System.out.println(String.format("JavaCard API version: %.1f", info.getJavaCardVersion())); - System.out.println(String.format("JavaCard supports system cleanup: %s", info.getCleanupSupport())); - System.out.println(String.format("Array sizes (apduBuf, ram, ram2, apduArr): %d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength())); + System.out.println(String.format("Card ATR:\t\t\t\t%s", ByteUtil.bytesToHex(cardManager.getATR().getBytes(), false))); + System.out.println(String.format("Card protocol:\t\t\t\t%s", cardManager.getProtocol())); + System.out.println(String.format("ECTester applet version:\t\t%s", info.getVersion())); + System.out.println(String.format("ECTester applet APDU support:\t\t%s", (info.getBase() == ECTesterApplet.BASE_221) ? "basic" : "extended length")); + System.out.println(String.format("JavaCard API version:\t\t\t%.1f", info.getJavaCardVersion())); + System.out.println(String.format("JavaCard supports system cleanup:\t%s", info.getCleanupSupport())); + System.out.println(String.format("Array sizes (apduBuf,ram,ram2,apduArr):\t%d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength())); } /** @@ -461,7 +415,7 @@ public class ECTesterReader { respWriter.outputResponse(allocate); OutputStreamWriter keysFile = FileUtil.openFiles(cfg.outputs); - keysFile.write("index;genTime[milli];exportTime[milli];pubW;privS\n"); + keysFile.write(String.format("index;genTime[%s];exportTime[%s];pubW;privS\n", cfg.timeUnit, cfg.timeUnit)); int generated = 0; int retry = 0; @@ -495,7 +449,7 @@ public class ECTesterReader { String pub = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false); String priv = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false); - String line = String.format("%d;%d;%d;%s;%s\n", generated, time / 1000000, export.getDuration() / 1000000, pub, priv); + String line = String.format("%d;%d;%d;%s;%s\n", generated, Util.convertTime(time, cfg.timeUnit), Util.convertTime(export.getDuration(), cfg.timeUnit), pub, priv); keysFile.write(line); keysFile.flush(); generated++; @@ -601,7 +555,7 @@ public class ECTesterReader { OutputStreamWriter out = null; if (cfg.outputs != null) { out = FileUtil.openFiles(cfg.outputs); - out.write("index;time[milli];pubW;privS;secret\n"); + out.write(String.format("index;time[%s];pubW;privS;secret\n", cfg.timeUnit)); } Response gen = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH).send(); @@ -669,7 +623,7 @@ public class ECTesterReader { if (out != null) { time += result.getDuration(); - out.write(String.format("%d;%d;%s;%s;%s\n", done, time / 1000000, ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(result.getSecret(), false))); + out.write(String.format("%d;%d;%s;%s;%s\n", done, Util.convertTime(time, cfg.timeUnit), ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(result.getSecret(), false))); out.flush(); } @@ -727,7 +681,7 @@ public class ECTesterReader { OutputStreamWriter out = FileUtil.openFiles(cfg.outputs); if (out != null) { - out.write("index;signTime[milli];verifyTime[milli];data;pubW;privS;signature;nonce;valid\n"); + out.write(String.format("index;signTime[%s];verifyTime[%s];data;pubW;privS;signature;nonce;valid\n", cfg.timeUnit, cfg.timeUnit)); } Command.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR); @@ -800,7 +754,7 @@ public class ECTesterReader { k = ByteUtil.bytesToHex(kValue.toByteArray(), false); } } - out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, signTime / 1000000, verifyTime / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k, verifyResp.successful() ? 1 : 0)); + out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, Util.convertTime(signTime, cfg.timeUnit), Util.convertTime(verifyTime, cfg.timeUnit), dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k, verifyResp.successful() ? 1 : 0)); out.flush(); } @@ -856,6 +810,7 @@ public class ECTesterReader { public String[] outputs; public boolean fresh = false; public boolean time = false; + public String timeUnit; public boolean cleanup = false; public boolean simulate = false; public boolean yes = false; @@ -922,6 +877,13 @@ public class ECTesterReader { color = cli.hasOption("color"); Colors.enabled = color; + timeUnit = cli.getOptionValue("time-unit", "micro"); + String[] times = new String[]{"milli", "micro", "nano"}; + if (!Arrays.asList(times).contains(timeUnit)) { + System.err.println(Colors.error("Wrong time unit " + timeUnit + ". Should be one of " + Arrays.toString(times))); + return false; + } + if (cli.hasOption("list-named")) { listNamed = cli.getOptionValue("list-named"); return true; diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 1b4d9b8..e39944b 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -1,6 +1,7 @@ /* * ECTester, tool for testing Elliptic curve cryptography implementations. * Copyright (c) 2016-2018 Petr Svenda + * Copyright (c) 2016-2019 Jan Jancar * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -85,7 +86,7 @@ public class ECTesterStandalone { private TreeCommandLine cli; public static final String VERSION = "v0.3.2"; private static final String DESCRIPTION = "ECTesterStandalone " + VERSION + ", an Elliptic Curve Cryptography support tester/utility."; - private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2018 Petr Svenda "; + private static final String LICENSE = "MIT Licensed\nCopyright © 2016-2019 Petr Svenda \nCopyright © 2016-2019 Jan Jancar "; private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; private static final String CLI_FOOTER = "\n" + LICENSE; -- cgit v1.2.3-70-g09d2