aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--!uploader/ectester.capbin13377 -> 13641 bytes
-rw-r--r--dist/ECTester.jarbin75369 -> 78703 bytes
-rw-r--r--src/cz/crcs/ectester/applet/ECKeyGenerator.java41
-rw-r--r--src/cz/crcs/ectester/applet/ECTesterApplet.java38
-rw-r--r--src/cz/crcs/ectester/reader/CardMngr.java2
-rw-r--r--src/cz/crcs/ectester/reader/Command.java27
-rw-r--r--src/cz/crcs/ectester/reader/ECTester.java121
-rw-r--r--src/cz/crcs/ectester/reader/Response.java131
8 files changed, 260 insertions, 100 deletions
diff --git a/!uploader/ectester.cap b/!uploader/ectester.cap
index a7da4dc..8d1bff8 100644
--- a/!uploader/ectester.cap
+++ b/!uploader/ectester.cap
Binary files differ
diff --git a/dist/ECTester.jar b/dist/ECTester.jar
index b0dae23..f0a8c3b 100644
--- a/dist/ECTester.jar
+++ b/dist/ECTester.jar
Binary files differ
diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
index 417944c..427577b 100644
--- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java
+++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
@@ -44,6 +44,19 @@ public class ECKeyGenerator {
return ecKeyPair;
}
+ public short clearPair(KeyPair keypair, byte key) {
+ sw = ISO7816.SW_NO_ERROR;
+ try {
+ if ((key & KEY_PUBLIC) != 0) keypair.getPublic().clearKey();
+ if ((key & KEY_PRIVATE) != 0) keypair.getPrivate().clearKey();
+ } catch (CryptoException ce) {
+ sw = ce.getReason();
+ } catch (Exception e) {
+ sw = ISO7816.SW_UNKNOWN;
+ }
+ return sw;
+ }
+
/**
* @param keypair
* @return
@@ -73,8 +86,8 @@ public class ECKeyGenerator {
sw = ISO7816.SW_NO_ERROR;
if (params == EC_Consts.PARAMETERS_NONE) {
- return sw;
- }
+ return sw;
+ }
short length;
if (alg == KeyPair.ALG_EC_FP && (params & EC_Consts.PARAMETER_FP) != 0) {
@@ -123,9 +136,9 @@ public class ECKeyGenerator {
*/
public short corruptCurve(KeyPair keypair, byte key, short corruptParams, byte corruption, byte[] buffer, short offset) {
sw = ISO7816.SW_NO_ERROR;
- if (corruptParams == EC_Consts.PARAMETERS_NONE) {
- return sw;
- }
+ if (corruptParams == EC_Consts.PARAMETERS_NONE) {
+ return sw;
+ }
//go through param bit by bit, and invalidate all selected params
short paramMask = EC_Consts.PARAMETER_FP;
@@ -252,7 +265,7 @@ public class ECKeyGenerator {
public short setExternalCurve(KeyPair keypair, byte key, short params, byte[] inBuffer, short inOffset) {
sw = ISO7816.SW_NO_ERROR;
if (params == EC_Consts.PARAMETERS_NONE) {
- return sw;
+ return sw;
}
short paramMask = EC_Consts.PARAMETER_FP;
@@ -273,9 +286,9 @@ public class ECKeyGenerator {
/**
* Exports a selected parameter from a given keyPairs key.
*
- * @param keypair keypair to export from
- * @param key key to export from (KEY_PUBLIC | KEY_PRIVATE)
- * @param param parameter to export (EC_Consts.PARAMETER_* || ...)
+ * @param keypair keypair to export from
+ * @param key key to export from (KEY_PUBLIC | KEY_PRIVATE)
+ * @param param parameter to export (EC_Consts.PARAMETER_* || ...)
* @param outputBuffer buffer to write to
* @param outputOffset offset to start writing in buffer
* @return length of data written
@@ -346,9 +359,9 @@ public class ECKeyGenerator {
*/
public short exportParameters(KeyPair keypair, byte key, short params, byte[] buffer, short offset) {
sw = ISO7816.SW_NO_ERROR;
- if (params == EC_Consts.PARAMETERS_NONE) {
- return sw;
- }
+ if (params == EC_Consts.PARAMETERS_NONE) {
+ return sw;
+ }
short length = 0;
short paramMask = EC_Consts.PARAMETER_FP;
@@ -372,8 +385,8 @@ public class ECKeyGenerator {
/**
* Copies this KeyPairs curve parameters to another ECKeyGenerator.
*
- * @param from keyPair to copy from
- * @param to keyPair to copy to
+ * @param from keyPair to copy from
+ * @param to keyPair to copy to
* @param buffer buffer to use for copying
* @param offset offset to use in buffer
* @return sw
diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java
index dfdd0f0..cb2c43f 100644
--- a/src/cz/crcs/ectester/applet/ECTesterApplet.java
+++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java
@@ -44,10 +44,11 @@ public class ECTesterApplet extends Applet {
//INSTRUCTIONS
public static final byte INS_ALLOCATE = (byte) 0x5a;
- public static final byte INS_SET = (byte) 0x5b;
- public static final byte INS_GENERATE = (byte) 0x5c;
- public static final byte INS_ECDH = (byte) 0x5d;
- public static final byte INS_ECDSA = (byte) 0x5e;
+ public static final byte INS_CLEAR = (byte) 0x5b;
+ public static final byte INS_SET = (byte) 0x5c;
+ public static final byte INS_GENERATE = (byte) 0x5d;
+ public static final byte INS_ECDH = (byte) 0x5e;
+ public static final byte INS_ECDSA = (byte) 0x5f;
//PARAMETERS for P1 and P2
public static final byte KEYPAIR_LOCAL = (byte) 0x01;
@@ -127,6 +128,9 @@ public class ECTesterApplet extends Applet {
case INS_ALLOCATE:
insAllocate(apdu);
break;
+ case INS_CLEAR:
+ insClear(apdu);
+ break;
case INS_SET:
insSet(apdu);
break;
@@ -170,6 +174,25 @@ public class ECTesterApplet extends Applet {
}
/**
+ *
+ * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
+ * P2 =
+ */
+ private void insClear(APDU apdu) {
+ apdu.setIncomingAndReceive();
+ byte[] apdubuf = apdu.getBuffer();
+ byte keyPair = apdubuf[ISO7816.OFFSET_P1];
+
+ short len = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0)
+ len += clear(localKeypair, apdubuf, (short) 0);
+ if ((keyPair & KEYPAIR_REMOTE) != 0)
+ len += clear(remoteKeypair, apdubuf, len);
+
+ apdu.setOutgoingAndSend((short) 0, len);
+ }
+
+ /**
* Sets curve parameters on local and remote keyPairs.
* returns setCurve SWs, set params if export
*
@@ -306,6 +329,13 @@ public class ECTesterApplet extends Applet {
return length;
}
+ private short clear(KeyPair keyPair, byte[] buffer, short offset) {
+ short sw = keyGenerator.clearPair(keyPair, ECKeyGenerator.KEY_BOTH);
+ Util.setShort(buffer, offset, sw);
+
+ return 2;
+ }
+
/**
* @param keyPair KeyPair to set params on
* @param curve curve to set (EC_Consts.CURVE_*)
diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java
index d95b7e5..6875d2e 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 final byte selectCM[] = {
+ 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};
diff --git a/src/cz/crcs/ectester/reader/Command.java b/src/cz/crcs/ectester/reader/Command.java
index c5fd465..31cde4d 100644
--- a/src/cz/crcs/ectester/reader/Command.java
+++ b/src/cz/crcs/ectester/reader/Command.java
@@ -23,11 +23,6 @@ public abstract class Command {
return cmd;
}
- /**
- *
- * @return
- * @throws CardException
- */
public abstract Response send() throws CardException;
public static List<Response> sendAll(List<Command> commands) throws CardException {
@@ -77,6 +72,28 @@ public abstract class Command {
/**
*
*/
+ public static class Clear extends Command {
+ private byte keyPair;
+
+ public Clear(CardMngr cardManager, byte keyPair) {
+ super(cardManager);
+ this.keyPair = keyPair;
+
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEAR, keyPair, 0x00);
+ }
+
+ @Override
+ public Response.Clear send() throws CardException {
+ long elapsed = -System.nanoTime();
+ ResponseAPDU response = cardManager.send(cmd);
+ elapsed += System.nanoTime();
+ return new Response.Clear(response, elapsed, keyPair);
+ }
+ }
+
+ /**
+ *
+ */
public static class Set extends Command {
private byte keyPair;
private byte export;
diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java
index e5a2b70..4cb63f7 100644
--- a/src/cz/crcs/ectester/reader/ECTester.java
+++ b/src/cz/crcs/ectester/reader/ECTester.java
@@ -33,6 +33,7 @@ import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
/**
@@ -58,6 +59,7 @@ public class ECTester {
private String optKey = null;
private String optLog = null;
private String optOutput = null;
+ private boolean optFresh = false;
private boolean optSimulate = false;
private int optGenerateAmount;
@@ -244,11 +246,15 @@ public class ECTester {
opts.addOption(Option.builder("fp").longOpt("prime-field").desc("Use prime field curve.").build());
opts.addOption(Option.builder("f2m").longOpt("binary-field").desc("Use binary field curve.").build());
+
opts.addOption(Option.builder("pub").longOpt("public").desc("Use public key from file [pubkey_file] (wx,wy).").hasArg().argName("pubkey_file").build());
opts.addOption(Option.builder("priv").longOpt("private").desc("Use private key from file [privkey_file] (s).").hasArg().argName("privkey_file").build());
opts.addOption(Option.builder("k").longOpt("key").desc("Use keyPair from fileĀ [key_file] (wx,wy,s).").hasArg().argName("key_file").build());
+
opts.addOption(Option.builder("o").longOpt("output").desc("Output into file [output_file].").hasArg().argName("output_file").build());
opts.addOption(Option.builder("l").longOpt("log").desc("Log output into file [log_file].").hasArg().argName("log_file").optionalArg(true).build());
+
+ opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys(set domain parameters before every generation).").build());
opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build());
CommandLineParser parser = new DefaultParser();
@@ -275,6 +281,7 @@ public class ECTester {
optLog = cli.getOptionValue("log", String.format("ECTESTER_log_%d.log", System.currentTimeMillis() / 1000));
}
optOutput = cli.getOptionValue("output");
+ optFresh = cli.hasOption("fresh");
optSimulate = cli.hasOption("simulate");
if (optKey != null && (optPublic != null || optPrivate != null)) {
@@ -365,7 +372,8 @@ public class ECTester {
*/
private void generate() throws CardException, IOException {
byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- List<Response> prepare = Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ List<Response> prepare = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ prepare.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass)));
FileWriter keysFile = new FileWriter(optOutput);
keysFile.write("index;time;pubW;privS\n");
@@ -373,6 +381,10 @@ public class ECTester {
int generated = 0;
int retry = 0;
while (generated < optGenerateAmount || optGenerateAmount == 0) {
+ if (optFresh) {
+ Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ }
+
Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (byte) (ECTesterApplet.EXPORT_BOTH | ECTesterApplet.KEYPAIR_LOCAL));
Response.Generate response = generate.send();
long elapsed = response.getDuration();
@@ -400,47 +412,36 @@ public class ECTester {
/**
* Tests Elliptic curve support for a given curve/curves.
+ *
+ * @throws IOException
+ * @throws CardException
*/
- private void test() {
- //TODO
+ private void test() throws IOException, CardException {
+ List<Command> commands = new LinkedList<>();
if (optAll) {
if (optPrimeField) {
//iterate over prime curve sizes used: EC_Consts.FP_SIZES
for (short keyLength : EC_Consts.FP_SIZES) {
- //prepareCurve(KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP);
- //insGenerate(KEYPAIR_BOTH, EXPORT_NONE);
- //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 00);
- //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 01);
- //insECDSA(KEYPAIR_LOCAL, EXPORT_NONE, null);
+ commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_FP));
}
}
if (optBinaryField) {
//iterate over binary curve sizes used: EC_Consts.F2M_SIZES
for (short keyLength : EC_Consts.F2M_SIZES) {
- //prepareCurve(KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M);
- //insGenerate(KEYPAIR_BOTH, EXPORT_NONE);
- //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 00);
- //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 01);
- //insECDSA(KEYPAIR_LOCAL, EXPORT_NONE, null);
+ commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_F2M));
}
}
} else {
if (optPrimeField) {
- //test with prepareCurve(KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_FP)
- //insGenerate(KEYPAIR_BOTH, EXPORT_NONE);
- //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 00);
- //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 01);
- //insECDSA(KEYPAIR_LOCAL, EXPORT_NONE, null);
+ commands.addAll(testCurve((short) optBits, KeyPair.ALG_EC_FP));
}
if (optBinaryField) {
- //test with prepareCurve(KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_F2M)
- //insGenerate(KEYPAIR_BOTH, EXPORT_NONE);
- //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 00);
- //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 01);
- //insECDSA(KEYPAIR_LOCAL, EXPORT_NONE, null);
+ commands.addAll(testCurve((short) optBits, KeyPair.ALG_EC_F2M));
}
}
+ List<Response> test = Command.sendAll(commands);
+ systemOutLogger.println(Response.toString(test));
}
/**
@@ -451,7 +452,8 @@ public class ECTester {
*/
private void ecdh() throws IOException, CardException {
byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- List<Response> ecdh = Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass));
+ List<Response> ecdh = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass));
+ ecdh.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass)));
if (optPublic != null || optPrivate != null || optKey != null) {
Response local = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_NONE).send();
@@ -465,10 +467,17 @@ public class ECTester {
Response.ECDH perform = new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_ECDH, (byte) 0).send();
ecdh.add(perform);
- for (Response r : ecdh) {
- systemOutLogger.println(r.toString());
+ systemOutLogger.println(Response.toString(ecdh));
+
+ if (!perform.hasSecret()) {
+ System.err.println("Couldn't obtain ECDH secret from card response.");
+ } else {
+ if (optOutput != null) {
+ FileWriter out = new FileWriter(optOutput);
+ out.write(Util.bytesToHex(perform.getSecret(), false));
+ out.close();
+ }
}
- //TODO check perform.hasSecret(), write perform.getSecret to file if -o
}
/**
@@ -479,7 +488,8 @@ public class ECTester {
*/
private void ecdsa() throws CardException, IOException {
byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- List<Response> ecdsa = Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ List<Response> ecdsa = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ ecdsa.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass)));
Response keys;
if (optKey != null || (optPublic != null && optPrivate != null)) {
@@ -502,33 +512,55 @@ public class ECTester {
Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_SIG, data).send();
ecdsa.add(perform);
- for (Response r : ecdsa) {
- systemOutLogger.println(r.toString());
+ systemOutLogger.println(Response.toString(ecdsa));
+
+ if (!perform.hasSignature()) {
+ System.err.println("Couldn't obtain ECDSA signature from card response.");
+ } else {
+ if (optOutput != null) {
+ FileWriter out = new FileWriter(optOutput);
+ out.write(Util.bytesToHex(perform.getSignature(), false));
+ out.close();
+ }
}
- //TODO output to file
}
/**
- * @param keyPair which keyPair/s (local/remote) to set curve domain parameters on
+ * @param keyPair which keyPair/s (local/remote) to allocate
* @param keyLength key length to allocate
* @param keyClass key class to allocate
- * @return an array of CommandAPDUs to send in order to prepare the keypair/s.
+ * @return a list of Commands to send in order to prepare the keyPair.
+ */
+ private List<Command> prepareKeyPair(byte keyPair, short keyLength, byte keyClass) {
+ List<Command> commands = new ArrayList<>();
+ commands.add(new Command.Allocate(cardManager, keyPair, keyLength, keyClass));
+ return commands;
+ }
+
+ /**
+ * @param keyPair which keyPair/s (local/remote) to set curve domain parameters on
+ * @param keyLength key length to choose
+ * @param keyClass key class to choose
+ * @return a list of Commands to send in order to prepare the curve on the keypairs.
* @throws IOException if curve file cannot be found/opened
*/
private List<Command> prepareCurve(byte keyPair, short keyLength, byte keyClass) throws IOException {
List<Command> commands = new ArrayList<>();
- commands.add(new Command.Allocate(cardManager, keyPair, keyLength, keyClass));
short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
if (optNamed) {
+ // Set named curve (one of the SECG curves embedded applet-side)
commands.add(new Command.Set(cardManager, keyPair, ECTesterApplet.EXPORT_NONE, EC_Consts.getCurve(keyLength, keyClass), domainParams, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, null));
- }
- if (optCurve != null) {
+ } else if (optCurve != null) {
+ // Set curve loaded from a file
byte[] external = ParamReader.flatten(domainParams, ParamReader.readFile(optCurve));
if (external == null) {
throw new IOException("Couldn't read the curve file correctly.");
}
commands.add(new Command.Set(cardManager, keyPair, ECTesterApplet.EXPORT_NONE, EC_Consts.CURVE_external, domainParams, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, external));
+ } else {
+ // Set default curve
+ commands.add(new Command.Clear(cardManager, keyPair));
}
return commands;
@@ -566,6 +598,23 @@ public class ECTester {
return new Command.Set(cardManager, keyPair, ECTesterApplet.EXPORT_NONE, EC_Consts.CURVE_external, params, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, data);
}
+ /**
+ * @param keyLength
+ * @param keyClass
+ * @return
+ * @throws IOException
+ */
+ private List<Command> testCurve(short keyLength, byte keyClass) throws IOException {
+ List<Command> commands = new LinkedList<>();
+ commands.addAll(prepareKeyPair(ECTesterApplet.KEYPAIR_BOTH, keyLength, keyClass));
+ commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, keyLength, keyClass));
+ commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH, ECTesterApplet.EXPORT_NONE));
+ commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_NONE, (byte) 0));
+ commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_NONE, (byte) 1));
+ commands.add(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_NONE, null));
+ return commands;
+ }
+
public static void main(String[] args) {
ECTester app = new ECTester();
app.run(args);
diff --git a/src/cz/crcs/ectester/reader/Response.java b/src/cz/crcs/ectester/reader/Response.java
index 8f9ab9b..05cd92a 100644
--- a/src/cz/crcs/ectester/reader/Response.java
+++ b/src/cz/crcs/ectester/reader/Response.java
@@ -6,17 +6,19 @@ import javacard.framework.ISO7816;
import javacard.security.KeyPair;
import javax.smartcardio.ResponseAPDU;
+import java.util.List;
/**
* @author Jan Jancar johny@neuromancer.sk
*/
public abstract class Response {
- protected ResponseAPDU resp;
- protected long time;
- protected short sw1 = 0;
- protected short sw2 = 0;
- protected byte[][] params;
- protected boolean success = true;
+ private ResponseAPDU resp;
+ private long time;
+ private short sw1 = 0;
+ private short sw2 = 0;
+ private int numSW = 0;
+ private byte[][] params;
+ private boolean success = true;
protected Response(ResponseAPDU response, long time) {
this.resp = response;
@@ -24,6 +26,8 @@ public abstract class Response {
}
protected void parse(int numSW, int numParams) {
+ this.numSW = numSW;
+
byte[] data = resp.getData();
int offset = 0;
@@ -31,14 +35,16 @@ public abstract class Response {
if (--numSW >= 0 && getLength() >= 2) {
sw1 = Util.getShort(data, offset);
offset += 2;
- if (sw1 != ISO7816.SW_NO_ERROR)
+ if (sw1 != ISO7816.SW_NO_ERROR) {
success = false;
+ }
}
if (--numSW >= 0 && getLength() >= 4) {
sw2 = Util.getShort(data, offset);
offset += 2;
- if (sw2 != ISO7816.SW_NO_ERROR)
+ if (sw2 != ISO7816.SW_NO_ERROR) {
success = false;
+ }
}
//try to parse numParams..
@@ -60,18 +66,6 @@ public abstract class Response {
}
}
- protected boolean hasParam(int index) {
- return params.length >= index + 1 && params[index] != null;
- }
-
- protected int getParamLength(int index) {
- return params[index].length;
- }
-
- protected byte[] getParam(int index) {
- return params[index];
- }
-
public ResponseAPDU getAPDU() {
return resp;
}
@@ -92,6 +86,22 @@ public abstract class Response {
return sw2;
}
+ public int getNumSW() {
+ return numSW;
+ }
+
+ protected boolean hasParam(int index) {
+ return params.length >= index + 1 && params[index] != null;
+ }
+
+ protected int getParamLength(int index) {
+ return params[index].length;
+ }
+
+ protected byte[] getParam(int index) {
+ return params[index];
+ }
+
public int getLength() {
return resp.getNr();
}
@@ -104,6 +114,21 @@ public abstract class Response {
public abstract String toString();
+ public static String toString(List<Response> responses) {
+ StringBuilder out = new StringBuilder();
+ for (Response r : responses) {
+ String message = r.toString();
+ String suffix;
+ if (r.getNumSW() == 1) {
+ suffix = String.format("%s", Util.getPrintError(r.getSW1()));
+ } else {
+ suffix = String.format("%s %s", Util.getPrintError(r.getSW1()), Util.getPrintError(r.getSW2()));
+ }
+ out.append(String.format("%-55s: %s\n", message, suffix));
+ }
+ return out.toString();
+ }
+
/**
*
*/
@@ -133,8 +158,32 @@ public abstract class Response {
} else {
key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
}
- //TODO general response.toString alignment + 2 SWs
- return String.format("Allocated %s %db %s: %#x", key, keyLength, field, getSW1());
+ return String.format("Allocated %s %db %s", key, keyLength, field);
+ }
+ }
+
+ public static class Clear extends Response {
+ private byte keyPair;
+
+ public Clear(ResponseAPDU response, long time, byte keyPair) {
+ super(response, time);
+ this.keyPair = keyPair;
+
+ int pairs = 0;
+ if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++;
+ if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++;
+ parse(pairs, 0);
+ }
+
+ @Override
+ public String toString() {
+ String key;
+ if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
+ key = "both keypairs";
+ } else {
+ key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
+ }
+ return String.format("Cleared %s", key);
}
}
@@ -145,15 +194,15 @@ public abstract class Response {
private byte keyPair;
private byte export;
private byte curve;
- private short params;
+ private short parameters;
private short corrupted;
- protected Set(ResponseAPDU response, long time, byte keyPair, byte export, byte curve, short params, short corrupted) {
+ protected Set(ResponseAPDU response, long time, byte keyPair, byte export, byte curve, short parameters, short corrupted) {
super(response, time);
this.keyPair = keyPair;
this.export = export;
this.curve = curve;
- this.params = params;
+ this.parameters = parameters;
this.corrupted = corrupted;
int pairs = 0;
@@ -168,14 +217,14 @@ public abstract class Response {
int paramCount = 0;
short mask = EC_Consts.PARAMETER_FP;
while (mask <= EC_Consts.PARAMETER_K) {
- if ((mask & params) != 0) {
+ if ((mask & parameters) != 0) {
paramCount++;
}
mask = (short) (mask << 1);
}
int other = 0;
- if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0 && (params & EC_Consts.PARAMETER_W) != 0) other++;
- if ((export & ECTesterApplet.EXPORT_PRIVATE) != 0 && (params & EC_Consts.PARAMETER_S) != 0) other++;
+ if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0 && (parameters & EC_Consts.PARAMETER_W) != 0) other++;
+ if ((export & ECTesterApplet.EXPORT_PRIVATE) != 0 && (parameters & EC_Consts.PARAMETER_S) != 0) other++;
parse(pairs, exported * keys * paramCount + exported * other);
}
@@ -189,7 +238,7 @@ public abstract class Response {
if (key == keyPair && param == mask) {
return index;
}
- if ((params & mask) != 0 && (key & export) != 0) {
+ if ((parameters & mask) != 0 && (key & export) != 0) {
if (mask == EC_Consts.PARAMETER_W) {
if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0)
index++;
@@ -209,7 +258,11 @@ public abstract class Response {
}
public boolean hasParameter(byte keyPair, short param) {
- return !((export & keyPair) == 0 || (params & param) == 0) && getIndex(keyPair, param) != -1;
+ if ((export & keyPair) == 0 || (parameters & param) == 0) {
+ return false;
+ }
+ int index = getIndex(keyPair, param);
+ return index != -1 && hasParam(index);
}
public byte[] getParameter(byte keyPair, short param) {
@@ -236,8 +289,7 @@ public abstract class Response {
} else {
key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
}
- //TODO general response.toString alignment + 2 SWs
- return String.format("Set %s curve parameters on %s: %#x", name, key, getSW1());
+ return String.format("Set %s curve parameters on %s", name, key);
}
}
@@ -301,13 +353,15 @@ public abstract class Response {
public boolean hasPublic(byte keyPair) {
if ((export & ECTesterApplet.EXPORT_PUBLIC) == 0 || (export & keyPair) == 0)
return false;
- return getIndex((byte) (keyPair | ECTesterApplet.EXPORT_PUBLIC)) != -1;
+ int index = getIndex((byte) (keyPair | ECTesterApplet.EXPORT_PUBLIC));
+ return index != -1 && hasParam(index);
}
public boolean hasPrivate(byte keyPair) {
if ((export & ECTesterApplet.EXPORT_PRIVATE) == 0 || (export & keyPair) == 0)
return false;
- return getIndex((byte) (keyPair | ECTesterApplet.EXPORT_PRIVATE)) != -1;
+ int index = getIndex((byte) (keyPair | ECTesterApplet.EXPORT_PRIVATE));
+ return index != -1 && hasParam(index);
}
public byte[] getPublic(byte keyPair) {
@@ -330,8 +384,7 @@ public abstract class Response {
} else {
key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
}
- //TODO general response.toString alignment + 2 SWs
- return String.format("Generated %s: %#x", key, getSW1());
+ return String.format("Generated %s", key);
}
}
@@ -368,8 +421,7 @@ public abstract class Response {
String pub = pubkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
String validity = invalid != 0 ? "invalid" : "valid";
- //TODO general response.toString alignment + 2SWs
- return String.format("ECDH of %s pubkey and %s privkey(%s point): %#x", pub, priv, validity, getSW1());
+ return String.format("ECDH of %s pubkey and %s privkey(%s point)", pub, priv, validity);
}
}
@@ -402,8 +454,7 @@ public abstract class Response {
public String toString() {
String key = keyPair == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
String data = raw == null ? "random" : "provided";
- //TODO general response.toString alignment + 2 SWs
- return String.format("ECDSA with %s keypair(%s data): %#x", key, data, getSW1());
+ return String.format("ECDSA with %s keypair(%s data)", key, data);
}
}